튜기's bloggggg(st1tch)

Prob


- Category : Coding 
- Score : 250 

Challenge


- 이 문제는 문제설명에도 적혀있다시피 base64로 encode된 x64 machine code를 11개 정도 준다. 이 machine code를 1개를 실행시키던, 전부 실행시키던, 순서를 뒤죽박죽 시키던 정상적으로 실행이 되는 순서조합의 machine code를 보내면 stage를 통과하는 그런 류의 문제이다.(실제로는 주어진 machine code를 모두 사용하는 경우밖에 보지 못한 것 같다.)


Solution

- 11개라고 가정했을 때, 모든 permutation을 검증을 하기에는 stage한개에 대한 최적의 실행순서를 찾는데도 오랜 시간이 걸린다. 

- 따라서 해당 순서에 실행이 되는 machine code가 있으면, 재귀적으로 다음 machine code를 실행해서, 유효한 machine code만 우선 실행시키는 방법을 사용하여, 트리순회와 같은 느낌으로 machine code의 실행결과를 검증하면 된다. 

- 예를들어, 6 번 째의 machine code가 첫 번째 순서에 있을 때 실행이 된다면, 이 machine code가 첫 번째에 올 때의 모든 경우를 생각한다. 재귀적으로 두 번째 순서에 나머지 machine code를 넣어보고 유효한 machine 코드의 목록들에 대해서 다시 재귀적으로 탐색한다. 즉, 해당 순서에 대해 유효한 machine code에 대해 dfs탐색을 한다고 생각하면 된다. 


- x64 machine code가 segment fault 없이 제대로 실행이 되는지 확인하는 방법으로는 python 모듈중에 unicorn 모듈을 사용하여 확인을 했다. 사실 여러가지 방법이 있겠지만 unicorn모듈을 통해 가상 emulate를 간단하게 할 수 있기 때문에 이 방법을 사용했다.


Solve


from __future__ import print_function
from unicorn import *
from unicorn.x86_const import *
from pwn import *
from base64 import b64encode, b64decode

def emulator(OPCODE):
    ADDRESS = 0x1000000
    try:
        mu = Uc(UC_ARCH_X86, UC_MODE_64)
        mu.mem_map(ADDRESS, 2 * 1024 * 1024)
        mu.mem_write(ADDRESS, OPCODE)
        mu.emu_start(ADDRESS, ADDRESS + len(OPCODE))
        return True
    except UcError as e:
        return False

def recursion(opcode, cur, depth, dict_):
    if depth > len(opcode):
        return
    opcodes = []
    for op in opcode:
        if op not in cur:
            opcodes.append(op)
    for op in opcodes:
        exec_op = ''.join(cur) + op
        if emulator(exec_op):
            dict_[len(exec_op)] = cur+[op]
            recursion(opcode, cur + [op], depth+1, dict_)

def solver():
    p = log.progress('start...')
    cnt = 1
    while True:
        try:
            dat = s.recvuntil(':', drop=True)
            block = eval(dat[dat.index('['):dat.index(']')+1])
            dict_ = {}
            recursion(map(b64decode, block), [], 0, dict_)
            s.sendline(sha256sumhex(''.join(sorted(dict_.items())[::-1][0][1])))
            p.status('stage{}'.format(cnt))
            cnt += 1
        except:
            log.success('get flag!')
            s.interactive()
            break

if __name__ == '__main__':
    s = remote('buildingblocks.eatpwnnosleep.com', 46115)
    solver()

Result





Comment +0