Name이 한 글자라고 되어있는데, 실제 한 글자만 입력해보면, 더 입력하라고 한다.
저 메시지를 출력하는 부분으로 이동하면, Name은 3글자 이상이어야 함을 알 수 있다.
그러므로 문제를 풀기 위해 한 글자만 입력할 수 있도록 패치한 후 진행한다.
패치 후 파일로 추출해 실행해보면 방금 전 메시지가 출력되지 않는다.
방금 전처럼 성공 메시지 출력 부분을 찾아가 그 곳으로 가보면, 45BBA9의 JNE문을 기준으로 성공 메시지 출력 / Sleep(333)으로 쪼개짐을 알 수 있다.
더 위를 보면 Key 값의 크기는 30 byte 이하임을 알 수 있는데, 이 부분에 breakpoint를 걸도록 한다.
실행해 breakpoint 부분으로 오면, F8로 한 단계씩 진행하면서 Key를 생성하는 함수가 어디인지 확인한다. 특히 CALL문이 많기 때문에 레지스터 값에 유의하며 확인해야 한다.
45B850으로부터 Key 값이 생성, 지역변수로 저장된다. 이 안을 들여다보면, Name을 이용해 4번 루프를 돌려 나온 값을 ESI, EDI에 저장한다. 그 후 ESI, EDI를 이용해 4086C8 함수로 다시 변환시키고, 404D0C 함수로 적당량으로 slicing을 가한다. (Keygen을 만들어 보려고 했으나, 그 코드의 양이 너무 방대해 주저앉았다.)
결국 선택한 방법은 Brute force이다. 한 글자라지만, 경우의 수가 꽤 되므로, 약간의 논리적인 연산을 더할 것이다. 우선 결과 값을 분석해보자. 아래의 이미지는 각각 Name이 a, b일 때의 결과이다.
a:
b:
8번에서 미리 45B850 함수의 연산 루프 4개를 분석해놓았다. 각 루프의 목적지를 보자면, 첫 번째는 ESI, 두 번째는 LOCAL.4, 세 번째는 EDI, LOCAL.5임을 알 수 있다. 게다가 하이픈(‘-‘)을 기준으로 두 번째(3EEC or 3F80)부터는 4086C8 함수로 생성하는 문자열이다. 즉, 확인할 것은 결과값의 첫 번째 문자열(66EE, 7629, …)과 1, 3번째 루프이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 |
def firstLoop(Name):
edx = 0
for c in Name:
esi = (ord(c) + edx) * 0x772 * (((ord(c) + edx) * 0x772) + 1) * 0x474 * 2
edx = esi
return hex(esi)[len(hex(esi))-9:len(hex(esi))-5].upper()
def thirdLoop(Name):
edi = 0
for c in Name:
edi += (ord(c) + 0x929 + 0x767 + (edi - 0x33 + 1) * edi) * 0x8392
return hex(edi)[2:].upper()
print "Result of first loop when Name is 'a': %s" % firstLoop('a')
print "Result of third loop when Name is 'a': %s" % thirdLoop('a')
print "Result of first loop when Name is 'b': %s" % firstLoop('b')
print "Result of third loop when Name is 'b': %s" % thirdLoop('b') |
cs |
이를 바탕으로 Python으로 작성한 코드이다. 작성 중 정리할 수 있는 수식은 정리했다. 첫 번째 루프에서 결과 값의 첫 번째 문자열을 생성함을 볼 수 있다.
이제 Brute force용 함수를 만든다. 첫 번째 루프의 알고리즘으로 문제에 주어진 Key 값의 첫 번째 문자열인 BEDA가 되는 글자를 찾도록 말이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 |
def firstLoop(Name):
edx = 0
for c in Name:
esi = (ord(c) + edx) * 0x772 * (((ord(c) + edx) * 0x772) + 1) * 0x474 * 2
edx = esi
return hex(esi)[len(hex(esi))-9:len(hex(esi))-5].upper()
def bruteforceOnFirstLoop(compareWith):
for i in range(ord('0'), ord('z')+1):
if firstLoop(chr(i)) == compareWith:
print "Name is %c" % chr(i)
break
bruteforceOnFirstLoop("BEDA") |
cs |
이 코드를 실행하면 이렇게 나온다.
정답은 저 Name을 MD5로 암호화한 값이다. 다음은 미리 만들어둔 hash 암호화 프로그램으로 추출한 결과이다.
'[Wargame Write-up] > CodeEngn Challenges' 카테고리의 다른 글
[CodeEngn Challenges] Basic RCE 19 (0) | 2016.08.30 |
---|---|
[CodeEngn Challenges] Basic RCE 18 (0) | 2016.08.30 |
[CodeEngn Challenges] Basic RCE 16 (0) | 2016.08.30 |
[CodeEngn Challenges] Basic RCE 15 (0) | 2016.08.30 |
[CodeEngn Challenges] Basic RCE 14 (0) | 2016.08.30 |