pwnable.kr AEG 문제를 보던 중 푸는데에 ANGR을 사용해보면 좋을 것 같아 이 참에 찾아보았다.

구글링 등 예제 코드를 보고 내가 대충 작성한 코드는 다음과 같았는데

(문제 바이너리를 local 로 다운로드 받았다고 치고 시작)


mine.py 

 def main():

        proj = angr.Project('newbin0', load_options={"auto_load_libs": False})


        input_size = 0x60

        argv1 = claripy.BVS("argv1",input_size * 8)


        init = proj.factory.entry_state(args=["./newbin0", argv1])

        init.libc.buf_symbolic_bytes=input_size + 1

        al = [0x947C86,0x947976,0x9478FB,0x947889,0x947809,0x94778C,0x94770C,0x94768C,0x947610,0x9475A8,0x94752B,0x9474A9,0x94742C,0x9473B3,0x947337,0x9472BB,0x94723B]


        for byte in argv1.chop(8):

                init.add_constraints(byte >= '0')

                init.add_constraints(byte <= 'Z')

                init.add_constraints(byte != '\x3a')

                init.add_constraints(byte != '\x3b')

                init.add_constraints(byte != '\x3c')

                init.add_constraints(byte != '\x3d')

                init.add_constraints(byte != '\x3e')

                init.add_constraints(byte != '\x3f')

                init.add_constraints(byte != '\x40')


        init_path = proj.factory.path(init)

        path_group = proj.factory.path_group(init)

        path_group.explore(find=FIND_ADDR, avoid=al)


        found = path_group.found[0]

        solution = found.state.se.any_str(argv1)

        return solution



위와 같이 코드를 작성하고 실행할 경우 문제는 원하는 방향으로 풀리고 Hex 값을 return 해주지만 실행시간이 약 60초 걸렸다.

문제에서 주어진 시간은 10초로 angr 돌리는데에만 터무니없이 긴 시간이 걸렸음.

시간을 줄이기 위해 avoid 조건을 이용해 이것 저것 넣어봤는데 효과는 미비했다.


구글링 중 github에 aeg 문제풀이 코드가 나와있는 것을 찾았고 여기서 angr 부분만 참고했다.

(출처 : https://github.com/rot256/Wargames/blob/master/pwnable/aeg/attack.py)

원본 코드는 위 URL에서 확인할 수 있으며 밑에는 테스트에 필요한 코드만 추출, 조작함


attack.py

# Create symbolic buffer

p = angr.Project(tar)

buf = claripy.BVS("buf",48*8)

start_state = p.factory.blank_state(addr=0x2233b96)

start_state.memory.store(0x2436160, buf)


# Setup a stack frame

start_state.regs.rbp = start_state.regs.rsp

start_state.regs.rsp = start_state.regs.rsp - 0x50

start_state.memory.store(start_state.regs.rsp, start_state.se.BVV(0, 8*0x32))


# Setup stepper

pg = p.factory.path_group(start_state)

def step_func(pg):

    pg.drop(filter_func = lambda path: path.addr == 0x2233bbd)

    pg.stash(filter_func = lambda path: path.addr == 0x4006e0, from_stash='active', to_stash='found')

    return pg

pg.step(step_func = step_func, until = lambda pg: len(pg.found) > 0)

f = pr.found[0]

cert = f.state.se.any_str(buf)

print cert.encode('hex')


위 스크립트 실행 시 약 6-7s 정도 시간 소요로 답을 구할 수 있었다.


결국 차이점은

1) 적절한 바이너리의 start state 설정

2) avoid 조건

으로 필요한 연산만 하도록해 state를 줄여줄 수 있는 것으로 보인다.


조금 더 공부해봅시다.

'Pwnable.kr > Grotesque' 카테고리의 다른 글

[pwnable.kr] dos4fun - 444pt  (5) 2018.03.14
[pwnable.kr] sudoku - 111pt  (0) 2018.02.19
[pwnable.kr] AEG - 550pt  (0) 2018.02.11
[pwnable.kr] maze - 150pt  (0) 2017.12.23

+ Recent posts