본문 바로가기

[Wargame Write-up]/CodeEngn Challenges

[CodeEngn Challenges] Advance RCE 08

 

 

패킹 여부를 확인해보자. 언팩 과정은 무시해도 되겠다.

 

 

 

우선 실행해보자. Check it! 버튼을 누르면 더 입력하라고 한다. 분명 2글자라고 했는데 말이다.

 

 

 

Name의 길이가 3 이상이어야 이 분기문을 통과할 수 있는데

 

 

 

답은 2글자라고 했으므로 패치해준다. 편의를 위해 수정 사항을 따로 바이너리로 저장하자.

 

 

 

45BB9B의 함수 호출 결과, LOCAL.5라는 지역변수에 Serial 같은 것이 생성되었다.

이 정도 길이라면 상당한 코드량이 예상되므로, 첫 번째 Serial만을 중점적으로 보자.

 

 

 

위의 함수 내부로 들어와서 처음 만나는 반복문을 통과하면 ESI와 EDX가 0x656A2F00으로 설정되는데,

상위 2바이트가 첫 번째 Serial과 같은 것을 알 수 있다.

 

 

 

실제 45B9D0에서 호출한 함수로 상위 2바이트만 추출한 것을 알 수 있다. (함수명은 IDA의 도움을 받았다.)

 

 

 

 

이것으로 첫 번째 반복문에서 Serial의 첫 부분을 생성하는 것을 알 수 있다.

pseudo code로 주석을 달아본다면 다음과 같을 것이다.

 

 

 

분석한 결과를 토대로, Brute Force를 시행한다. 알고리즘은 다음과 같다.

1. 0-9, A-Z, a-z 문자 총 62개로 2자리 name 후보(00 ~ zz)를 생성

2. 한 글자씩 위의 알고리즘을 돌려 그 hex 값을 구한다.

3. long 타입 정수가 되는데, 필요한 부분([-9:-5])만 추출하여 출력한다.

4. 그 결과가 "5D88"과 같으면 끝낸다.

 

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
48
49
50
51
52
53
54
55
 
import os, string, hashlib, time
 
def showTitle():
    title =     '######################################################\n'
    title += '#                                                    #\n'
    title += '#   .dP"Y8 88 888888 88  88 88        db    88""Yb   #\n'
    title += '#   `Ybo." 88   88   88  88 88       dPYb   88__dP   #\n'
    title += '#   o.`Y8b 88   88   888888 88  .o  dP__Yb  88""Yb   #\n'
    title += '#   8bodP\' 88   88   88  88 88ood8 dP""""Yb 88oodP   #\n'
    title += '#                                                    #\n'
    title += '#                CodeEngn Advance 08                 #\n'
    title += '#                      keygen                        #\n'
    title += '#                                                    #\n'
    title += '######################################################'
    
    print title
 
def bruteforceFirstSerial():
    names = []
    charCandidate = list(string.digits) + list(string.ascii_uppercase) + list(string.ascii_lowercase)
    
    print "\n[*] Starting Brute Force"
 
    # generate name candidates
    for i in charCandidate:
        for j in charCandidate:
            names.append(i + j)
    
    for name in names: # in 62*62 cases
        esi = edx = 0
 
        for c in name:
            esi = (ord(c) + edx) * 0x772
            esi += esi ** 2
            esi *= 0x474 * 2
            edx = esi
 
        firstSerial = hex(esi).upper()[-9:-5]
 
        if firstSerial == "5D88":
            print "\n  [!] Found NAME: %s\n\n[*] Finish Brute Force" % name
            print "\n[*] Auth Key: md5(\"%s\") = %s" % (name, hashlib.md5(name).hexdigest().upper())
            return
        else:
            print "  [+] Analyzing Name [%s] - generated 1st serial text [%s]" % (name, firstSerial)
 
def main():
    os.system("cls")
    showTitle()
    time.sleep(2)
    bruteforceFirstSerial()
 
if __name__ == '__main__':
    main()
cs

 

 

Title을 보여주고 ^___^

 

 

 

답이 나왔지만, 여태 그랬듯이 유추 가능한 부분과 함께 모두 가렸다.

 

 

Clear!