2017. 2. 19. 00:58

## 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!!!")


끝~!





Posted by holinder4S