2017 DEFCON CTF - Crackme2000 writeups
by St1tchprob
category : Crackme 2000
Challenge
주어진 바이너리들의 KEY 값을 찾는 그런 문제였다.
총 6개의 문제가 출제 되었고, 각각 다른 루틴을 가지고 있다.
enlightenment 문제에서 나머지 다른 5문제의 루틴이 섞인 바이너리가 존재하기 때문에 enlightenment 문제만 푼다면 다른 5개 문제는 모두 풀 수 있다.
전체적으로 objdump, grep, 정규표현식, 약간의 리버싱만 있으면 풀 수 있는 문제였다.
Solution
import re
import sys
import os
import glob
import subprocess
import string
check_out = lambda cmd : subprocess.check_output(cmd, shell=True)
printable_check = lambda key : all([d in string.printable for d in key])
def traverse():
for filename in glob.glob('./enlightenment_dist/*'):
if len(filename) == 85:
key = real_solver(filename)
print key
def real_solver(filename):
print filename,
tmp = solver1(filename)
if tmp != None:
return tmp
tmp = solver2(filename)
if tmp != None:
return tmp
tmp = solver3(filename)
if tmp != None:
return tmp
tmp = solver4(filename)
if tmp != None:
return tmp
tmp = solver5(filename)
if tmp != None:
return tmp
tmp = solver6(filename)
if tmp != None:
return tmp
raise
# alchemy
def solver1(filename):
try:
cmd = 'objdump -S -Mintel {} | grep "cmp" | grep "rcx,0x[0-9]."'.format(filename)
dat = check_out(cmd)
key = (''.join(re.findall('0x([0-9a-f]{2})',dat))).decode('hex')
if printable_check(key):
return key
else:
raise
except:
return None
# magic
def solver2(filename):
try:
cmd = 'objdump -S -Mintel {} | grep "cmp" | grep "rdi,0x[0-9]."'.format(filename)
dat = check_out(cmd)
key = (''.join(re.findall('0x([0-9a-f]{2})',dat))).decode('hex')
if printable_check(key):
return key
else:
raise
except:
return None
# sorcery
def solver3(filename):
try:
cmd = 'objdump -S -Mintel {} | grep "cmp" | grep "cl,0x[2-7]."'.format(filename)
dat = check_out(cmd)
key = (''.join(re.findall('0x([0-9a-f]{2})',dat))).decode('hex')
if printable_check(key):
return key
else:
raise
except:
return None
# witchcraft
def solver4(filename):
try:
cmd = 'objdump -S -Mintel {} | grep jo -1 | grep "add \|sub \|cmp\|test" | grep "rdi"'
dat = check_out(cmd.format(filename))
key = ''
s = 0
for line in dat.split('\n')[:-1]:
try:
oper, arg = re.findall(r'test|cmp|sub |add |0x\w*', line)
except:
oper = 'test'
if oper == 'add ':
s += eval(arg)
elif oper == 'sub ':
s -= eval(arg)
elif oper == 'test':
key += chr(s*-1)
s = 0
elif oper == 'cmp':
if eval(arg) > 0xffffffff:
key += chr(((0x10000 - (eval(arg) & 0xffff))*-1) - s)
else:
key += chr(eval(arg) - s)
s = 0
if printable_check(key):
return key
else:
print repr(key)
raise
except:
return None
# occult
def solver5(filename):
try:
cmd = 'objdump -S -Mintel {} | grep "rax+0x8" -3 | grep "add rsi,0x\|sub rsi,0x\|cmp QWORD"'
dat = check_out(cmd.format(filename))
key = ''
s = 0
for line in dat.split('\n')[1:-1]:
oper, arg = re.findall(r'cmp|sub |add |,0x\w*', line)
if oper == 'add ':
s += eval(arg[1:])
elif oper == 'sub ':
s -= eval(arg[1:])
elif oper == 'cmp':
if eval(arg[1:]) > 0xffffffff:
key += chr( (((0x10000 - (eval(arg[1:]) & 0xffff))*-1) - s - 1)/2 )
else:
key += chr( (eval(arg[1:]) - s -1)/2 )
s = 0
if printable_check(key[::-1]):
return key[::-1]
else:
raise
except:
return None
# enlightenment
def solver6(filename):
try:
cmd = 'objdump -S -Mintel {} | grep "je" -2 | grep "cmp\|rsi,\["'
dat = check_out(cmd.format(filename))
cmp_sum = 0
key = ''
s = 0
for line in dat.split('\n')[:-1]:
oper = re.findall(r'lea|cmp', line)[0]
if cmp_sum != 3:
if oper == 'cmp':
cmp_sum += 1
continue
if oper == 'cmp':
arg = re.findall(r',0x\w*', line)[0]
else:
arg = re.findall(r'[+-]0x\w*', line)[0]
if arg[0] != ',':
s += eval(arg)
else:
if eval(arg[1:]) > 0xffffffff:
key += chr( (((0x10000 - (eval(arg[1:]) & 0xffff))*-1) - s - 1)/2 )
else:
key += chr( (eval(arg[1:]) - s -1)/2 )
s = 0
if printable_check(key[::-1]):
return key[::-1]
else:
raise
except:
return None
if __name__ == '__main__':
if len(sys.argv) == 1:
traverse()
else: # testing routine
filename = sys.argv[1]
print solver4('./enlightenment_dist/'+filename)
블로그의 정보
튜기's blogg(st1tch)
St1tch