본문 바로가기

[Wargame Write-up]/CodeEngn Challenges

[CodeEngn Challenges] Basic RCE 20



실행해도 빈 창만 뜬다. 그래서 우선 문제의 crackme3.key라는 key file을 만들고, 미리 CMP문에 breakpoint을 걸어 저 예시로 한번 디버깅해보았다. 



 

저 CMP에서 문자열 개수가 12h(18)인지 검사한다. 그래서 일단 필요한 부분에 주석을 달아보았다.



 

이후, 길이 조건에 충족하도록 입력한 후 401311에서 어떠한 과정을 거치는지 알아보았다. 대충 주석을 달아보았다. 



 

이를 바탕으로 python 코드를 작성해보았다. 알고리즘을 보자면, 입력한 문자열의 [0]~[13]번까지 14 문자를 0x41, 0x42, …, 0x4E로 각각 XOR 연산하여 각 자리 값을 치환, 각각의 연산 결과를 모두 더해 0x4020F9 주소에 넣는다. 아래는 0x12345678과의 XOR까지 진행한 결과이다. 같은 걸 볼 수 있다. 


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
def encrypt(string):
    if len(str(string)) != 18:
        return
 
    BL = 0x41
    sum = 0
    result = ""
 
    for i in range(len(string)):
        result += chr(ord(string[i]) ^ BL)
        BL += 1
        sum += ord(result[i])
        if BL == 0x4F:
            result += string[i+1:]
            break
 
    XORedSum = sum ^ 0x12345678
    print "result: %s\nresult in hex: 0x%s\n*(4020F9) = %d\n*(4020F9) ^ 0x12345678 = %d\n*(402149) = %d\n" \
        % (result, result.encode('hex'), sum, XORedSum, i)
 
    return (i, hex(int(str(XORedSum), 0)))
 
def ToLittleEndian(XORedSum):
    XORedSum = XORedSum[2:]
    result = ""
 
    for i in range(6-1-2):
        result += XORedSum[i:i+2]
    return ("0x" + result.capitalize())
cs

 

 

문자열 암호화 이후에는 0x4020F9 주소에 있는 값과 0x12345678을 XOR 취하고 40133C 함수를 호출한다.



 

40133C에서는 암호화하고 남은 문자열(입력값의 15~18번째 글자들)을 거꾸로 뒤집는다. (“ABCD” -> “DCBA”)



  

EAX 값(40133C 함수 결과)과 1~14번째 문자를 암호화한 값을 비교한다. 값이 상당히  다르므로, EAX 값에 저 값이 들어가도록 수정해야 한다. 0x123450E9를 little endian 방식으로, 0xE9503412로 넣을 것이다. 0xE9나 0x12의 글자는 키보드로 입력할 수 없으니 Hex Editor를 이용했다.


  

  

이대로 진행하면 다음과 같은 결과가 나온다. 크랙에는 성공했으나 문자열이 원하는 결과가 아니다. 이 문자열의 출처는 바로 암호화한 뒤의 문자열 + “!”이다.




문제에서는 저 부분이 “CodeEngn”임을 원하고 있다. 따라서 아까 만든 Python 코드를  이용하면 된다. 각 문자에 대한 암호화는 XOR만을 이용하기 때문에, 이 함수로 복호화해도 무관하다. 여기에서, 답이 여러 개 나올 수 있다는 문장을 이해할 수 있다. Key 파일에 들어가는 내용으로 [(CodeEngn을 복호화한 값 8자) + 임의의 6자 + (앞의 14자를 암호화한 4자리)] 형태로 들어가기 때문이다.



 

다시 Hex Editor를 열어, “result in hex”값을 그대로 입력하고 실행해, 끝에서 8글자를  파악한다. 키보드로 입력할 수 없는 글자가 있어, Python 콘솔에선 확인할 수 없다.



 

0x12345239이어야 하므로, little endian 방식으로 수정해준다.




수정 후, 실행하면, 목표하던 답보다 좀더 긴 문자열로 표시된다. “CodeEngn”만으로 끝내기 위해서는 9번째 글자를 NULL 문자(\x00)로 치환해줘야 한다. 9번째 글자는 암호화  함수에서 0x49와 XOR하므로 Hex Editor로 9번째 글자를 49로 바꿔주면 될 것이다. 중간의 한 문자가 바뀌기 때문에 10, 11번 과정을 다시 해줘야 한다.



  

완벽히 크랙에 성공한 모습이다. 


 


Auth Key: 0x022D272100282026497F7F7A79797B553412


정리하자면, 이 프로그램의 알고리즘은:

1. crackme3.key 파일 탐색 (없으면 종료)

2. 해당 파일 속 문자열 길이가 18인지 확인 (아니면 종료)

3. 14번째 글자까지 본문의 4번 과정으로 암호화

4. 남은 4글자는 역방향으로 EAX 레지스터에 넣어두고, 3번의 결과값과 같은지 비교 (다르면 종료)

5. 성공한 결과, 창 중앙에 “Cracked by: (3번의 결과 문자열)” 식으로 출력