西湖论剑-linkone
前言
这是winmt师傅给我的第一个挑战,一道没有任何保护,甚至没有ALSR的iot漏洞挖掘题目.即使漏洞很明显,但是我一共用了两天.基本上碰上了第一次做iot的所有坑,最后还是难逃被🍐的命运…不过也学到了很多很多东西.
正式开始
1.前置准备
题目的附件为:
- debian虚拟机镜像
- 内核文件
- 镜像的用户名和密码
- 启动脚本
其中启动脚本
1 | /bin/bash |
大概的解释就是:
调试
为了方便调试.我们添加一个端口映射hostfwd=tcp::9999-:9999
,这样可以将qemu的9999端口转发到宿主机的9999端口上,这样就可以在宿主机上通过9999端口进行gdb调试
提取文件
1 | /bin/bash |
这样配置出来的qemu是可以和主机间使用通信,方便我们使用scp命令将文件复制到主机中
scp可以将文件从qemu中提取到宿主机,或将宿主机中的文件挂入qemu中:
1 | scp path_to_src path_to_dest |
其中qemu的路径为:root@ip(192.168.52.130):path_to_target
path_to_target为qemu中目标文件的绝对路径
很烦人,我一定要找个能同时传输文件和调试的qemu启动模式
gdbserver
提前将gdbserver传入qemu中,调试必要的组件
1 | +----------------+ +-------------------+ |
具体使用方法为:
- 启动二进制文件
- 发送exp,使得二进制文件被卡在某个地方
- 在qemu中使用
ps -ef
查看二进制文件的pid - 在qemu中启动gdbserver=>
./gdbserver :9999 --attach pid
- 在宿主机中使用gdb-multiarch加载elf=>
gdb-multiarch ./elf
- 在gdb-multiarch中连接远程9999端口=>
target remote : 9999
开始漏洞挖掘
1.文件寻找
随便输入个账号密码,在brup里抓包发现了
发现会运行一个login.cgi文件,这多半就是目标漏洞文件
于是在qemu中寻找
我们使用scp将这个文件提取到宿主机中,发现是个elf文件
其实我们可以顺便把libc提取出来
2.逆向与脚本编写
1.web相关函数学习
- getenv(“REQUEST_METHOD”)
从数据包中获取亲求格式 - getenv(“QUERY_STRING”)
从数据包中获取查询字符串 - getenv(“CONTENT_LENGTH”)
从数据包中HTTP请求体的长度(以字节为单位) - web_get(“page”, v3, 0)
从数据包中获取请求的 URL 路径或页面名称
2.逆向请求处理
从page获取类型后会调用不同的函数,
其中Goto_chidx中
sprintf会将wlanUrl格式化放入v9,但是没有检查wlanUrl的长度,会导致栈溢出
由于ALSR=0,所以栈,libc地址都是可以直接用
3.编写EXP
首先观察缓冲区与返回地址,缓冲区位于sp+0x20的地方,返回地址位于sp+0xac的地方,所以需要填充的字符长度为{0xac-0x20},此时我们前往libwebutil.so中寻找可以执行system的片段
在do_system中,会将第一个参数(a1)复制到bss上,然后拼接后作为system的参数.
此时我们还有一个重要的步骤:修改$GP
MIPS 架构使用
$gp
来提高访问全局变量或静态变量的效率。它通常指向一个全局数据区的中间位置,这样访问某些偏移量范围内的全局变量就只需要一次lw
(或sw
)加偏移,不需要多步地址计算。
在这里,$GP
用于访问libc中的相关函数,所以必须要正确设置$GP
,才能调用到system,sprintf等函数
可以看到这里的vsprintf就要由$GP+offset
进行寻址的
恢复$GP
:首先来到do_system的开头
按照这里的$GP
恢复,$GP=libc_base+0x7ff0+_GLOBAL_OFFSET_TABLE_
,双击_GLOBAL_OFFSET_TABLE_
查看得到0x55560
我们还需要寻找用于恢复$GP
的gadget,首先查看libc对do_system的交叉引用
我们可以在这里布置$GP
,同时发现do_system的延时槽中为do_system装填了$a0
,由$s0
决定,刚刚好在login.cgi的ret时可以控制$s0
的值.此时我们可以画出来执行ROP
时的栈帧分布
据此我写出payload:
1 | base=0x77e1e000 |
关键点:cp /flag /etc_ro/lighttpd/www/FLAG
- /flag是我们的攻击目标
- 在web进行资源配置时,会将
/etc_ro/lighttpd/www
挂载到url
中,此时/etc_ro/lighttpd/www
的资源被映射到url
中 - 那么我们在WIFI登录界面的
url
后输入/FLAG.txt
就可以访问到/etc_ro/lighttpd/www/FLAG.txt
实现了对不可访问/flag
的泄露
4.调试
调试是iot类题目最重要的一环,其实以上payload是通过大量调试后调整才写出来的
难点:
在我们发送exp后的瞬间,httpd程序开始运行cgi文件,然后cgi文件瞬间运行结束,这导致我们无法将gdb挂入cgi中
如果不发送exp,就不会触发cgi文件
解决方案:
- 我们对cgi文件进行patch,在缓冲区溢出的附件将代码修改为
while 1(死循环)
,这样cgi文件就会被卡住 - 此时我们可以挂载gdb,通过set *$恢复
while 1
后就可以进行正常调试了 - patch这步要借助IDA PRO,通过patch生成一个全新的elf文件,再通过scp将这个文件传入qemu中
- 此时发送payload,web上运行的cgi文件就是被我们patch过的elf
patch
在Goto_idx中的溢出前随便寻找一条指令(我选择一个nop,nop在mips中的机器码为\x00\x00\x00\x00
)
选中这个地址,转到Hex View中选中nop指令
如图选择
while(1)在mips中的机器码为FF FF 00 10
可以多试几个位置,有的地方patch后会反编译失败
使用scp将这个cgi传入qemu后就可以开始调试了
此时挂载gdb可以看到cgi陷入死循环,我们通过set *0x404ce0=0恢复
然后就可以正常调试了
成功 :)