가. 코드엔진(CodeEngn) 이란?
- 리버스 엔지니어링 정보를 공유하고 소프트웨어 보안에 대한 연구를 진행하는 국내 리버스 엔지니어링 커뮤니티이다.
- 리버스 엔지니어링과 관련된 컨퍼런스, 세미나, 워크숍 등을 운영하고 있으며 다양한 연습 문제도 제공하고 있다.
- 코드엔진(CodeEngn) 홈페이지는 아래의 링크를 통해 접속할 수 있다.
CodeEngn [코드엔진] 리버스엔지니어링 컨퍼런스
국내외 보안 세미나, 컨퍼런스, 워게임 일정을 제공합니다.
codeengn.com
나. 환경 세팅
1. 문제 다운로드
- 아래의 링크에 접속하여 RCE_Basic L01 문제를 다운로드한 뒤, 압축을 해제한다.
※ 파일의 암호는 "codeengn" 이다.
https://github.com/codeengn/codeengn-challenges/blob/main/RCE_Basic/01.7z
codeengn-challenges/RCE_Basic/01.7z at main · codeengn/codeengn-challenges
Challenge Files Provided by CodeEngn. Contribute to codeengn/codeengn-challenges development by creating an account on GitHub.
github.com
2. 필요 도구 다운로드
2-1. PEView
- PEView는 Windows PE(Portable Executable) 파일의 내부 구조를 분석할 수 있는 PE 파일 분석 도구이다.
- 아래의 사이트에 접속하여 PEview.zip 파일을 다운로드 및 압축해제한다.
http://wjradburn.com/software/
WJR Software - PEview (PE/COFF file viewer),...
Utilities (for use with Windows® XP operating system or later) PEview provides a quick and easy way to view the structure and content of 32-bit Portable Executable (PE) and Component Object File Format (COFF) files. This PE/COFF file viewer displays heade
wjradburn.com
2-2. OllyDbg
- OllyDbg는 Windows 환경에서 실행 파일을 어셈블리 레벨에서 분석하고 디버깅할 수 있는 무료 디버거(Debugger)이다.
- 아래의 링크를 클릭하여 OllyDbg를 다운로드 및 압축해제한다.
OllyDbg v1.10
www.ollydbg.de
2-3. Frida Client
- Frida는 실행 중인 프로그램을 분석하고 조작(후킹, Hooking)할 수 있는 오픈소스 도구(Tool)이다.
- 아래의 게시글을 참고하여 프리다 클라이언트를 설치한다.
https://hagsig.tistory.com/276
안드로이드 프리다 서버/클라이언트 설치방법
Frida Server/Client 설치 방법 - Android(AOS) 가. 설치 프로그램 설명1. 아나콘다(Anaconda)- 오픈소스 라이브러리를 모아둔 개발 플랫폼이다.- 아나콘다를 사용하면 파이썬을 버전별로 설치해서 사용할 수
hagsig.tistory.com
다. 문제 풀이
1. 문제 의도 파악
- 01.exe
파일을 실행하면 "Make me think your HD is a CD-Rom."이라는 메시지 창이 출력된다.
- 확인
버튼 클릭 시 "Nah... This is not a CD-ROM Drive!" 이라는 오류 창이 출력된다.
- 해당 문제는 HDD를 CD-ROM으로 인식시키는 게 목표인 것 같다.
2. PEView를 통한 분석
- 디버깅 도구를 통한 본격적인 분석에 앞서 PEView를 통해 01.exe 파일의 구조 정보를 분석한다.
2-1. 분석 시작점 찾기
- 디버깅 도구에서 프로그램을 로드하면 자동으로 엔트리 포인트(Entry Point)
에 BP(BreakPoint)
가 설정되어 프로그램 실행이 시작되는 지점에서 분석을 시작할 수 있다. 하지만 악성코드나 난독화된 파일의 경우 엔트리 포인트가 숨겨져 있거나 BP가 정상적으로 작동하지 않을 수 있다.
- 이럴 때 PEView를 활용하여 정확한 엔트리 포인트를 파악하면 불필요한 시행착오 없이 바로 코드 분석을 진행할 수 있다.
*엔트리 포인트(Entry Point) : 프로그램이 실행될 때 가장 먼저 실행되는 코드의 시작 지점
- PE 파일의 IMAGE_OPTIONAL_HEADER
영역에는 실행 파일이 메모리에 로드되고 실행될 때 필요한 정보가 포함되어 있다. 특히, Address Of Entry Point
와 Image Base
값을 통해 실제 엔트리 포인트를 확인할 수 있다.
*Address Of Entry Point : 실행이 시작되는 상대 가상 주소(RVA, Relative Virtual Address)
*Image Base : 실행 파일이 로드될 기본 메모리 주소
- PE 파일의 헤더에는 엔트리 포인트가 상대 가상 주소(RVA)로 저장되며, 프로그램이 로딩될 때 ImageBase
와 AddressOfEntryPoint
값을 더한 값이 실제 엔트리 포인트 주소가 된다.
- 점검 대상 파일은 AddressOfEntryPoint
값이 0x1000
, ImageBase
값이 0x00400000
이므로, 실제 엔트리 포인트는 0x00401000
이 된다.
2-2. 외부 API 함수 호출 확인
- IMPORT Address Table(IAT)
영역에는 실행 파일이 외부 라이브러리에서 정적 호출하는 API 함수들의 주소가 저장되어 있다.
구분 | 특징 |
정적 IAT 호출 | API를 직접 호출하며, IAT(Import Address Table)에 함수 주소가 기록됨 |
동적 API 호출 | GetProcAddress()와 LoadLibrary()를 사용해 실행 중 API 주소를 가져옴 (IAT에 기록되지 않음) |
- 점검 대 파일의 IAT 영역을 분석하니 GetDriveTypeA
와 MessageBoxA 함수
를 외부 라이브러리에서 호출해 오는 것을 알 수 있다.
*GetDriveTypeA : Windows API 함수로, 특정 드라이브의 유형(예: HDD, CD-ROM, 네트워크 드라이브 등)을 확인하는 데 사용된다.
*MessageBoxA : Windows API 함수 중 하나로, 메시지 박스를 생성한다.
3. OllyDbg를 통한 분석
- 올리디버거를 통해 점검 대상 프로그램을 로드한다.
- 전체적인 흐름을 보니 메시지 창 출력 후, GetDriveTypeA
함수를 통해 C드라이브의 유형을 검사하는 것 같다.
- GetDriveTypeA
함수 호출 다음 구문에 BP를 걸어보니, 함수의 반환값 3이 EAX
레지스터에 들어있는 것을 볼 수 있다.
- GetDriveTypeA
함수는 드라이브 유형에 대해 다음과 같은 값을 반환한다. C드라이브를 HDD로 인식하여 3을 반환한 것이다.
Return Code | Value | Description |
DRIVE_UNKNOWN | 0 | 알 수 없는 드라이브 |
DRIVE_NO_ROOT_DIR | 1 | 루트 디렉터리를 찾을 수 없음 |
DRIVE_REMOVABLE | 2 | 이동식 드라이브 (USB, 플로피 디스크 등) |
DRIVE_FIXED | 3 | 고정 디스크 (HDD, SSD) |
DRIVE_REMOTE | 4 | 네트워크 드라이브 |
DRIVE_CDROM | 5 | 광학 드라이브 (CD/DVD) |
DRIVE_RAMDISK | 6 | 램 디스크 |
- 그 이후 흐름을 분석하니 현재 EAX
값과 ESI
의 값이 일치하지 않아 실패 메시지가 출력되는 것으로 확인된다.
메모리 주소 | 어셈블리 명령어(Opcode) | 설명 | EAX 값 | ESI 값 |
00401013 | PUSH 01.00402094 | 검사할 드라이브 문자 주소 입력 | 00000001 | 00401000 |
00401018 | CALL <JMP.&KERNEL32.GetDriveTypeA> | GetDriveTypeA 호출 | 00000001 | 00401000 |
0040101D | INC ESI | ESI(엔트리포인트) 값 1증가 | 00000003 | 00401000 |
0040101E | DEC EAX | EAX(GetDriveTypeA 반환값) 1 감소 | 00000003 | 00401001 |
0040101F | JMP SHORT 01.00401021 | 00000002 | 00401001 | |
00401021 | INC ESI | ESI 값 1증가 | 00000002 | 00401001 |
00401022 | INC ESI | ESI 값 1증가 | 00000002 | 00401002 |
00401023 | DEC EAX | EAX 값 1감소 | 00000002 | 00401003 |
00401024 | CMP EAX,ESI | EAX와 ESI 값의 차이를 구함 | 00000001 | 00401003 |
00401026 | JE SHORT 01.0040103D | 두 값의 차이가 0이면 0040103D 으로 점프 | 00000001 | 00401003 |
00401028 | 실패 창 출력 로직 | |||
... | ||||
0040103D | 성공 창 출력 로직 |
4. 점검 로직 우회
- 성공 메시지가 출력되도록 하는 방법은 수도없이 많겠지만 본글에서는 아래와 같은 세 가지 방법으로 우회하였다.
4-1. 성공 로직으로 JMP
- 0x00401026 주소의 Opcode를 "JMP 0040103D"로 수정한다.
*JMP : 조건 없이 해당 주소로 이동
4-2. EAX 또는 ESI 값 수정
- CMP
명령어 수행 전에 EAX
와 ESI
값을 동일하게 수정한다.
4-3. 프라다 후킹을 통한 EAX 값 수정
- 아래의 사이트에 접속하면 Windows 프로그램에 대한 프리다 공식 후킹 소스코드를 확인할 수 있다.
https://frida.re/docs/examples/windows/
Windows
Observe and reprogram running programs on Windows, macOS, GNU/Linux, iOS, watchOS, tvOS, Android, FreeBSD, and QNX
frida.re
- 위 코드를 바탕으로 점검 대상 프로그램을 후킹 하여 EAX
값을 ESI
값과 동일하게 변경, CD-ROM으로 인식하게 하였다.
#프리다 코드 실행 명령어
#01.exe 프로그램이 실행중이어야 함
python hagsig_hooking.py 01.exe
//CodeEngn RCE_Basic L01 01.exe Frida hooking script
import frida
import sys
def on_message(message, data):
print("[%s] => %s" % (message, data))
def main(target_process):
session = frida.attach(target_process)
script = session.create_script("""
Interceptor.attach(ptr('0x00401024'), { // CMP EAX, ESI 명령어 주소
onEnter: function (args) {
var context = this.context;
console.log("[*] CMP EAX, ESI 실행 전");
console.log(" EAX: " + context.eax.toInt32());
console.log(" ESI: " + context.esi.toInt32());
// EAX 값을 ESI 값으로 강제 변경
context.eax = context.esi;
console.log("[*] 변조 후");
console.log(" EAX: " + context.eax.toInt32());
}
});
""")
script.on('message', on_message)
script.load()
print("[!] Ctrl+D on UNIX, Ctrl+Z on Windows/cmd.exe to detach from instrumented program.\n\n")
sys.stdin.read()
session.detach()
if __name__ == '__main__':
if len(sys.argv) != 2:
print("Usage: %s <process name or PID>" % __file__)
sys.exit(1)
try:
target_process = int(sys.argv[1])
except ValueError:
target_process = sys.argv[1]
main(target_process)
5. 풀이 결과
- 점검 로직 우회 결과 HDD를 CD-Rom으로 인식, 오류 메시지 창이 아닌 성공 메시지가 출력되는 것을 확인할 수 있다.
'CS App 취약점 진단 · 모의해킹' 카테고리의 다른 글
BetaBank 풀이 - 메모리 변조 취약점 (0) | 2025.01.02 |
---|---|
BetaBank 풀이 - 메모리 내 중요정보 평문노출 취약점 (0) | 2024.11.14 |
BetaBank 풀이 - 어셈블리 변조 취약점(무결성 검증) (0) | 2024.11.12 |
BetaFast 풀이 - 중요정보 평문저장 취약점(로컬 저장소) (0) | 2024.11.10 |
BetaBank 풀이 - 패킷 변조 취약점(SQL Injection) (0) | 2024.11.07 |