Fix to use quotemeta to prevent shell injection in usermin module

Ref.: a8417099-d3bc-468a (VULN-004)
This commit is contained in:
Ilia Ross
2026-02-10 13:21:56 +02:00
parent c47b63bfcf
commit c87712ef4e
6 changed files with 36 additions and 27 deletions

View File

@@ -46,7 +46,8 @@ if ($in{'ipv6'}) {
@newports = &unique(grep { &indexof($_, @oldports) < 0 } @ports);
if (&has_command("lsof")) {
foreach my $p (@newports) {
$out = &backquote_command("lsof -t -i tcp:$p 2>/dev/null");
my $qp = quotemeta($p);
$out = &backquote_command("lsof -t -i tcp:$qp 2>/dev/null");
if ($out =~ /\d+/) {
&error(&text('bind_elsof', $p));
}
@@ -111,7 +112,7 @@ foreach my $mod ("firewall", "firewalld") {
$ENV{'WEBMIN_CONFIG'} = $config_directory;
&system_logged(
&module_root_directory($mod)."/open-ports.pl ".
join(" ", map { $_.":".($_+10) } @newports).
join(" ", map { quotemeta($_).":".quotemeta($_+10) } @newports).
" >/dev/null 2>&1");
&reset_environment();
}
@@ -121,4 +122,3 @@ foreach my $mod ("firewall", "firewalld") {
&webmin_log("bind", undef, undef, \%in);
&redirect("");

View File

@@ -24,7 +24,9 @@ do {
# Copy the config directory
mkdir("$config{'usermin_dir'}/$dst", 0755);
$out = &backquote_logged("( (cd $config{'usermin_dir'}/$src ; tar cf - .) | (cd $config{'usermin_dir'}/$dst ; tar xpf -) ) 2>&1");
$qsrc = quotemeta($src);
$qdst = quotemeta($dst);
$out = &backquote_logged("( (cd $config{'usermin_dir'}/$qsrc ; tar cf - .) | (cd $config{'usermin_dir'}/$qdst ; tar xpf -) ) 2>&1");
if ($?) {
&error(&text('clone_ecopy', $out));
}
@@ -51,4 +53,3 @@ if ($in{'cat'} ne '*') {
'dst' => $dst,
'dstdesc' => $in{'desc'} });
&redirect("");

View File

@@ -19,7 +19,7 @@ local %miniserv;
chdir($miniserv{'root'});
$cmd = "tar chf -";
foreach $m (@mods) {
$cmd .= " $m";
$cmd .= " ".quotemeta($m);
}
$cmd .= " | gzip -c >".quotemeta($temp);
$out = &backquote_logged("($cmd) 2>&1 </dev/null");
@@ -47,4 +47,3 @@ else {
"", $text{'index_return'});
}

View File

@@ -32,7 +32,8 @@ $ctemp = &transname();
$ktemp = &transname();
$outtemp = &transname();
$size = $in{'size_def'} ? $default_key_size : $in{'size'};
&open_execute_command(CA, "$cmd req -newkey rsa:$size -x509 -nodes -out ".quotemeta($ctemp)." -keyout ".quotemeta($ktemp)." -days $in{'days'} >".quotemeta($outtemp)." 2>&1", 0);
$qdays = quotemeta($in{'days'});
&open_execute_command(CA, "$cmd req -newkey rsa:$size -x509 -nodes -out ".quotemeta($ctemp)." -keyout ".quotemeta($ktemp)." -days $qdays >".quotemeta($outtemp)." 2>&1", 0);
print CA ($in{'countryName'} || "."),"\n";
print CA ($in{'stateOrProvinceName'} || "."),"\n";
print CA ($in{'cityName'} || "."),"\n";
@@ -51,8 +52,9 @@ if (!-r $ctemp || !-r $ktemp || $?) {
&ui_print_footer("", $text{'index_return'});
exit;
}
$qnewfile = quotemeta($in{'newfile'});
&lock_file($in{'newfile'});
&execute_command("cat ".quotemeta($ctemp)." ".quotemeta($ktemp)." 2>&1 >'$in{'newfile'}'", undef, \$catout);
&execute_command("cat ".quotemeta($ctemp)." ".quotemeta($ktemp)." 2>&1 >$qnewfile", undef, \$catout);
&unlink_file($ctemp);
&unlink_file($ktemp);
if ($catout || $?) {
@@ -65,7 +67,7 @@ if ($catout || $?) {
&unlock_file($in{'newfile'});
print "<p>$text{'newkey_ok'}<br>\n";
$key = `cat '$in{'newfile'}'`;
$key = `cat $qnewfile`;
print "<pre>$key</pre>";
&ui_print_footer("", $text{'index_return'});
@@ -80,4 +82,3 @@ if ($in{'usenew'}) {
&restart_usermin_miniserv();
&webmin_log("newkey", undef, undef, \%in);
}

View File

@@ -124,6 +124,7 @@ elsif ($in{'source'} == 5) {
$error && &inst_error($error);
}
$qfile = quotemeta($file);
$qindir = quotemeta($indir) if (defined($indir));
# gunzip the file if needed
open(FILE, "<$file");
@@ -134,7 +135,8 @@ if ($two eq "\037\213") {
&inst_error($text{'upgrade_egunzip'});
}
$newfile = &transname();
$out = `gunzip -c $file 2>&1 >$newfile`;
$qnewfile = quotemeta($newfile);
$out = `gunzip -c $qfile 2>&1 >$qnewfile`;
if ($?) {
unlink($newfile);
&inst_error(&text('upgrade_egzip', "<tt>$out</tt>"));
@@ -199,7 +201,7 @@ elsif ($in{'mode'} eq 'deb') {
}
else {
# Check if it is a usermin tarfile
open(TAR, "tar tf $file 2>&1 |");
open(TAR, "tar tf $qfile 2>&1 |");
while(<TAR>) {
if (/^usermin-([0-9\.]+)\//) {
$version = $1;
@@ -235,7 +237,8 @@ else {
# Installing .. extract it in /usr/local and run setup.sh
local $root = "/usr/local";
mkdir($root, 0755);
$out = `cd $root ; tar xf $file 2>&1 >/dev/null`;
$qroot = quotemeta($root);
$out = `cd $qroot ; tar xf $qfile 2>&1 >/dev/null`;
if ($?) {
&inst_error(&text('upgrade_euntar', "<tt>$out</tt>"));
}
@@ -268,7 +271,8 @@ else {
}
# Extract it next to the current directory and run setup.sh
$out = `cd $extract ; tar xf $file 2>&1 >/dev/null`;
$qextract = quotemeta($extract);
$out = `cd $qextract ; tar xf $qfile 2>&1 >/dev/null`;
if ($?) {
&inst_error(&text('upgrade_euntar', "<tt>$out</tt>"));
}
@@ -276,7 +280,7 @@ else {
$ENV{'config_dir'} = $config{'usermin_dir'};
$ENV{'webmin_upgrade'} = 1;
$ENV{'autothird'} = 1;
$setup = $indir ? "./setup.sh '$indir'" : "./setup.sh";
$setup = $indir ? "./setup.sh $qindir" : "./setup.sh";
if ($in{'delete'}) {
$ENV{'deletedold'} = 1;
$cmd = "(cd $extract/usermin-$version && $setup && rm -rf \"$miniserv{'root'}\")";
@@ -340,4 +344,3 @@ unlink($file) if ($need_unlink);
&error($_[0]);
exit;
}

View File

@@ -420,6 +420,7 @@ if (&is_readonly_mode()) {
open(MFILE, "<".$file);
read(MFILE, $two, 2);
close(MFILE);
local $qfile = quotemeta($file);
if ($two eq "\037\235") {
if (!&has_command("uncompress")) {
unlink($file) if ($need_unlink);
@@ -427,13 +428,15 @@ if ($two eq "\037\235") {
}
local $temp = $file =~ /\/([^\/]+)\.Z/i ? &transname("$1")
: &transname();
local $out = `uncompress -c "$file" 2>&1 >$temp`;
local $qtemp = quotemeta($temp);
local $out = `uncompress -c $qfile 2>&1 >$qtemp`;
unlink($file) if ($need_unlink);
if ($?) {
unlink($temp);
return &text('install_ecomp2', $out);
}
$file = $temp;
$qfile = quotemeta($file);
$need_unlink = 1;
}
elsif ($two eq "\037\213") {
@@ -443,13 +446,15 @@ elsif ($two eq "\037\213") {
}
local $temp = $file =~ /\/([^\/]+)\.gz/i ? &transname("$1")
: &transname();
local $out = `gunzip -c "$file" 2>&1 >$temp`;
local $qtemp = quotemeta($temp);
local $out = `gunzip -c $qfile 2>&1 >$qtemp`;
unlink($file) if ($need_unlink);
if ($?) {
unlink($temp);
return &text('install_egzip2', $out);
}
$file = $temp;
$qfile = quotemeta($file);
$need_unlink = 1;
}
@@ -462,7 +467,7 @@ open(TYPE, "<../install-type");
chop($type = <TYPE>);
close(TYPE);
if ($type eq 'rpm' && $file =~ /\.rpm$/i &&
($out = `rpm -qp $file 2>/dev/null`)) {
($out = `rpm -qp $qfile 2>/dev/null`)) {
# Looks like an RPM of some kind, hopefully an RPM usermin module
# or theme
local ($out, %minfo, %tinfo);
@@ -471,7 +476,7 @@ if ($type eq 'rpm' && $file =~ /\.rpm$/i &&
return $text{'install_erpm'};
}
$redirect_to = $name = $2;
$out = &backquote_logged("rpm -Uv \"$file\" 2>&1");
$out = &backquote_logged("rpm -Uv $qfile 2>&1");
if ($?) {
unlink($file) if ($need_unlink);
return &text('install_eirpm', "<tt>$out</tt>");
@@ -515,7 +520,7 @@ else {
# Check if this is a valid module (a tar file of multiple module or
# theme directories)
local (%mods, %hasfile);
local $tar = `tar tf "$file" 2>&1`;
local $tar = `tar tf $qfile 2>&1`;
if ($?) {
unlink($file) if ($need_unlink);
return &text('install_etar', $tar);
@@ -548,7 +553,7 @@ else {
next if (!$hasfile{$m,"module.info"});
push(@realmods, $m);
local %minfo;
system("cd $tmpdir ; tar xf \"$file\" $m/module.info ./$m/module.info >/dev/null 2>&1");
system("cd $tmpdir ; tar xf $qfile $m/module.info ./$m/module.info >/dev/null 2>&1");
if (!&read_file("$tmpdir/$m/module.info", \%minfo)) {
$err = &text('install_einfo', "<tt>$m</tt>");
}
@@ -600,7 +605,7 @@ else {
}
# Extract all the modules and update perl path and ownership
local $out = `cd $miniserv{'root'} ; tar xf "$file" 2>&1 >/dev/null`;
local $out = `cd $miniserv{'root'} ; tar xf $qfile 2>&1 >/dev/null`;
if ($?) {
unlink($file) if ($need_unlink);
return &text('install_eextract', $out);
@@ -800,6 +805,7 @@ sub delete_usermin_module
{
local $m = $_[0];
return undef if (!$m);
local $qm = quotemeta($m);
local %minfo = &get_usermin_module_info($m);
%minfo = &get_usermin_theme_info($m) if (!%minfo);
return undef if (!%minfo);
@@ -832,7 +838,7 @@ else {
@lst = stat("$miniserv{'root'}/$l");
if (-l "$miniserv{'root'}/$l" && $lst[1] == $mst[1]) {
&unlink_logged("$miniserv{'root'}/$l");
&system_logged("rm -rf $config{'usermin_dir'}/$l");
&system_logged("rm -rf ".quotemeta("$config{'usermin_dir'}/$l"));
push(@clones, $l);
}
}
@@ -848,7 +854,7 @@ else {
"<tt>$mdir</tt>", $size);
if ($type eq 'rpm') {
# This module was installed from an RPM .. rpm -e it
&system_logged("rpm -e ubm-$m");
&system_logged("rpm -e ubm-$qm");
}
else {
# Module was installed from a .wbm file .. just rm it
@@ -1071,4 +1077,3 @@ chmod(0755, $wrapper);
}
1;