BUU
:ciscn_2019_s_3
思路
检查保护,开了NX
保护
源码:
signed __int64 vuln() |
程序中有两个系统调用,read
可栈溢出,程序中没有后门函数。但是我们看到了下面这个,3bh
是64
位程序execve
的系统调用号,程序中有系统调用则肯定有syscall
即我们可以利用gadgets
布置execve
的参数,然后syscall
获得shell
。
系统调用execve
,我们必须要知道/bin/sh
的地址。本题中,buf
的长度为16
个字节,而write
打印0x30
个字节,又因为buf
在栈上,所以buf
下面的一些栈中的数据也会被打印出来。
我们填满buf
的16
个字节,然后发送vuln
函数的第一个指令的地址,执行流会重新执行一遍vuln
函数。发送payload = b'/bin/sh\x00'+b'a'*8+p64(vuln_addr)
,然后看栈中的内容,其中0x7ffd3e0cdce8
是栈地址同时也能被泄漏。
payload
如下:
vuln_addr = 0x4004ed |
接下来就是传参,不过我们没有直接找到rdx
相关的gadget
地址,好吧,其实这就是道关于ret2csu
类型的题。


下面是csu
片段,我们就是要利用这两个片段,对寄存器进行各种操作,最后使rdx
中的值为0
(execve
的第3
个参数)。
csu
②都是一些pop
,重要的是怎么绕过csu
①,首先我们要弄懂csu
①中的汇编代码是什么意思。其中,call
指令是调用函数,这里的[]
是间接寻址,call [r12+rbx*8]
这个指令的意思是调用一个函数,这个函数在哪,这个函数的地址在r12+rbx*8
这个地址里装着。也就是说,如果r12
和rbx
的值分别为0x123456
和0
,0x123456
又指向0x400123
这个地址,那么我们要调用的函数的地址不是0x123456
而是0x400123
。
cmp
指令用于比较两个操作数的值,cmp rbx,rbp
指令的意思是比较rbx
和rbp
这两个寄存器的值。如果rbx
和rbp
的值不相等,那么jnz
会跳转到相应的地址执行,反之执行流继续执行下一条指令。
payload
如下:
csu1_addr = 0x400580 |
我们在ida
中看到term_proc
是一个空函数,其地址为0x4005b4
,当然这个肯定不是我们想要的,我们想要的是哪个地址指向0x4005b4
。
在gdb
中,我们利用search -p 0x4005b4
这个命令看到0x600e50
这个地址中装的是0x4005b4
。
一开始按照上面的payload
发送一直打不通,调试的时候发现,调用完这个空函数后会ret
到返回地址0x40058d
也就是csu
①中的add rbx, 1
指令,后面会影响栈的有add rsp,8
和6
个pop
指令,所以我们还需要再发送7*8
个垃圾数据。
修改后payload
如下:
csu1_addr = 0x400580 |
exp
from tools import * |
拿到flag
更换libc
本题中本地和远程的libc
不一样,所以偏移量也不同,本题中本地的是0x148
远程为0x118
。我们可以利用pathelf
和glibc-all-in-one
更换本地依赖的libc
。
首先用strings ./libc-2.23.so | grep "GNU"
命令查看远程libc
的GLIBC
版本
然后在glibc-all-in-one
中找到对应的版本号,64
位程序对应amd64
,32
位程序对应i386
执行./download 2.23-0ubuntu11.3_amd64
,便会在glibc-all-all-in-one
目录下的libs
目录中生成一个新目录
最后便可利用patchelf
中--set-interpreter
和--add-needed
选项分别设置链接器和依赖的路径即可。