## Codegate CTF_2017(EasyCrack 101, rev)
[Summary]
1. 키 값을 찾아야 하는 간단한 바이너리가 101개 주어지고 각각의 바이너리의 키 값을 웹 페이지에 인증해야함
2. 바이너리들이 작고 101개가 전부 동일한 구조이므로 angr를 이용하여 자동화하여 문제를 풀 수 있음
[Analysis]
EasyCrack 101 문제는 Binary.zip 파일을 하나 던져주고 전부 다 크랙해서 패스워드를 찾아내 101개의 바이너리
모든 패스워드를 웹을 통해 인증하는 문제였다. 우선 다운로드 받은 binary 파일들 중 prob1과 prob2를 아래
[그림 1]과 같이 IDA를 이용해 분석해 보았다. prob1과 prob2 바이너리는 완전 동일한 구조로 이루어져 있었고
주소 값만 약간씩 다른 것을 확인할 수 있었다. 또한 이 문제도 angrybird 문제와 비슷하게 input값이 주어지면
자체 연산을 거쳐 조건 분기문으로 가서 비교를 한 후 키 값이 맞으면 "Good job"이라는 문자열을 틀리면
"No No!"라는 문자열을 출력하고 프로그램을 종료했다.
따라서 이 문제도 angr를 이용해서 풀면 쉬울거라고 생각했다. 하지만 문제점이 하나 있는데 여기서 각 101개의
바이너리들의 모든 find 주소와 avoid 주소를 수동으로 직접 IDA를 켜서 눈으로 확인하고 angr로 만든 파이썬
코드에 주소 값을 수정하면서 하나하나 키 값을 찾아내어 웹 상에 인증하는 것은 너무 비효율적이라고 생각이
되었다.
[그림 1] prob1 & prob2 분석
이 문제점은 아래 [그림 2]와 같이 avoid 주소의 어셈블리 코드(OPCODE)와 find 주소의 어셈블리코드(OPCODE)의
특징을 이용하여 해결하였다.
[그림 2] find & avoid OPCODE 특징
따라서 해당 OPCODE를 이용하여 find와 avoid 리스트를 자동으로 구한 후 angr를 이용하여 키 값을 자동으로 찾게
파이썬 스크립트를 짠 후 실행하면 아래 [그림 3]과 같이 101개의 바이너리에 대한 각각의 키 값을 얻을 수 있게 된다.
[그림 3] 키 값 자동화
각각의 키 값을 웹에 다 입력하게 되면 아래 [그림 4]와 같이 flag가 있는 웹페이지가 로드된다.
[Exploit Code] - easycrack101_exploit.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | import angr import hexdump from pwn import * def solve(binary_name, find_addr, avoid_addr): proj = angr.Project(binary_name, load_options={'auto_load_libs':False}) argv1 = angr.claripy.BVS("argv1", 100*8) initial_state = proj.factory.entry_state(args=[binary_name, argv1]) pg = proj.factory.path_group(initial_state) pg.explore(find=find_addr, avoid=avoid_addr) found = pg.found[0] solution = found.state.se.any_str(argv1) solution = solution[:solution.find("\x00")] return solution if __name__ == '__main__': for i in xrange(0,101): binary_name = "prob" binary_name += str(i+1) f = open(binary_name, 'rb') binary_content = f.read() f.close() total = '' for j in xrange(len(binary_content)): total += '%02X' % int(ord(binary_content[j])) find_list_tmp = [j for j in range(len(total)) if total.startswith('EB0ABF',j)] avoid_list_tmp = [j for j in range(len(total)) if total.startswith('FFFFC9C3',j)] find_list = []; avoid_list = [] for j in xrange(len(find_list_tmp)): find_list.append(0x400000 + (find_list_tmp[j]+1)/2 - 0xa) for j in xrange(len(avoid_list_tmp)): avoid_list.append(0x400000 + (avoid_list_tmp[j]+1)/2 - 0x8) #print avoid_list #print find_list #hexdump.hexdump(solve(binary_name, find_list[0], avoid_list[0])) #print find_list[0], avoid_list[0] print '['+str(i+1)+']', print(repr(solve(binary_name,find_list[0],avoid_list[0]))) | cs |
[Get Flag~~!!!!]
[그림 4] flag 확인("Thank_U_4 s0lving_MY_Pr0b...u_@re_vEry_genius!!!")
끝~!
'CTF writeup' 카테고리의 다른 글
[Secuinside CTF_2017] TrippleRotate(reversing) (0) | 2017.07.22 |
---|---|
[Secuinside CTF_2017] babyheap(pwn) (0) | 2017.07.20 |
[Codegate CTF_2017] angrybird(reversing) (0) | 2017.02.19 |
[Codegate CTF_2017] RamG-thunder(reversing) (2) | 2017.02.19 |
[Codegate CTF_2017] messenger(pwn) (8) | 2017.02.18 |