문제입니다.

실행화면입니다.

패킹되어 있지는 않은 것 같습니다.

먼저 성공문자열을 찾아보았습니다.

"Good job. Now ~~~"로 시작하네요.

들어가 보겠습니다.

break point 부분을 보시면 "CMP BYTE PTR SS:[EBP-A5], 0"명령의 결과로 성공과 실패의 문자열이 출력되는 것을 확인할 수 있습니다.

그럼 "EBP-A5"의 값은 어디서 만들어 지는지 확인해보겠습니다.

401FBA 부분을 살펴보면 CALL의 결과를 AL에 대입하고 EBP-A5에 저장하는 것을 확인할 수 있습니다.

함수 내부로 들어가 EAX가 어떻게 리턴이 되는지 확인해 보겠습니다.

[리턴값 EAX 찾기1]

401C80을 살펴보면 EBP-C4의 값을 EAX에 대입하고 있습니다.

그럼 EBP-C4는 어디서 값을 가져오는지 확인해보겠습니다.

[리턴값 EAX 찾기2]

401BC2를 살벼보면 EBP-10C의 값을 EDX에 넣고 그값을 또 EBP-C4에 저장하는 것을 확인할 수 있습니다.

[리턴값 EAX 찾기3]

401B57을 보면 어떤 함수를 CALL한 결과를 EAX담고 5와 비교하고 있습니다.

EAX가 5보다 크면 401B61에서 EBP-69에 0을 저장하고 401B79에서 다시 그값을 EAX에 저장하는 것을 확인할 수 있습니다.

비교값을 만드는 부분의 로직이 복잡해서 IDA의 HEXRAY기능을 이용하여 분석해보겠습니다.

G를 누르고 401FBA를 쳤을 때의 화면입니다.

즉, 이 부분이 EAX를 리턴해주는 함수이며 옆에보니 check_serial이라고 써있네요 ㅎㅎ

노란색 call을 더블클릭하여 들어가보겠습니다.

들어가서 쭉 내리다보면 if문이 보입니다. 5와 비교하는 것으로 보아 올리디버거로 찾은 "CMP EAX,5"부분인 것 같습니다. 그렇다면 여기서 EAX는 "v23 - v22" 라는 것을 알 수가 있습니다.

빨간색 네모박스의 v23과 v22를 살펴보면 stringFindSecond()함수에 "&28", "v10" 그리고 "&28", "v11" 두개의 인자로 들어가는 것을 확인 할 수 있는데 함수를 마우스로 한번 클릭하면 IDA 하단에서 아래처럼 해당 코드의 주소를 알아낼 수 있습니다.

다시 올리디버거로 돌아가서 두개의 stringFindSecond() 함수 부분을 확인하고 분석해보겠습니다.

[Serial Check 부분]

첫번째 함수는 분석결과 Serial을 값을 1byte씩 추출하여 "AJXGRFV6BKOW3Y9TM4S2ZU I70H5Q81PDECLNAJXGRFV6BKOW3Y9TM4S2ZU I70H5Q81PDECLNAJXGRFV6BKOW3Y9TM4S2ZU I70H5Q81PDECLN"이 문자열에 있는지 확인하고 있을 경우 index를 반환합니다.

만일 시리얼에 "G"라는 글자가 있다면 "G"의 index는 4번째 이고 인덱스는 0부터 시작하므로 결과는 3이 됩니다.

위 화면은 Serial 중 1byte를 뽑아 저장하는 부분의 주소이고 현재 "W"값이 들어가 있습니다.

결과를 확인해보면!

index는 0x30 이고 10진수로 48 , 즉 49번째에 있습니다.

[Name Check 부분]

두번째 stringFindSecond() 부분은 serial 대신 name 부분을 1byte를 추출하여 index를 반환하고 있습니다.

name "1234"중 1이 저장되어있고 결과는 아래와 같습니다.

0x43이 결과물입니다. 0x43은 10진수 67입니다.

