튜기's blogggg

2017 DEFCON CTF - Crackme2000 writeups

by St1tch

prob

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

활동하기