D^3CTF Pwn d3op 复现报告
孩子才刚开始看内核啊……
ARM完全不会啊……
太菜了太菜了……
D^3CTF Pwn d3op 复现报告
附件下载地址:Here
init
首先解包文件系统。
|
|
然后去/etc/os-release
看一下发行版信息。
|
|
要么魔改要么埋洞好像这两种说法没什么区别
先搜一波openwrt 22.03.3 download
找到这里然后到下载页下载squashfs版本的镜像备用。
find diff
diff
可以快速查找所有文件的不同,bindiff
可以用来快速寻找二进制文件的不同。
但写完之后才发觉bindiff好像没用到
BinDiff Install: Official Page
选择对应版本即可。其余过程不再赘述。Windows端安装完成后IDA会自动识别该扩展。
我们来到WSL-debian这边。先解压好镜像备用,然后diff
之
|
|
等一会,去除掉一些显然没啥用的信息,关键信息如下。
|
|
显然多了个base64,那拖一手IDA。
reverse
啥符号都没有,_start也不知道他在干嘛,先看一眼strings碰碰运气:
交叉引用encode/decode,就能找到这里:
显然41FE40是strcmp,4061AC是decode,405EC0是decode。
直接逆一手decode就可以发现他没查outputlen就直接decode了,decode的buf还在栈上,直接考虑栈溢出/ROP。
效果并不好,可能是我的手法问题或者是工具本身的限制。
用过IDA的rizzo插件,用过Ghidra的Version Tracking,但效果都不好,出来的函数没几个。
做签名的musl-libc有自己编译的,也有去官网工具链下载的,但效果都差不多。
find gadget
参照这篇博客可以了解到aarch64架构的系统调用相关内容。
重点放在调用约定这里。
arch | syscall NR | return | arg0 | arg1 | arg2 | arg3 | arg4 | arg5 |
---|---|---|---|---|---|---|---|---|
arm | r7 | r0 | r0 | r1 | r2 | r3 | r4 | r5 |
aarch64 | x8 | x0 | x0 | x1 | x2 | x3 | x4 | x5 |
x86 | eax | eax | ebx | ecx | edx | esi | edi | ebp |
x86_64 | rax | rax | rdi | rsi | rdx | r10 | r8 | r9 |
然后对一些gadget做一下 x86 -> arm64 的转换
-
mov rax, SYSCALL_NR;syscall
->mov x8, SYSCALL_NR; svc 0
x8存放系统调用号,
svc 0
目前来看相当于amd64的syscall
-
leave;ret
->ldp x29,x30,[sp]{,#offset}
x29是栈指针,x30指向下一条指令
相当于
pop x29; pop x30; {add sp,#offset;} ret x30;
arm64没有pop
,取而代之的是ldp
一族。
所以找gadget可以围着ldp x29,x30,[sp]{,#offset};ret
这么找:
|
|
从decode返回时由于x29和x30已经被上一函数设定,所以只能在下一函数完全控制执行流程。好在返回后改了个x0就leave;ret
了,没啥影响。
Nu1L的师傅使用的是ret2csu这段通用gadget。
反正可以栈溢出且溢出长度基本无限,乱搞喽。
construct payload
ROP已经完成了,那么我们来看看payload的前导内容。
往上追,看谁call了这个分流decode/encode操作的函数,可以看到还需要一个input字段。
参照官方的ubus文档可以大概了解到怎么构造请求包。结构贴在下面了。
|
|
而且文档里有这么一句话:
|
|
所以orw的shellcode,write的起始点必须是一个json结构的起始点。至于你放在哪里是无所谓的。实测如果没有json结构的话,返回值为2且没有任何其他内容。
再看一眼这里,
params的格式也就出来了。
或者你curl一发:其实你如果能一眼看出来那就没必要了
|
|
他会给你吐出来一个json:
|
|
怎么构造payload也知道了:
ubus_rpc_session
32位0不用动,反正你从头到尾都是unauthenticated。ubus_object
填base64
ubus_method
填decode
arguments
就是"input":"$payload"
官方WP payload构造脚本
|
|
ret2csu payload构造脚本
|
|
debug
诸如qemu
、gdb-multiarch
等基础环境安装不再赘述。
在start.sh
中添加参数-g
让qemu
暴露调试接口。
然后启动gdb-multiarch
,然后target remote :1234
,然后照常下断点即可。
可以看到循环结束,程序走到decode
函数的ret
时,栈中的内容已经变成我们预留的ROP。
然后走到就是mprotect改rwx然后走orw的shellcode了。
attack
payload1
|
|
payload2
|
|