ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 국가암호공모전 2017 (II-A)분야 6번 문제 풀이
    문제 풀이/2017 국가암호공모전 2020. 3. 10. 21:28

    2017년 국가암호공모전은 성적이 딱히 좋지는 않았지만, 인터넷에 풀이를 찾아봐도 거의 없어서 작성하고자 하였습니다.

     

    6번 문제는 게임 클라이언트의 불법적 조작과 관련된 문제입니다. 게임 클라이언트의 무결성을 검증하기 위해 게임을 실행할 때마다 해쉬값을 계산해서 서버로 보내주고, 이를 통해 클라 조작 여부를 판별하는 시나리오입니다. 

     

    먼가 nProtect...메x플스토리...이런 키워드가 생각나면서 추억이 새록새록 떠오르네요..... 실제로 해당 프로그램들이 이런 방식을(엄청 단순화되었겠지만) 사용한다는 생각을 하니 가슴이 뛰네요. 흠..?

     

    어쨌든 이 문제는 아주 간단한 exe 파일 reversing을 하는 문제인데, 아래에 대회때 적은 답안을 작성해보고자 합니다. 궁금한 것이 있으면 언제든 댓글로 말씀주세요.

     

    문제 (1) 실행파일 내부에서 해시정보를 생성하는 코드를 찾고, 찾은 코드를 변조하여 다른 해시값을 출력하도록 고치시오. 실행파일을 조작하는 내용을 자세히 기술하고 필요시 관련 소스코드를 제출하시오.

     

    답안 목차

    1. 0x404000 함수 외부

    2. 0x404000 함수 내부

    3. 코드를 변조해 다른 해시 값을 출력하도록 고치기

    -------------------------------------------------------

    1. 0x404000 함수 외부

    프로그램을 켜고 해쉬 정보 추출 버튼을 누르면 ClientCheck.exe에서 해쉬정보가 추출이 된다.

    실행파일 내부에서 해시정보를 생성하는 코드를 찾기 위해서 Ollydbg를 켜고 해쉬정보 추출 버튼을 눌렀는데, 프로그램이 바로 꺼졌다. 따라서 IsDebuggerPresent() 함수와 같은 안티디버깅 기법이 적용되어 있음을 알 수 있었다.

    실제 해쉬정보를 추출하는 함수에 위와 같은 함수가 있을 것이라고 추측하고 분석하였다. IsDebuggerPresent()함수가 주소 0x401B4B와 0x4017C3에 있는 것을 확인할 수 있었다.

    먼저 0x401B4B가 있는 함수 sub_401AB0을 분석해보면, FindResourceA(0,0xae,“bin”), LoadResource, LockResource등의 함수가 있어서 현재 파일인 ClientCheck.exe의 .rsrc영역의 bin 부분을 불러온다는 것을 알 수 있었다.

    "PEView"로 본 ClientCheck.exe의 .rsrc 영역의 bin 부분

    bin 부분의 뒤쪽에 JCAuth라는 string이 써져있고 그 뒤에 수상한 binary가 있는데, 55 8B(push ebp...)로 시작하는 것을 보고 스택 프레임(함수)인 것을 알 수 있었다. 함수의 존재 이유를 생각하였더니, 이를 실행중인 프로그램에 write한 후 실행시킬 것이라고 추측을 할 수 있었다.

    이후 이 함수에서 sub_401740을 부르고 각종 memory allocation(malloc)을 수행한 후 sub_402120을 부르고 WriteProcessMemory함수를 실행시키는 것을 알 수 있다.

    Ollydbg의 동적분석을 통해 보니 WriteProcessMemory의 인자가 (현재프로세스, 0x404000, ......) 등임을 알 수 있었다. 즉 현재 프로세스의 0x404000위치에 아까 다양한 Resource함수를 통해 불러왔던 ClientCheck.exe 의 bin 부분을 쓰는 것을 알 수 있었다.

    "OllyDbg"로 보는 ClientCheck.exe에서 WriteProcessMemory를 call하는 부분

    이제 0x404000 부분 메모리로 가보니 JCAuth 뒤쪽의 함수가 그대로 올려져 있는 것을 알 수 있었다.

    이후 0x401ab0 함수 내부에서 0x404000에 위치하는 함수를 실행해 이 함수 내부에서 실제로 해쉬값을 만들어내어 출력하는 것을 알 수 있었다.

     

    2. 0x404000 함수 내부 - 해쉬정보를 생성하는 코드

    Ollydbg를 이용해 동적 분석을 하였다.

    함수 내부에서 CryptAcquireContext, CryptCreateHash, CryptHashData, GetModuleFileName, fopen 함수등을 쓰는 것을 알 수 있었다.

    먼저 CryptCreateHash의 ALG_ID 인자로 CALG_SHA_256 identifier를 쓰는 것으로 보아 sha256 알고리즘과 깊은 관련이 있는 것을 알 수 있다. 이후 fopen으로 ClientCheck.exe 파일을 0x1f9d 바이트씩 파일의 끝까지 읽은 후 이를 이용해 다양한 Crypt 관련 함수를 call해서 sha256으로 해싱하는 것을 알 수 있었다.

    즉 내부 알고리즘을 python pseudocode로 나타내면 다음과 같다: sha256(open(“ClientCheck.exe”,“rb”).read())

    그리고 위 코드를 실행하면 (ClientCheck.exe에서 해쉬정보 추출 버튼을 누르면) “3BBA3BACBEAA309337CD68512BA2CF29D459ADB67CB79CDE494EF1E66B370272” 가 출

    력된다. 그리고 이는 ClientCheck.exe 의 sha256 checksum과 같다.

    이러한 생각을 뒷받침하기 위해 ClientCheck.exe 의 뒷부분을 살짝 바꾸었더니 나타나는 해시 정보가 달라지는 것을 알 수 있었다.

     

    3. 코드를 변조해 다른 해시 값을 출력하도록 고치기

    공격자 입장에서는 ClientCheck.exe 파일을 변조해도 나타나는 Hash 정보가 같아야 클라이언트를 조작할 수 있을 것이다.

    공격자 입장이 되어서 해시 정보를 마음대로 바꾸어보자.

    다른 해시 값을 출력하기 위해서는 해시를 만드는 알고리즘 부분을 바꾸거나 출력해주는 부분을 바꿀 수 있을 것이다. 해시를 실제로 출력해주는 부분이 대략 printf(hash)와 같을 것으로 추측해 출력해주는 부분을 바꾸고자 하였다.

    실제로도 위와 유사하였는데, crypt함수 부분에서 해시를 다 만든 이후에 sprintf 함수를 이용해 힙 부분에 해시를 출력한 후 해시의 시작 주소를 EDI 레지스터에 저장하고 이를 스택에 push해서 mfc120.#1524 함수의 인자로 넘겨주는 것을 알 수 있었다.

    그래서 이 주소를 바꾸고 mfc120.#1524 함수를 call한 뒤에 EDI를 다시 원래 주소로 바꾸어주니 해시 값이 바뀌는 것을 알 수 있었다. (c++ malloc – free 관련 에러로 인해서)

    따라서 공격자는

    1. ClientCheck.exe 파일 내부 어딘가에 “3BBA3BACBEAA309337CD68512BA2CF29D459ADB67CB79CDE494EF1E66B370272”라는

    해쉬를 저장한다.

    2. mfc120.#1524 함수를 call하기 전에 EDI의 값을 저 해시의 주소로 바꾼다.

    3. mfc120.#1524 함수를 실행한 후에 EDI의 값을 다시 malloc한 곳의 주소로 바꾼다.

    의 과정을 바탕으로 공격을 시행할 수 있다.

     

    이를 어셈블리어로 바꾸면 다음과 같다:

    MOV EDI,[0x123456??] - 추가 해주어야 한다.

    PUSH EDI

    CALL DWORD PTR DS:[<&mfc120.#1524>]

    MOV EDI,DWORD PTR SS:[EBP-20C0]

     

    안타깝게도 ClientCheck.exe 파일 내부에(data 영역같은 곳에) 공격자가 마음대로 쓰고 읽을 수 있는 64 byte의 공간은 찾을 수 없었다. 따라서 jcauth 함수 부분 중에 줄일 수 있는 부분을 줄여서 64 byte 이상의 공간을 만든 후에 여기에 해시를 넣어두기로 했다.

    64byte 이상의 공간을 만들기 위해 다음과 같은 방법을 사용했다.

    1. 함수 내부의 IsDebuggerPresent() 부분은 공격자 입장에서 필요 없으므로 삭제할 수 있다. 이를 통해 48 byte를 줄일 수 있었다.

    2. 문제가 생기지 않는다고 가정하고 각종 error 관련 코드를 삭제하였다. malloc error와 같은 부분을 삭제하여 나머지 공간을 확보할 수 있었다.

    3. 이제 공간이 생겼으므로 삭제된 코드 하단을 위쪽으로 붙이고 아래 공간에 해시를 저장하였다. 또 MOV EDI,[0x123456??] 부분을 HxD를 통해 코드 중간에 추가해주었다.

    JCAuth Function를 임의로 수정하였다.

    그리고 [0x123456??] 부분은 실제 코드 상에서 0x4043ad 가 되었다. 따라서 0x4043ad 부분의 해쉬를 고치면 출력되는 해쉬도 바뀌게 된다. 여기에 해당하는 ClientCheck.exe파일의 hxd 상에서의 오프셋은 1650D이다.

    결국 이를 통해 공격자 마음대로 실행파일을 조작해 해쉬값을 바꿀 수 있었다.

    다른 해쉬값을 출력하도록 실행파일을 조작할 수 있었다.

    아래의 텍스트는 위의 실행창과 대응되는 ClientCheck.exe의 바이너리를 HxD를 이용해 출력한 부분이다.

    -----------------------------------

     

    문제 (2): 문제 (1)의 해시값 조작이 가능한 이유를 설명하고 이를 막기 위해서는 어떠한 방식으로 재설계해야 할지 기술하시오. 보다 안전한 설계를 위한 다양한 설계가 가능하며 그 독창성에 따른 가산점이 부여됩니다.

     

    답안: 해시값 조작이 가능한 핵심적인 이유는 "ClientCheck.exe 내부에 해쉬값을 만드는 함수가 있고 이 함수를 공격자가 바꿀 수 있기 때문"이다.

    따라서 해쉬값 조작을 막으려면 반드시 이 함수를 공격자가 modify 할 수 없게 해야 한다. 이를 위해서는 다음과 같은 것들을 시도해볼 수 있다:

    1. 웹서버에 파일 업로드하기

    웹서버에 ClientCheck.exe 파일 내용을 업로드해서 웹서버 상에서 파일을 처리하면 공격자가 해쉬값 조작을 할 수 없을 것이다.

    2. 코드 가상화하기

    ClientCheck.exe 파일을 가상화된 cpu 등에서 실행시켜 공격자가 리버싱을 하기 힘들게 만든다.

     

    감사합니다.

    댓글

Designed by Tistory.