본문 바로가기

Games/CTF

CODEGATE2013 BIN200


CODEGATE2013 BIN200.pdf





주말에 CODEGATE 2013 예선이 있는것을 3일전에 알았다 -_-

스케줄도 차있었고 팀구성도 제대로 안됬기때문에 본선은 포기하고 연습삼아 몇개 풀어봤다.

연구실 형님이 BIN100 을 풀어놓으셨길래 BIN200 을 봤다.


32bit PE 가 주어진다.

실행시켜보면 zlib.dll 이 필요하다고한다.

내부적으로 압축알고리즘을 쓰는 모양이다.


인터넷에서 zlib.dll 을 구한다음 실행시켜보니 다음과같은 창이뜬다



Drive Name 을 입력하라고하는데, 아무거나 입력하면 그냥 끝난다.

IDA 로 열어서 조금 분석하다보니 PHYSICALDRIVE 0 번을 여는등 파일시스템의

MBR 에 접근을 한다.  가상머신에서 분석해야하나 싶었으나 설마 Codegate 예선문제가

실제로 부트섹터를 날리는 등 해를 끼칠리야 없겠지 싶어서 그냥 동적분석 하기로했다.


부트섹터등에 접근한다는것은 관리자 권한이 필요하다는 것이므로

관리자권한으로 프로그램을 실행시켜보니 아래와같이 드라이브 파티션과 섹터에 대한 정보들, 덤프가 나왔다.




눈에 띄는것은 "8pFHHoMssjtoucpX4EdPgcrdzuKXgEFV7iNur4YzDrOdfyNOA/bp7lX=" 라는 System Message 였다

해당 메시지는 단순히 데이터섹션에 하드코딩된 것이 printf 로 출력되는 것이었다.



마지막에 = 패딩이 붙는것이 딱 Base64 스러우므로 일단 Base64 디코딩부터 해봤는데, 별건 안나왔다.

기본적으로 IDA 정적분석을 통해 알아낸 사실들은 C++ 으로 만들어진 콘솔 바이너리이고 MBR 관련 정보들을 

Query 해서 출력한다는 점들, zlib 라이브러리의 compress 기능을 쓴다는 점들 정도였다.  



IDA 로 동적분석을 하면서 내가 준 Input 이 zlib compress 함수를 통해 압축되고

그 압축된 결과가 뭔가 복잡한 Encoding 연산을 수행하는 함수에 의해 인코딩되서

마지막에 Message: 로 다음과 같이 나타나는 것을 알아냈다.



이게도데체 뭐지? 라고 생각하면서 Input 을 여러가지로 주면서 나오는 Message 들을 그저 바라만 보고 있었는데

그 와중에 메시지가 위에서 출력됬던 System Message 와 비슷한 형태로 길게 출력될 때도 있는것을 발견하고

문득 내 Input 을 통해 생성된 Message 가 System Message 와 같아질 조건을 찾아야 하는게 아닌가? 라는 생각이 들었다.

그래서 마지막의 "8pFH6OJ=" 가 어떤 과정을 통해 생성된 것인지 추적해 들어가기 시작했다.


일단 내가 준 Drive Name Input 은 zlib.dll 의 compress 함수에 의해 압축이 되었는데, 확인해보니

이건 unix compress 툴의 압축 결과와 동일했다.  이렇게 압축된 데이터가 뭔가 복잡한 과정을 거쳐서

마지막의 Message 가 생성되는데, 메모리 스캐닝 꼼수를 써서 13B43B9 번지의 call 명령이 수행될 때

(주소는 실행시마다 바뀐다) 메시지가 메모리에 나타나는 것을 확인했다.



내가 준 Input 이 Xref 되는 모든 부분들에 대해서 검사해 나가면서 분석을 했는데 하다보니 다음과 같은

부분을 발견했다. EBP-18 이라는 지역변수의 값을 1 증가시키고 1291AD0 번지의 JNB 명령이

이 지역변수의 값과 sub_1291465 함수의 리턴값을 비교해서 종료조건을 검사한다.

그리고 이 카운터 변수를 sub_1291299 의 인자로 넘겨준뒤에 함수의 리턴값을 EBP-144h 에

저장하고 그것을 포인터로서 참조하여 1바이트를 가져온다(movsx edx, byte ptr[ecx])

이것을 3 과 XOR 하고 그 결과를 원래의 위치에 쓴다.



그다음의 루틴을 분석하다보니 이전에 참조했던 메모리 값들에 대해서 이번에는

0xFC 와 AND 연산을 하고 2비트 SAR 연산을 하는 것을 발견했다.



그리고 조금더 분석을 하다보니 메모리상에 "ABCDEFGHI.... 0123456789+/" 이런식으로 쭉 들어있는

데이터를 아래와 같이 "QwErTyUi....." 로 수정하는 루틴을 발견했다.



여기까지 본순간 이건 Custom Table 을 사용하는 Base64 인코딩 알고리즘이라는 느낌이 왔다.

이것을 비교적 빠르게 눈치챌 수 있었던건, 옜날에 딱 이렇게 동작하는 custom base64 인코딩프로그램을 

개인적인 암호화를 위해 만든적이 있었기 때문이다.


Base64 는 8비트의 데이터 3개를 6비트의 데이터 4개의 Index로 쪼개기 때문에 위에서 봤던 2비트 SAR 연산을

해야하고, 각각의 Index 를 통해서 테이블을 참조하는데, 그 방식은 아래와 같다.



원래 Base64 테이블은 ABCDEFG... 0123456789+/ 로 구성되어있다.

하지만 여기서는 이 공식적인 기본 테이블을 사용하지 않고 QwErTyU... 로 구성된 커스텀 테이블을 사용한 것이다.

결론은 내 Input 이 zlib 의 compress 함수로 압축되고, 그 압축된 바이너리가 여기서의 Custom Base64 로 인코딩

되는 것이다.  따라서 나는 문제와 동일한 Custom 테이블을 사용하는 Base64 디코더를 만들었다



이걸로 System Message "8pFHHoMssjtoucpX4EdPgcrdzuKXgEFV7iNur4YzDrOdfyNOA/bp7lX=" 를 디코딩했다.

그리고 그 결과를 zlib decompress 시켰다.  compress 툴을 구하다가 openssl 에 zlib 라이브러리 기능이

구현되어있는것을 알고 다음과 같이 decompress 했다.

decompress 가 된 결과는 flag 가 담긴 메시지였다.



부트섹터에 대한 작업들은 훼이크였고 compress 와 커스텀 Base64 인코딩 부분을 파악하는게 핵심인 문제였다

풀이시간은 4~5시간정도 걸린것 같다.




'Games > CTF' 카테고리의 다른 글

DEFCON20 PWN100  (0) 2013.03.19
Forbidden BITS x96  (0) 2013.03.19
PHDays 2012 pwn200  (0) 2013.01.25
PHDays 2012 Misc400  (0) 2013.01.23
PHDays 2012 Realword 200  (0) 2013.01.23