이제 이결과물을 가지고 401B52 에서 "SUB EAX, EDX" 를 통해 "serial 결과물 - name 결과물"한 결과를 EAX에 넣고 5와 비교를 하고 있습니다.

즉, name의 index와 serial의 index의 길이가 5를 초과하면 안됩니다.

최종 결과물을 확인하기 위해 "1234 / abcdefghijkl" 로 입력하여 확인해보았습니다.

[테스트 결과]

1. Serial : "A" , 결과 : 0x25 | Name : "1", 결과 : 0x43 | sub : abs(30)

2. Serial : "B" , 결과 : 0x2D | Name : "1", 결과 : 0x43 | sub : abs(22)

3. Serial : "C" , 결과 : 0x47 | Name : "1", 결과 : 0x43 | sub : abs(4)

4. Serial : "D" , 결과 : 0x45 | Name : "2", 결과 : 0x38 | sub : abs(13)

5. Serial : "E" , 결과 : 0x46 | Name : "2", 결과 : 0x38 | sub : abs(14)

6. Serial : "F" , 결과 : 0x2A | Name : "2", 결과 : 0x38 | sub : abs(14)

7. Serial : "G" , 결과 : 0x28 | Name : "3", 결과 : 0x31 | sub : abs(9)

8. Serial : "H" , 결과 : 0x3F | Name : "3", 결과 : 0x31 | sub : abs(14)

9. Serial : "I" , 결과 : 0x3c | Name : "3", 결과 : 0x31 | sub : abs(11)

10. Serial : "J" , 결과 : 0x26 | Name : "4", 결과 : 0x36 | sub : abs(16)

11. Serial : "K" , 결과 : 0x2E | Name : "4", 결과 : 0x36 | sub : abs(8)

12. Serial : "L" , 결과 : 0x48 | Name : "4", 결과 : 0x36 | sub : abs(18)

[Serial이 WWWCCCJJJRRR 일 경우]

1. Serial : "W", 결과 : 0x30, 10진수 : 48

2. Serial : "C", 결과 : 0x47, 10진수 : 71

3. Serial : "J", 결과 : 0x26, 10진수 : 38

4. Serial : "R", 결과 : 0x29, 10진수 : 41

12번의 반복을 할 때 serial은 순차적으로 결과물을 추출하고 name은 자리수당 3번씩 같은 결과물을 추출하고 있습니다.

이를 토대로 name에 "WCJR"을 넣고 serial에 "WWWCCCJJJRRR"을 넣으면 name의 index와 serial의 index가 같기 때문에 차를 구하면 0이되므로 성공문자열을 출력할 것입니다.

성공했습니다.

하지만 "Hint 2 : 정답으로 나올 수 있는 문자열 중 (0~9, a~z, A~Z) 순서상 가장 먼저 오는 문자열" 의 조건을 맞추어야 하기 때문에 "AJXGRFV6BKOW3Y9TM4S2ZU I70H5Q81PDECLNAJXGRFV6BKOW3Y9TM4S2ZU I70H5Q81PDECLNAJXGRFV6BKOW3Y9TM4S2ZU I70H5Q81PDECLN"문자 중 "WCJR"의 각 문자의 앞뒤로 5글자내의 범위에서 가장 빠른 숫자를 찾으면!

"31a6" 이 됩니다.

인증을 하면!

후... 성공입니다.

10번 문제를 이해하기까지 오래 걸렸습니다..

포기하지 않고 꾸준히 하다보면 지금보다는 조금 더 나아질 것이라 생각하고 더

열심히 해야겠습니다

Advance RCE L10 성공!

'WAR GAME > CodeEngn(Advance)' 카테고리의 다른 글

Advance RCE L09  (0) 2020.07.15
Advance RCE L08  (0) 2020.04.29
Advance RCE L07  (0) 2020.04.29
Advance RCE L06  (0) 2020.04.29
Advance RCE L05  (0) 2020.04.29

+ Recent posts