Last active
May 13, 2017 23:18
-
-
Save vient/0d5e0f0a6cc9b2b0b7bcb87be2b599b9 to your computer and use it in GitHub Desktop.
Solution for Enlightenment task from DEF CON CTF Qualifier 2017
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The idea is that in each task the key was checked character by character in the same way. | |
So we can make a pattern from assembly code and then extract all information with simple re.search() | |
The first task, Magic, was solved with angr though mainly because I didn't think about regexes in the first way. | |
There are two details that differ Enlightment from pevoius tasks (subtasks here): | |
1. All binaries were compiled with another options so all my regexes broke as well as angr solution. | |
Regexes are easily adjustable, but you can't use these solutions to solve previous tasks anymore. | |
2. Only in this task keys are sometime reversed. I decided not to find in the binary whether it reverses key or not, | |
instead I just tried to feed the key to the binary. If return code is not 0 then we need to reverse the key. | |
Additional notes | |
Occult solution is overcomplicated with handlers but they help with debugging and make cleaner code. | |
Witchcraft code is obscure since I mixed all regexes for different operations in one. | |
Check for 'swift' in subprocess output is there because Swift do not work on my machine and I decided not to spend time on this. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from pwn import * | |
import re | |
import angr | |
import struct | |
import base64 | |
import subprocess | |
def MagicSolution(filename): | |
elf = angr.Project('./' + filename) | |
state = elf.factory.blank_state(addr=0x40066D) | |
i = state.se.BVS('i', 80*8) | |
state.memory.store(0x1000, i) | |
state.regs.rbx = 0x1000 | |
pg = elf.factory.path_group(state) | |
pg.explore(find=0x400675) | |
state = pg.found[0].state | |
key = state.se.any_str(i).rstrip("\x00") | |
return key | |
def SorcerySolution(filename): | |
with open(filename, 'rb') as f: | |
q = f.read() | |
mask1 = r'\x8A\x0F\x80\xF9([\x10-\x7f])' | |
mask2 = r'\x8A(\x47.\x3C|\x4F.\x80\xF9)([\x10-\x7f])' | |
key = '' | |
found = re.search(mask1, q) | |
key += found.group(1) | |
prev = 0 | |
while True: | |
prev += found.start() + 1 | |
found = re.search(mask2, q[prev + 1:], re.DOTALL) | |
if not found: | |
break | |
key += found.group(2) | |
return key | |
def AlchemySolution(filename): | |
with open(filename, 'rb') as f: | |
q = f.read() | |
mask2 = r'\x0F\xB6.{1,2}\x48\x83[\xF8\xF9]([\x10-\x7f])' | |
key = '' | |
prev = 0 | |
while True: | |
found = re.search(mask2, q[prev + 1:], re.DOTALL) | |
if not found: | |
break | |
prev += found.start() + 1 | |
key += found.group(1) | |
return key | |
def WitchcraftSolution(filename): | |
with open(filename, 'rb') as f: | |
q = f.read() | |
mask = r'\x48(\x81([\xC7\xEF\xFF])(.{4})|\x83([\xC7\xEF\xFF])(.)|\x85\xFF)[\x70-\x80\x0F]' | |
key = '' | |
prev = 0 | |
acc = 0 | |
while True: | |
found = re.search(mask, q[prev + 1:], re.DOTALL) | |
if not found: | |
break | |
prev += found.start() + 1 | |
op = found.group(2) or found.group(4) | |
if op: | |
num = ord(found.group(5)) if found.group(5) else struct.unpack('<I', found.group(3))[0] | |
else: | |
op = '\xFF' | |
num = 0 | |
if op == '\xC7': | |
acc += num | |
elif op == '\xEF': | |
acc -= num | |
else: | |
if acc: | |
key += chr((num - acc) & 0xFF) | |
acc = 0 | |
return key | |
def OccultSolution(filename): | |
with open(filename, 'rb') as f: | |
q = f.read() | |
mask_arith = r'\x48\x8D\x78\x08\x48\x8D[\x70-\x78](.)\x40' | |
mask_res = r'\x48\x89\x44\x24\x38\x48(\x81\x78\x08(.{4})|\x83\x78\x08(.))' | |
mask_index = r'\x48[\x8B\x0B].{4}\0\xB9(.\0\0\0)' | |
def ArithHandler(found): | |
num = struct.unpack('<b', found.group(1))[0] | |
return num | |
def ResHandler(found): | |
if found.group(2): | |
return struct.unpack('<i', found.group(2))[0] | |
else: | |
return ord(found.group(3)) | |
def IndexHandler(found): | |
return struct.unpack('<i', found.group(1))[0] | |
key = {} | |
prev = 0 | |
it_arith = re.finditer(mask_arith, q, re.DOTALL) | |
it_res = re.finditer(mask_res, q, re.DOTALL) | |
it_index = re.finditer(mask_index, q, re.DOTALL) | |
found_arith = next(it_arith) | |
try: | |
while True: | |
acc = 0 | |
found_res = next(it_res) | |
while found_arith and found_arith.start() < found_res.start(): | |
acc += ArithHandler(found_arith) | |
try: | |
found_arith = next(it_arith) | |
except StopIteration: | |
break | |
res = (ResHandler(found_res) - acc) & 0xFF | |
found_index = next(it_index) | |
key[IndexHandler(found_index)] = chr(res // 2) | |
except StopIteration: | |
pass | |
key = ''.join(x[1] for x in sorted((k, key[k]) for k in key)) | |
return key | |
def main(): | |
p = remote('cm2k-enlightenment_4ee3a7c97ce496cde9bdf905843cf0f1.quals.shallweplayaga.me', 12999) | |
_ = p.readline() | |
try: | |
while True: | |
x = p.readline() | |
print x | |
x = x.strip() | |
keys = [] | |
try: | |
with open(x, 'rb') as f: | |
q = f.read() | |
if len(q) < 1024*15: | |
keys.append(MagicSolution(x)) | |
except Exception: | |
pass | |
try: | |
keys.append(SorcerySolution(x)) | |
except Exception: | |
pass | |
try: | |
keys.append(AlchemySolution(x)) | |
except Exception: | |
raise | |
try: | |
keys.append(WitchcraftSolution(x)) | |
except Exception: | |
pass | |
try: | |
keys.append(OccultSolution(x)) | |
except Exception: | |
pass | |
key = sorted([(len(y), y) for y in keys if y is not None])[-1][1] | |
proc = subprocess.Popen(['./' + x], shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
out, err = proc.communicate(key + '\n') | |
if proc.returncode != 0 and 'swift' not in err: | |
key = key[::-1] | |
print key | |
p.sendline(base64.b64encode(key)) | |
except Exception: | |
raise | |
p.interactive() | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment