※ ssdeep와 Pyssdeep 설치 관련 정보를 게시합니다. 

[ Source Path ]
ssdeep : http://ssdeep.sourceforge.net/
Pyssdeep : http://code.google.com/p/pyssdeep
   - pyssdeep는 현재 ( 2011.11.18 ) 별도의 다운로드는 지원하지 않으며 svn을 통한 Source ( Trunk ) 다운만 지원
      하고 있다. 또한 설치 방법은 pyssdeep 사이트에서 공지하고 있는 방법을 사용한다. 

Step 0. 사전 설치 환경 꾸리기

$ sudo apt-get install subversion
   - pyssdeep은 svn으로 Source만을 제공하기 때문에 svn을 이용해 최신 Trunk를 다운받아야 하므로 Subverion
     을 설치해 줘야 한다. 

Step 1. ssdeep 설치하기

$ wget http://sourceforge.net/projects/ssdeep/files/ssdeep-2.7/ssdeep-2.7.tar.gz
$ tar -xvfz ssdeep-2.7.tar.gz
$ cd ssdeep-2.7
$ ./configure
$ make
$ make check
$ sudo make install
$ sudo ldconfig
   - ssdeep을 설치한 후 (추정) 설치과정에서 설정한 신규 정보를 반영하기 위한 명령어로 추정된다. 반드시 해줘야
     시스템이 ssdeep에 의해 변경된 정보를 반영할 수 있다. 

Step 2. pyssdeep 설치하기 

( 현재 경로 : ssdeep-2.7 )
$ svn checkout http://pyssdeep.googlecode.com/svn/trunk/ pyssdeep-read-only
$ cd pyssdeep-read-only
$ python setup.py build
$ sudo python setup.py install
$ sudo ldconfig

Step 3. 확인하기

$ python
>> import ssdeep
>>
- 위와 같이 import시 Error가 발생하지 않으면 정상적으로 설치가 완료된 것이다. 

[ Error Report ]
ImportError: libfuzzy.so.0: cannot open shared object file: No such file or directory

$ sudo echo "/usr/local/lib" >> /etc/ld.so.conf
$ sudo ldconfig
   - 첫번째 Line의 명령이 /etc 폴터의 권한 문제로 정상 동작하지 않은 경우가 있었지만 두번째 Line의 명령어를
     실행해도 위의 문제는 해결되었다. 

ssdeep.c:3:20: fatal error: Python.h: No such file or directory

$ sudo apt-cache search python
$ sudo apt-get install python2.7-dev 


'Techniques > Ubuntu' 카테고리의 다른 글

[Ubuntu] YARA Install 와 Error Report  (0) 2011.11.17
Posted by GhostKei
,

Chapter 6. Documents, ShellCode and URLs
문서 뷰어, 웹 브라우저, 브라우저 플러그 인과 같은 Client Application에 대한 공격이 점점 증가하고 있다. 악성코드 제작자들은 다양한 사회 공각 기법, 취약점 공격을 이용해 공격하고 있으며 피해자 시스템에 설치된 악성코드를 수집하는 행위를 막기 위한 기능도 사용하고 있다. 이러한 감염되는 모든 현상들은 악성 웹 페이지에 접근하거나 E-Mail을 통해 받은 악성 PDF 또는 MS Office 문서를 열어보았을 때  감염된다. 이러한 공격은 특별한 지식과 추가적인 툴에 대해 알아야 하고 이 Chapter에서 그러한 것에 대해 다루게 될 것이다.

분석하고자 하는 악성 문서가 개인 파일 포멧 , 난독화 기법 , 범용적으로 사용되는 방대한 양의 Exploitation 기법이 적용되어 있을 때 여러분은 노력하게 된다. 게다가, 취약점이 동작하는 정확한 환경을 알지 못한다. 마찬가지로, 파일내에 ShellCode가 어떻게 , 어디에 있는지 확실한 수 없게 된다. 이 Chapter는 이러한 타입의 문제에도 불구하고 문서를 분석할 수 있는 정적 / 동작 기법 모두를 설명한다.

Analyzing JavaScript
JavaScript는 악성코드를 분석할 때 이해하기 어려운 언어다. JavaScript를 사용하면, 공격자는 Victim의 시스템에서 동작하는 ( 브라우저 플러그 인과 같은 ) 다양한 요소들과 상호작용 할 수 있다. 그러므로, JavaScript Code엇 잘못된 입력값을 전달해 브라우저와 브라우저 플러그 인에서 취약점을 동작시킬 수 있다. 때론, 취약한 함수 명을 찾아 Exploit을 탐지할 수도 있지만, 대부분의 경우, 공격자는 알기 어렵게 하기 위해 JavaScript를 난독화 한다. ( 하지만 브라우저는 이해할 수 있다. ) 여러분은 Packet Captures , PDF , SWFs( Flash Files )에서 악성 JavaScript를 발견한다. 그러므로, 이 Section은 처음에 JavaScript를 어떻게 다루고 다른 문서 포멧을 분석하는 방법에 대해 언급한다.

***** 레시피 6-1 : SpiderMonkey를 이용한 JavaScript 분석 *****
SpiderMonkey는 C로 만든 JavaScript 엔진이다. 이 툴은 Linux에서 Command Line 명령을 통해 JavaScript를 ( 브라우저나 플러그 인을 사용하지 않고 ) 해석한다. 그러므로, 알 수 없는 JavaScript Code를 실행하고 분석하기 위한 안전한 환경을 만든다. 예를 들어, 여러분이 조사하고 있는 Page에 다음과 같은 Script를 추가하는 것도 지원한다.

     < html >
     < meta name="robots" content="noindex" >
     < title > 404 NOT FOUND < /title >
     < /head >< body >
     < h1 > Not Found < /h1 >
     < p > The Requested URL /pics/show.php?s=1e8f2530d5 was not found on this server. < /p >

     < script language='JavaScript' >
     var CRYPT={signature: 'JHDjhusud7HG' , _keyStr:'
     ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
     decode:function(input){var output=' '; var chr1, chr2, chr3; var enc1, enc2, enc3, enc4;var
     [REMOVED]
    eval(CRYPT.obfuscate('1641821542234 ...'))
     < /script >


( 역 - 별도의 소스를 제공하고 있지 않으며 단지 CD내에 레시피 6-1의 테스트 과정이 동영상으로 첨부되어
         있다.  따라서, 레시피 6-1의 JavaScript Encode 방식에 대한 테스트를 다른 JavaScript 파일을 이용하
         도록 하겠다. )

[ 테스트 샘플 ]

Figure 1-1. JavaScript Decoding Test Code


만약, 브라우저내의 Page를 보면, 서버는 404 Not Found Message를 통해 파일을 찾을 수 없다고 생각할 것이다. 그러나, 소스를 본다면, Page 하위의 Script는 Parameter로 함수에 전달되는 추가적인 JavaScript를 처리하기 위해 eval 함수를 사용한다.  정상적인 경우, JavaScript를 처리하지만, 공격자는 CRYPT.obfucate 함수를 만들어 JavaScript Code Block을 해석한다. 이는 공격자가 코드의 동작을 확인하려는 누군가로 부터 소스 코드를 보호하기 위한 방법이다. 

[ SpiderMonkey 설치하기 ]
소스에서 다음의 명령어를 이용해 소스단위 설치를 하거나 "apt-get install spidermonkey-bin" 을 직접 입력해 SpiderMonkey를 설치할 수 있다. 

     $ wget http://ftp.mozilla.org/pub/mozilla.org/js/js-1.8.0-rc1.tar.gz    
     $ tar -zxvf js-1.8.0-rc1.tar.gz
     $ cd js/src/
     $ make BUILD_OPT=1 -f MakeFile.ref
     $ make install

( 역 - 실제 $ make install 에서 오류가 발생했다. 아마 Target을 지정하지 않아서 발생한 것으로 추정된다.
         따라서 Source를 통한 설치가 아닌 apt-get을 통한 설치를 수행하도록 하겠다 )


예제에서 JavaScript 상태를 확인하거나 유사 경우의 JavaScript를 분석해야 할 경우, 다음의 단계를 따르면 된다.

1. JavaScript block을 추출해 ( <script> 태그내에 있는 모든 것을 의미하지만, <script> 태그 자체를 포함하지
    는 않는다. ) 별도의 파일로 저장한다.
2. eval = print 를 Script의 첫번째 Line에 추가한다. 이는 eval을 재정의해 eval에 전달되는 Parameter를 출력
    한 후 실행된다.
3. 다음의 명령어를 사용해 SpiderMonkey를 통해 Script를 실행한다.

     $ js example_js_eval.txt | indent
Figure 1-2. JavaScript Decoding Test Code 
( 역 - 테스트에 사용한 JavaScript의 경우 eval을 통한 Decoding 이후 추가 작업이 필요한 형태이기 때문에
         책과 같이 바로 코드가 보이지 않는 것이다. )

SpiderMonkey는 CRYPT.obfuscate 함수를 실행하지만, eval에 결과값을 전달하는 대신 그 결과값을 출력한
다. 이제 여러분은 공격자의 실제 의도를 알 수 있고 Internet Explorer 브라우저 , Adobe Reader 플러그 인, Winamp ActiveX Control을 이용해 분석할 수 있다.

( 참고 - 추가 "eval = print"를 이용해 Decode 하는 방법 :: http://ghostkei.tistory.com/140 )

***** 레시피 6-2 : Junpack를 이요해 JavaScript 자동으로 Decode 하기 *****
이번 섹션에서, 자동으로 난독화된 JavaScript를 Decode 하기 위한 Jsunpack ( 웹사이트 ) 와  Jsunpack-n ( Command Line 버전 ) 의 사용법에 대해 배운다. Jsunapck은 (이 책의 저자중 한명인 ) Blake Hartstein 이 만든 툴로 Shmoocon 2009 에서 처음으로 소개되었다. 2010 Shmoocon에서, Blake는 Jsunpack을 업그레이드를 통해 더욱 정확하게 파일을 복호화 하기 위해 네트워크 트래픽상에서 툴을 사용할 수 있는 방법과 URL 과 Http Header를 사용하는 방법을 추가했다.
( http://jsunpack.blogspot.com/2009/05/shmoocon-and-presentation-slides-pdf.html )
( http://jsunpack.blogspot.com/2010/02/shmoocon-recap-and-presentation-slides.html )

[ The Jsunpack Website ]
Figure 6-1은 Jsunpack 웹 사이트를 보여주고 있다. ( http://jsunpack.jeek.org/dec/go )
Figure 6-1 : Jsunpack 의 Input과 최근 하위 페이지

Jsunpack 웹 사이트는 다음과 같은 기능을 갖고 있다.
* 여러분이 제공한 URL이나 또는 Web 형태로 붙여 넣은 Encoded JavaScript를 Decode 한다. 
* 또한 Input으로 Packet Capture , PDFs , HTML Files , JavaScript Files을 지원한다.
* Input으로 부터 추출된 파일의 다운로드나 ShellCode를 포함한 Zip File의 다운로드를 지원한다.
* 웹 페이지의 결과 부분에 안전하게 Decoded JavaScript를 보여준다.
* Input에서 공격 가능한 특정 CVE Entry를 탐지하기 위해 YARA 룰을 사용한다. ( YARA에 대해서는 Chapter 3
   에서 소개했다. )
* RSS feed를 제공한다.
* 여러분이 조사중인 공격과 관련된 문자열이나 특징을 검색할 수 있다.

[ Jsunpack-n Command Line Tool ]
Jsunpack-n Command Line Tool은 다음과 같은 기능을 제공한다.
* JavsScript를 Decode 하고 실행하기 위한 SpiderMonkey의 수정된 버전을 제공한다.
* 다중 Input Mode - 인터페이스를 통해 실시간으로 확인할 수 있으며 입출력 트래픽을 스캔하거나 Packet
   Capture 파일을 제공한다.
* 다운로드나 Decode를 위한 URL을 지정하거나 JavaScript Files , Local PDF , HTML을 위한 Decoder를
  제공한다.
* Packet Capture를 통한 다중 Output Mode - HTTP상으로 전달된 모든 파일을 추출해 분리된 파일로 저장
  하고 URL 관계도를 만든다.
* html.py 모듈은 추가적인 Decode가 필요한 HTML 변수를 JavaScript 변수로 변환한다. ( 레시피 6-4 참조 )
* pdf.py 모듈은 PDF 파일에서 JavaScript를 추출한다.
* swf.py 모듈은 SWF 파일에서 JavaScript를 추출한다.
* Decoding 과 Output Parameter를 Options.config내의 Option을 설정함으로 여러분이 수정할 수 있다.
* Exploit을 탐지하기 위해 사용되는 웹 사이트는 YARA 룰을 사용하므로 확장이 용이하다.

[ Jsunpack-n 설치하기 ]
Jsunpack-n 을 설치하기 위해, 다음 코드의 명령어를 이용해 SVN으로 부터 최신 버전을 확인한 후 INSTALL 파일내의 명령어를 이용한다. ( https://code.google.com/p/jsunpack-n/source/checkout )
     $ svn checkout http://jsunpack-n.googlecode.com/svn/trunk/ jsunpack-n
     $ cd ./jsunpack-n

의존적으로 설치하려면 INSTALL 파일을 따른다.
( 역 - Source를 다운받은 폴더내에 INSTALL 파일이 존재한다. 또는 다음의 URL에서 확인할 수 있다.
         https://code.google.com/p/jsunpack-n/source/browse/trunk/INSTALL 
         실제 설치 테스트은 다음의 URL을 참고하기 바란다.:: http://GhostKei.tistory.com/141 )

jsunpack-n은 -h Parameter를 통해 문법을 볼 수 있다.

     $ ./jsunpackn.py -h

< Usage >

레시피에 따라, Jsunpack-n을 다양한 Command을 이용할 수 있다. 

[ NOTE ]
Wepawet ( http://wepawet.cs.ucsb.edu/ )은 악성 JavaScript를 포함된 파일을 분석하기 위해 사용할 수 있는 또 다른 웹 사이트이다. Wepawet는 Exploit을 분석하기 위해 Jsunpack이 수 많은 브라우저의 함수를 사용해 에뮬레이트한 대신에수정된 브라우저를 사용한다.

***** 레시피 6-3 : 복호화 속도 향상을 위한 Jsunpack.-n 옵션과 완결 *****
Heap Spray 기법은 공격자가 그들의 Exploit의 안정성 ( 역 - 공격 성공 확률 ) 을 높이기 위해 사용하는 기법이다. 이 기법에 대한 기반지식은 Alexander Sotirov의 글을 참고하기 바란다. ( http://www.phreedom.org/research/heap-feng-shui/ )

JavaScript에서 사용하는 Heap Spray는 메모리와 시간 집약적이다. Jsunpack-n이 JavaScript를 해석할 때, Script의 동작 시간 제한을 기본적으로 30초로 설정되어 있다. 만약 Script의 필요 동작 시간이 그 보다 더 길경우, Jsunpack-n은 경고를 출력하고 실행을 멈춘다. 이는 Command Shell의 Hang으로 인한 무한 Loop를 예방할 수 있기 때문에 좋은 방법이다. 그러나, 너무 이르게 Heap Spray 동작이 종료될 수 있어서 완벽한 분석을 방해할 수 있다. 
다음의 예는 Jsunpack-n에 -v 옵션을 사용한 것으로 매우 장황한 Output에 대해 설명을 볼 수 있다. 이 옵션은 파일의 악성여부를 시그니쳐 기반으로 판단해 정보를 출력해 주고 Script가 기본 시간을 초과했는지 여부와 같은 각종 정보 알람 및 Decoded 파일 정보를 보여준다. 

< Output >

확인한 것처럼, 악성 PDF내의 JavaScript는 메시지 "Script Analysis Exceeded 30 Seconds"를 통해 시간이 초과되었음을 알려준다. -t TIMEOUT, --timeout=TIMEOUT 옵션을 통해 타임아웃을 변경할 수 있다. 만약 타임 아웃을 늘리면, JavaScript는 더 오랜 시간 실행되고 더욱 완벽한 분석이 가능하게 된다. 예를 들어, Jsunpack-n을 -t 4000 옵션을 사용해 test.pdf 파일을 확인하면, 몇분내에 악성 PDF인지 판단하고 다음과 같은 메시지를 띄워 준다.

     malicious :: shellcode of length 647/259026079

ShellCode의 길이는 두 값을 갖는다. : 647과 259026079. 첫번째 값은 ShellCode중 647Bytes는 반복되지 않는 문자열을 의미하므로 NOP sled 부분은 아니다. 두번째 값은 훨씬 큰 값을 갖는데 이는 NOP sled 동작을 포함하고 있기 때문이다. 이 경우, 사이즈 ( 247MB )가 처리가 오래 걸리는 이유가 될 수 있다. 이러한 문제에 대한 해결 방법은 -f 옵션을 사용하면 된다. 이 옵션은 네게 ShellCode 처리 제한 시간등 다양한 퍼포먼스 옵션을 제공해 준다. 


***** 레시피 6-4 : 브라우저 DOM Elements 에뮬레이팅을 통한 Exploit 실행시키기 *****
SpiderMonkey Engine은 HTML을 처리할 수 없다. 오직 JavsScript만 Parsing 하고 실행시킬 수 있다. 그러므로, HTML 페이지에서 (또는 PDF , SWF , 그외에서 ) JavaScript를 보게되면 SpiderMonkey로 해석하기 전에 별도의 파일로 추출해야만 한다. 아래의 예는 위에서 설명한 부분을 간략하게 설명한 예제이다. JavsScript가 HTML 태그내에 있기 때문에 첫번째 파일을 SpiderMonkey는 해석할 수 없다.

     $ cat with_html.js
     < html >
     <script> print("hello"); </script>
     </html>

     $ js with_html.js
     $


두번째 파일의 경우 순수하게 JavaScript로 이뤄진 파일이므로 SpiderMonkey를 사용하는데 아무런 문제가 없다.

     $ cat no_html.js
     print("hello");
     $ js no_html.js
     hello


우리가 논의하고 이슈는 초당 SpiderMonkey의 제한이 없다. 하지만 SpiderMonkey는 JavaScript 해석기이지 HTML을 해석하지는 않는다. 그러므로 결과적으로, SpiderMonkey에 전달하는 파일내에 HTML 코드를 포함할 수 없다. 이는 항상 문제가 되는 건 아니다. 그러나 공격자는 이점을 공략할 것이다. 예를 들어, HTML내의 JavaScript Code는 DOM ( Document Object Model )이다. 그러므로, JavaScript는 document.title로 접근해 페이지 타이틀과 같은 페이지내의 모든 HTML 코드에 접근할 수 있다. 하위 예는 이론적인 예를 간략하게 표현할 것이다. 즉, JavaScript에서 document.title를 참조하고 eval을 통해 문자열을 복호화할 수도 있다.

     < html >
     < head >
     < title >MyEncrypi0nK3y< /title >
     < /head >
     < script >
          function decrypt(key , input) {
               var output = " ";
               // decryption code here
               return output;
          }
          eval( decrypt(document.title, "258ff2c006e9bd6[REMOVED]") );
     < /script >
     < /html >


만약 복호화된 JavaScript Code를 보고자 한다면, eval을 print로 변경하면 된다. ( 이전 레시피 6-1에서 설명했다. ) 그리고 SpiderMoneky로 분석하면 된다.

     $ cat test.js
     eval = print;
     function decrypt(key , input) {
          var = " " ;
          // decryption code here
          return output;
     }

     eval( decrypt( document.title , "258ff2c006e9bd6[REMOVED]") );
 
     $ js test.js
     test.js:7: ReferenceError: document is not defined


 예상한 것처럼, 참조 Error를 반환한다. 왜냐하면, Document Object는 SpiderMonkey의 Context에 정의되어 있지 않기 때문이다. Document Object는 오직 브라우저의 Context내에서 실행되는 JavaScript 에서만 접근할 수 있다. 또한 MyEncypti0nK3ydocument.title를 대체해 코드를 암호화 할 수 있으며 SpiderMonkey를 통해 동작 시킬수 있다. 그러나, 이건 설명을 위한 동작인 단순한 예제이다. 우리가 원하는 값이 페이지 타이틀과 같이 항상 표시되지는 않는다.

[ Jsunpack-n's HTML Parsing Language ]
Jsunpack-n은 HTML 페이지내의 Contents를 해석하고 JavaScript 변수내의 다른 Element 와 태그 , 타이틀을 
변환한다. HTML 페이지에서 추출한 JavaScript를 해석해 SpiderMonkey의 변수로 자동 전달된다. 그러믈, 만약 JavaScript가 HTML 페이지내의 어떤 변수를 참조한다면, 이용할 수 있다. Jsunpack-n의 htmlparse.config 파일을 수정해 HTML을 해석하도록 설정할 수 있다. 예를 들어, document.title을 정의하기 위해, 다음과 같은 줄을 추가할 수 있다.

     !define TITLE     document.title = String(%s);
     !parse  title     * TITLE:contents


Content내에서 HTML 파일을 발견하면,

     < title > MyEncryi0nK3y < /title >

다음과 같은 JavaScript 변수를 생성한다.

     document.title = String("MyEncrypi0nK3y");

htmlparse.config의 기본적인 룰은 수 많은 HTML 필드에서 공격자가 일반적으로 사용하는 JavaScript를 추출했다. 만약 JavaScript가 htmlparse.config 파일에 없었던 방식이라면 단지 새로운 룰을 추가하기만 하면 된다.
이제 실제 악성코드를 실행할 수 있는 유사 시나리오에 대해 생각해 보자. 우린 Encoded JavaScript를 포함하고 있는 HTML 페이지를 발견했다. ( fetch_bd29f.html ) :

     < html >
     < head >
     < Script >
          function f_E() {
               [REMOVED]
               var __V_n_ = document.getElementById("__V_n_").value;
               [REMOVED]

               if ( okdRVC == 0 ) {
                    for( var eOL=0 ; eOL < __V_n_.length / 2 ; ++eOL ) {
                         var PHcj = parseInt(__V_n_.substr( eOL*2 , 2) , zpu) - (eOL+2) * shj[eOL % 4];
                         if(PHcj < 0 ) {
                              PHcj -= Mox_u[SecCJyg](PHcj / JY_rE) * JY_rE;
                         }
                         NCXs += yflAp[SyFt](PHcj);
                    }
                    _niTm[Jjt](NCXs);
               }
               [REMOVED]
          } 

     < /Script >
     < /head >
     < body onload = "f_E();" >
     < input class="f_i_" type="hidden" id="__V_n_" value="a2decb737683e0[REMOVED]">
     < /body >
     < /html >

 
코드는 document.getElementById 를 호출하고 ID __V_n_ 와 함께 HTML 태그의 값을 반환한다. 그 값은 추가적으로 실행하기 위한 JavaScript의 상태를 확인하기 위해 사용된다. SpiderMonkey를 이용한 JavaScript 해석은 우리가 이전에 보았던 것과 같은 참조 Error를 발생시킨다. 그러나, Jsunpack-n의 htmlparse.config는 모든 HTML 태그를 JavaScript 변수로 변환해 접근할 수 잇게 한다. 

     !parse     *   id, value          headerIDVAL:id,value,contents

이 룰은 기본적으로 htmlparse.config 파일에 존재한다. 만약 이를 확인하기 위해 그것을 비활성화 시키면,  다음과 같은 것을 보게된다.

     $ ./Jsunpackn.py fetch_bd29f.html -V
     [nothing detected] fetch_bd29f.html
               info : [meta refresh] URL=fetch_bd29ffhysgcjfg.php
               info : [decodingLevel=0] found JavaScript
               error : undifined variable __V_n_


해당 룰을 활성화하면, Decode 결과의 큰 차이점을 확인할 수 있다.

     $ ./Jsunpackn.py fetch_bd29f.html -V
     [nothing detected] fetch_bd29f.html
               info : [meta refresh] URL=fetch_bd29fhysgcjfg.php
               info : [decodingLevel=0] found JavaScript
               error : undefined variable Pdf1
               error : undefined function Pdf1.GetVersions
               info : DecodedGenericCLSID detected VA8A9780-280D-11CF-A24D-_
               info : DecodedIframe detected
               info : [iframe] fetch_bd29f./yo_ee_r/slkoeg.pdf
               info : [decodingLevel=1] found JavaScript
               file : decoding_a72e3[REMOVED] : 807 Bytes


숨겨진 부분은, Jsunpack-n은 HTML을 해석하고 __V_n_ 으로 부터 JavaScript 변수를 생성한다. 이는 이는 악성 JavaScript의 의존성을 만족시키고 완벽하게 실행할 수 있게 한다. 여러분이 널리 확인되었지만 실행되지 않는 "stubborn" JavaScript가 눈에 띄면, 브라우저의 DOM Element에 의존하는지 확인해 봐야 한다. 만약 그것을 발견하면, 이러한 타입을 처리하기 위해 Jsunpack-n 을 설정하는 방법을 알야아 한다. 


Analysing PDF Documents
PDF 문서는 다수의 Object와 Directory 구조체 Set으로 이루어져 있다. 이러한 구조화된 정보는 메타 데이터, Directory 정보와 관련된 PDF의 사양 및 버전으로 구성되어 있다. 이는 이미지, 폰트, 텍스트, 포멧, 스크립트 및 
문서가 출력해야하는 모든 컨텐츠를 의미한다. 2008년 7월, Adobe는 공개 표준으로써 PDF의 전체 상세 기술서를 
공개했으므로 원한다면 깊이 있게 살펴볼 수 있다. ( http://www.adobe.com/devnet/pdf/pdf_reference.html )

PDF 분석에 있어서 가장 중요한 개념은 PDF내에 내장된 Object의 타입이다. 각 Object는 Object Number, Version Number 그리고 문자열 Obj로 시작한다. Object는 Object의 Contents나 다른 Object를 참조하는 Tag들로 이루어져
있다. 이러한 Object는 Carriage Return과 문자열 endobj로 끝난다. 

PDF 파일을 파싱할 때, Object의 Content를 추출하기 위해 정규 표현식을 사용할 수 있다.  ( 레시피 6-5 참조 ) pdf.py의 Python Code는 Object Number, Version Numbers와 모든 Object의 Contents를 추출한다. 
해당 Python Code는 PDF 파일의 Content는 이미 Self.indata 변수에 로드 되었다고 가정한다. 모든 Object를 수집한 후 각 Object를 Scan해 관련 데이터를 처리한다.

< 샘플 코드 >

불행히도, Object의 Content가 항상 Plain-Text로 읽기 편한 것은 아니다. Adobe 문서는 압축( Compress ), 암호화( Encode ), 수정등의 여러 종류의 Filter를 사용한다. 그러므로 Object의 Data를 추출한 후, 분석하기 전에 압축 해제( DeCompress ) , 복호화 ( Decode )를 해야한다. 다음의 레시피는 이러한 종류의 작업을 도와줄 수 있는 여러가지 툴을 설명한다.

***** 레시피 6-5 : pdf.py를 이용해 PDF 파일내의 javaScript 추찰하기 *****

Adobe Reader는 PDF 파일내의 JavaScript를 찾기 위해 수정된 버전의 SpiderMonkey를 사용한다. PDF 파일내의 JavaScript는 IDS와 분석가를 피하기 위해 압축되어 있기도 한다. 이 레시피에서는 자동으로 압축 해제 후 JavaScript를 추출하기 위해 Jsunpack-n의 pdf.py 모듈의 사용법을 보여준다.

만약 이미 레시피 6-2에서 Jsunpack-n의 SVN을 다운받았다면, ./jsunpack-n/pdf.py에서 Command-Line Script를 볼 수 있을 것이다. pdf.py를 위한 필수 조건은 ( Install 파일내에 기록되어 있다. ) BeautifulSoup와 PyCrypto 이다. 이들을 Ubuntu에 설치한 후 아래의 Command를 따라하기 바란다. ::

$ sudo apt-get install python-beautifulsoup python-srypto

[ 문자열 압축 해제하기 ]
이전에 언급한 것처럼, PDF Object내의 Data를 압축하기 위한 많은 방법이
있다. 그림 6-2는 Hex Editor로 FlatDecode ( zlib ) 문자열을 포함한
PDF를 보는 방법이다. 하이라이트된 바이트들은 암축된 Data의 시작을 의미한다.


< Figure 6-2 : Hex Editor에 로드된 PDF내의 압축된 Data >

pdf.py script는 압축 해제된 모든 JavaScript를 포함한 Output 파일을 만든다.
이 PDF 추출 프로그램은 FlateDecode(zlib), ASCIIHexDecode, ASCII85Decode, LZWDecode
와 RunLengthDecode등의 PDF 필터를 통해 압축 해제 처리를 하도록 다양한 파이썬
라이브러리를 사용한다. 아래의 코드는 pdf.py가 압축된 데이터를 압축 해제된 데이터로
변환하는 과정을 보여준다. pdf.py 파일을 확인하면 전체 알고리즘을 볼 수 있을 것이다.

< 샘플 코드 >

Samples 디렉토리는 Jsunpack-n 과 함께 테스트할 수 있는 다양한 파일이 포함되어 있다. 아래의 Output은
Samples 디렉토리내의 PDF 파일을 대상으로 pdf.py을 실행시킨 결과이다.

< 샘플 코드 >

보는 바와 같이, Input 파일이 어떤 JavaScript를 포함하고 있다면 ( 압축 여부에 상관없이 ), pdf.py는 파일로 부터 분리해 낼 것이다. 만약 Output 파일을 확인한다면, PDF 파일내의 비정상적인 JavaScript를 확인할 수 있을 것이다.

< 샘플 코드 >

이 부분에서, 위의 샘플코드내의 Comment // jsunpack End PDF headers 가 pdf.py에 의해 추가되어 있다. 
Comment 아래의 모든 JavaScript는 원본 파일로 부터 추출했다. 왜 Output 파일에 pdf.py는 JavaScript를 추가했을까? ( 특히, info.Creator 문자열 ) 이것은 pdf.py의 특징 중 하나로 매우 강력한 기능이다. PDF를 파싱하는 과정에서, Script는 /Creator 태그를 갖는 Object를 발견한 것이다. 일반적으로 Object의 타입은 PDF 생성자가 구분하기 위해 문자열을 포함하고 있다. 하지만 이 경우엔, 공격자가 암호화된 JavaScript 명령어들을 저장하기 위해 사용하였다. "첫 번째" JavaScript 실행시, PDF의 info.creator 문자열에 접근해 명령어를 변환하고 eval 로 전달한다. 

질문 다시 상기해 보면 - 왜 pdf.py는 Output 파일에 info.creator을 추가했을까? 그 이유는 만약 SpiderMonkey와 같은 툴을 이용해 처음으로 JavaScript를 실행하면, info.creator 을 실행하지 않고, 두번째 실행시엔 시도조차 하지 않기 때문이다. pdf.py Script는 PDF내에서 /Creator 태그를 확인했고 임의의 내부 JavaScript가 접근을 시도할 것이라고 가정해 Output 파일에 그것을 추가하는 것이다. 만약 레시피 6-4를 읽었다면, 브라우저 밖에서
동작하는 JavaScript에 접근할 수 있는 HTML 변수를 생성하는 방법을 알 수 있고 이는 매우 익숙할 것이다.

[ JS Hook을 사용해 CVEs 탐지하기 ]
이제 SpiderMonkey를 이용해 Output 파일을 실행할 수 있을 것이다. 다음 예제는 레시피 6-1에서 언급한 것과는 약간 다른 SpiderMonkey 사용법이다. 특별히 우린 같은 Context에서 여러 파일을 처리하기 위해 -f 옵션을 사용할 것이다. 실행할 첫번째 파일은 pre.js 로 ( Jsunpack-n 소스 코드에 포함되어 있다. ) JavaScript 함수를 Hook 하기 위한 특별히 정의 셋을 포함하고 있다. SpideMonkey를 실행하기 전에 Script 맨 처름에 eval=print;
를 추가하는 대신, pre.js를 추가하고 -f pre.js 명령을 내린다. 그러나 pre.js의 진정한 이점은 취약한 JavsScript 함수를 재정의해 취약한 함수가 호출될 때 특정 동작을 수행시킬 수 있다는 점이다. 다음은 pre.js의 코드중 일부로 util.printf와 util.printd 를 Hook 했다. ::

< 샘플 소스 >

Hook 의 결과 경고창을 보여주고 CVE를 알려주며, print 함수로 전달된 Parameter의 길이를 알려준다. pdf-thisCreator.file.out 을 계속 분석해 보면, 발견할 수 있다. ::

$ js -f pre.js -f samples/pdf-thisCreator.file.out | indent

< 샘플 코드 >

즉, 여러분은 압축된 JavaScript가 Heap-Spray Code를 갖고 있음을 알 수 있다. pre.js 내의 Hook과 정의를 사용해, JavaScript가 Adobe Reader의 util.printf 함수를 공격하는 것을 확인할 수 있다. 추가 사항은 레시피 6-8에서 언급하겠다. 만약 false positives ( 오진 )을 보고, 경고창이 발생하기 이전의 util.printf로 전달되는 Parameter의 길이를 확인하기 원한다면, 목적에 맞게 pre.js의 룰만 수정하면 된다. 만약 이 룰때문에 악성으로 진단된 현재까지의 파일 목록을 보길 원한다면, 다음 URL을 확인해 보기 바란다.

[ NOTE ]
PDF 내의 압축 해제된 문자열을 위한 다른 툴로는 pdftk가 있다. http://www.accesspdf.com/pdftk 에서 Linux용이나 WIndows용을 다운받을 수 있으며 또는 Ubuntu에서 apt-get install pdftk명령을 통해 설치할 수 있다.
그러나 pdftk는 JavaScript 복호화나 악성 Content 스캐닝과 같은 추가적인 분석은 수행하지 않는다.

***** 레시피 6-6 : PDF 소프트웨어 버전을 속여 Exploit을 동작시키기 *****

문서를 분석하는데 있어서 어려운 점 중 하나는 Exploit이 동작하는 상태를 알 수 없다는 점이다. 예를 들어, 악성 PDF는 종종 PDF를 열려고 하는 Adobe Reader의 Version을 확인하는 JavaScript Code를 갖고 있다. 만약 잠재적인 피해자가 취약하지 않는 Version의 Adobe Reader를 통해 PDF을 열면, JavaScript는 공격을 시도하지 않는다. 이는 테스트 머신에서 PDF를 실행해 PDF 동작( 즉, 파일 생성, 네트워크 트래픽등 )을 분석하려는 조사자들 때문이다. 만약 PDF가 목표로 하는 Adobe Reader의 정확한 Version을 사용하지 않는다면, PDF는 악성 동작을 하지 않을 것이다.

이 레시피 6-6에서 여러분은 위에서 설명한 이슈를 우해하기 위해 Brute-Force 와 유사한 방식으로 Jsunpack-n을 사용하는 방법을 확인할 것이다. 목표는 타겟으로 하는 Adobe Reader Version에서 실행되는 것으로 JavaScript Code를 속이는데 있다. 이 개념을 증명하기 위해, 우린 Jsunpack-n을 이용해 samples/pdf-versionDetection.file 에서 JavaScript를 추출할 것이다. 아래의 코드는 app.viewerVersion의 값에 따라 다른 동작을 한다.

< 샘플코드 >

ppp( ) 함수는 ( 샘플코드에는 없지만 ) 공격을 준비하기 위해 unescape( )를 사용해 ShellCode의 버퍼를 생성한다. 보는 바와 같이, Adobe Reader의 Version에 따라 세가지 동작 상태가 있다.

* 상태 1 :: Adobe Reader의 Version이 7.2 이상, 8.103 이하인 경우.
               이 경우, 코드는 ppp( ) 를 호출하고 Collab.getIcon( )을 실행하기 위해 eval( )을 사용한다. 
* 상태 2 :: Adobe Reader의 Version이 8.2 이상, 9.103 이하인 경우.
               이 경우, 코드는 ShellCode 버퍼를 생성하기 위해 ppp( )를 호출하지만 동작하지 않는다.
* 상태 3 :: Adobe Reader의 Version이 어떠한 것도 충족되지 않을 경우.
               이 경우, 코드는 어떠한 동작도 하지 않은채 종료된다.

PDF를 분석하기 위해 Jsunpack-n 을 사용하면, fasteval 모드를 활성화하기 위해 -f 플래그를 사용하기 바란다.이는 공격에 필요한 조건을 만들기 위해 사용되는 트릭을 줄이므로써 성능을 향상시킨다. Jsunpackn.py 내의 코드는 fasteval 모드의 성능을 증명한다. 만약 -f 플래그를 지정하면, Adobe Reader 9.1와 Blank Version의 Context에서만 JavaScript가 실행된다. Blank Version 문자열은 wildcard로 사용되어 Version을 비교하거나 확인하기 위해 공격자에 의해 사용된다. 만약 -f ( 기본값 ) 플래그를 설정하지 않으면, Jsunpack-n은 Adobe Reader 7.0 , 8.0 , 9.1 와 Blank Version에서 동작하도록 할 것이다.

< 샘플 코드 >

pdfversion 목록에서 각각의 Version에 대해, Jsunpack-n은 app.viewerVersion=9.1 과 같은 환경 변수를 생성해 악성 JavaScript를 확인할 때 SpiderMonkey로 전달한다. 레시피 6-1에서 print( )와 eval( )을 오버라이드 하기 위해 유사한 기법을 사용한다. fasteval 모드에서, 다음과 같은 결과를 볼 수 있다.

< 결과 >

Junpack-n은 PDF로 부터 JavaScript를 추출했지만 JavaScript가 어떤 취약점을 공격하는지 확인하기는 어렵다. 이는 fasteval 모드에서, Adobe Reader Version은 목록중 오직 상태 #2만 만족하기 때문이다. 그러므로 ShellCode 버퍼는 생성은 되지만 사용하지는 않는다. 기본 모드에서, 4가지의 Adobe Reader Version에 대해 다음과 같은 결과를 볼 수 있다.

< 결과 >

이 경우, app.viewerVersion=8.0으로 설정하면 Jsunpack-n은 목록중 상태 #1을 동작시킬 수 있다. 그러므로, ShellCode 버퍼가 생성되고 CVE-2009-0927인 Collab.getIcon( )을 호출한다. 앞으로 Adobe Reader의 신규 버전이 출시되고 공격자가 해당 버전의 취약점을 타겟으로 하기 시작하면, 다음과 같이 Jsunpack-n의 목록에 추가하면 된다.

pdfversion = [ '','9.1','9.6','10.5','12.109' ]

여러분은 다른 환경 변수를 속이기 위해 Jsunpack-n을 사용할 수 있다. 일반적으로 특정 OS, 특정 Version의 브라우저, 특정 사용자의 브라우저, 심지어 특정 언어로 설정되어 있는 브라우저 만을 타겟으로 하는 공격자를 보았을 것이다. 이 경우, 다음과 같은 Jsunpackn.py 소스 코드내의 문자열을 찾아 여러분이 테스트하려는 parameter로 변경하기 위해 다른 값을 추가하는 방법을 확인할 수 있을 것이다.

* navigator.appCodeName
* navigator.appVersion
* navigator.userAgent
* navigator.systemLanguage
* navigator.browserLanguage

***** 레시피 6-7 : Didier Stevens의 PDF Tool 활용하기 *****

Didier Stevens는 PDF로 부터 악성 Content를 추출하고 분석하기 위한 여러 유용한 툴을 만들었다. 이번 레시피에서 레시피 6-5에서 사용했던 동일한 악성 PDF를 테스트할 것이다. 그러나 Didier의 툴중 pdfid.py와 pdf-parser.py 만을 사용할 것이다. 

[ Exploring PDF Tags ]
pdfid.py를 사용하면 PDF 파일로 부터 모든 Tag의 타입과 수를 출력할 수 있다. 이는 파일이 다른 데이터 타입을 숨기고 있는지 여부를 확인할 수 있다. 사실, VirusTotal은 스캐닝 결과 페이지의 여분의 정보 섹션에 pdfid.py의 Output을 보여준다.  다음의 Output은 파일이 포함하고 있는 내부 압축 문자열과 JavaScript Object를 보여준다. Lenny Zeltser의 "악성 문서 분석 Cheat Sheet"에 잠재적인 위협 가능성이 있는 Tag 목록이 포함되어 있다.

< 샘플 Output >

[ Following Object References ]
JavaScript Object가 파일에 포함되어 있다는 사실을 알았다면, 관련된 Object IDs를 찾아낼 수 있어야 한다.
이 작업을 위해, pdf-parser.py에 Paramter --search=javascript 를 추가한다.

< 샘플 테스트 >

Output을 기준으로 Object ID는 3과 6이다. 그러나 이 Object 둘다 JavaScript Code를 갖고 있다. 더욱이, Object 3과 Object 6과의 관계 또한 명확하지 않다. 그러므로 (Object 3과 6은) 퍼즐의 한 조간으로 함께 두고 생각해야 한다. ( 파일 시스템에서 심볼릭 링크처럼 ) Object 3과 6 모두 다른 Object를 참조하지만 그들이 참조하는 Object는 Output에는 없다. 특히, Object 3는 Object 5를 참조하고 있다. Object 6은 Object 111611을 참조하고 있다. Object 3이 참조하고 있는 Object의 Content를 Dump 하기 위해서 pdf-parser.py를 다음과 같이 사용한다.

< 샘플 테스트 >

이제 여러 Object 사이의 관계를 알 수 있다. Object 3은 Object 5를 참조하고 Object 5는 Object 6을, Object 6은 Object 111611을 참조한다. ( 참조하는 Object 숫자가 반드시 순서대로 나열되지 않아도 된다. ) Object 111611을 출력해 보면, 어떤 다른 Object도 참조하지 않고 있음을 알 수 있다. 즉, "end of the line" 임을 의미한다. 아래의 명령처럼, Object 111611은 zlib로 암축된 142Bytes의 데이터를 갖는다. ( /FlateDecode 로 알 수 있다. ) 옵션 -f를 통해, Content를 자동으로 복호화 할 수 있다.

< 샘플 테스트 >

이런 과정을 거쳐 JavaScript를 확인할 수 있다. 공격자가 분석을 어렵게 하기 위해 사용한 여러 단계는 우회는 매우 흥미롭다. 만약 여러분이 pdf-parser.py를 이용해 전체 파일에서 관련 문자열을 Dump하고자 한다면, 옵션 -f와 함께 옵션 -o를 사용하면 한번에 모든 문자열을 추출해 검사할 수 있다.

[ NOTE ]
PDFMiner는 ( 악성코드 분석만을 위한 것이 아닌 ) 일반적으로 PDF Content를 추출하고 분석하기 위해 사용되는 프로그램 Suite 이다.  PDFMiner를 library로써 사용해 새로운 툴을 만들 수도 있다.

***** 레시피 6-8 : PDF 파일을 공격하는 취약점 확인 *****

PDF 파일에서 JavaScript를 추출해 복호화 했다면, 어떤 취약점을 위한 것인지 알고 싶을 것이다. 이는 위협 평가에 유용하다. 왜냐하면, 만약 PDF가 특정 시스템에 접근할 수 있다면, Adobe Reader의 Version을 제공할 수 있기 때문이다. 표 6-1은 가장 널리 확산된 PDF Exploit을 보여주고 있다. 표 가로 부분의 취약한 위치 ( Vulnerable Condition )는 의심 파일을 분석할 때 확인할 수 있다.

< 표 6-1 : PDF 취약점 >
===================================================================================================
CVE                                        취약한 위치                          설명
---------------------------------------------------------------------------------------------------
CVE-2007-5659                        Collab.CollectEmailInfo( )        Collab.EmailInfo( ) 함수의 Parameter                                                                                                  Parsing 과정에서 발생하는 JavaScript
                                                                                         Engine내의 Stack 버퍼 오버플로우
---------------------------------------------------------------------------------------------------
CVE-2008-2992                        util.printf( )                            JavaScript 함수 util.printf( )내의 Stack 버퍼
                                                                                        오버 플로우
---------------------------------------------------------------------------------------------------
CVE-2009-0927                        Collab.getIcon( )                    Collab.getIcon( ) 함수의 Parameter Parsing
                                                                                         과정에서 발생하는 JavaScript Engine내의
                                                                                         버퍼 오버플로우
---------------------------------------------------------------------------------------------------
CVE-2009-1492                        getAnnots( )                          getAnnots( ) 함수에서 Parameter Parsing
                                                                                         과정에서 발생하는 JavaScript Engine내의
                                                                                         버퍼 오버 플로우
---------------------------------------------------------------------------------------------------
CVE-2009-0658                        JBIG2                                    JBIG2 Image 문자열 Parsing 과정에서 발생
                                                                                         하는 버퍼 오버 플로우
---------------------------------------------------------------------------------------------------
CVE-2009-1862                        Adobe Flash                          authplay.dll 의 메모리 문제로 인한 취약점
CVE-2010-1297
---------------------------------------------------------------------------------------------------
CVE-2009-2990                        U3D                                     U3DCLODProgressiveMeshContinuation
                                                                                        Blocks을 Parsing 할 때 잘못된 Index 참조
                                                                                        로 인해 발생하는 문제
---------------------------------------------------------------------------------------------------
CVE-2009-3459                        Colors                                 FlateDecode Colors Parameter를 Parsing
                                                                                       하는 과정에서 발생하는 Integer 오버플로우
---------------------------------------------------------------------------------------------------
CVE-2009-4324                        media.newPlayer( )              JavaScript media.newPlayer( ) 함수에서 
                                                                                       발생하는 Stack 버퍼 오버플로우
---------------------------------------------------------------------------------------------------
CVE-2010-0188                        libTiff                                  AdobeReader의 libTiff 라이브러리내에서 발생
                                                                                      하는 Stack 버퍼 오버 플오우
---------------------------------------------------------------------------------------------------
PDF Launch ( NO CVE )           PDF Launch Action              내부 실행 파일을 실행시키기 위해 사용자에게 
                                                                                      질의하는 형태의 사회 공학적 기법
====================================================================================================

이 부분에서 타겟 취약점이 무엇인지 판단할 때 기억해야 할 점이 있다.

* 대부분, 취약한 부분 또는 함수는 복호화된 JavaScript에서 볼수 있는 함수의 이름이거나 문자열이다. 그러나 
  복호화하더라도, 취약한 함수가 변수로 정의되거나 선택 방식 ( Alternative Methods )에 의해 실행될 경우 확
  인할 수 없을 수도 있다. 예를 들어, 공격자가 동일한 함수를 호출하기 위해 다음과 같은 방법을 사용할 수 있
  다.

   Collab.getIcon(.....);

   Collab["\x67\x68\x74\x49\x63\x6f\x6e"] (.....);

   var a = Collab;  a.getIcon(.....);


* 많은 악성 PDF 파일은 하나 이상의 취약점을 공격한다. 공격자는 (AdobeReader Version을 포함하고 있는)  
  app.viewerVersion 를 확인한다. 만약 취약하지 않는 Version일 경우, 공격자는 다른 취약점을 공격할 수 있
  다.

[ CVE-2007-5659 :: Collab.collectEmailInfo( ) ]
Collab.collectEmailInfo( )는 널리 확산된 가장 일반적인 취약점 중 하나다. 2008년 2월 초, 신규 취약점을 발견한 iDefense의 연구 그룹은 Zonebak Trojan을 설치하기 위해 배너 광고를 통해 공격했다. 해당 취약점을 공격하는 악성 JavaScript Code 일부를 발췌했다.

< JavaScript Code >

해당 취약점은 Adobe 제품이 사용하는 JavaScript Engine을 이용한 최초의 악성 파일이다. iDefense는 Adobe에 의해 Patch가 이뤄지기 전 약 2주동안 취약점이 공격에 이용되었다는 것을 알았다. 이는 악성 코드를 설치하기 위해 JavaScript 취약점을 이용하기 시작했음을 의미한다.

[ CVE-2008-2992 :: util.printf( ) ]
util.printf( ) 함수의 취약점을 Target으로 하는 공격은 취약점을 동작시키기 위해 Heap-Spray 방법을 사용한다.취약점을 공격하기 위해, 공격자는 아래의 코드와 유사한 형태의 Argument를 통해 취약한 함수를 호출한다. 비록 util.printf( )가 정상 PDF 파일에 의해 실행되더라고, 악성 여부를 판단하는 두번째 Parameter를 주의깊게 확인해야 한다. 취약점은 Stack 버퍼 오버플로우이기 때문에 두번째 Parameter가 악성의 경우 비정상적으로 길다. 

< 샘플 코드 >

[ CVE-2009-0927 :: Collab.getIcon( ) ]
해당 취약점은 Collab.getIcon( )에 전달되는 긴 문자열에 의해 취약점을 공격하는 PDF 파일임을 식별할 수 있다. 그 코드는 다음과 같다.

< 샘플 코드 >

Adobe는 2009년 3월 해당 취약점은 Patch되었고 Patch 후 몇주가 지난 2009년 4월에 널리 확산되었다. 그리고특정 일자에 공격하도록 설계된 가장 일반적인 형태가 남아있다. 몇몇 보안 연구가들은 공격자들은 특정 취약점을 공격하기 위해 Patch를 Reverse-Engineer 했다고 추정한다. ZDI에 의해 출판된 취약점에 따르면, Tenable Network Security는 2008년 7월에 발견되었다. 

[ CVE-2009-1492 :: getAnnots( ) ]
해당 취약점을 공격하는 PDF 파일을 탐지하기 위해, 메모리 Corruption을 일으키는 4개의 Parameter를 전달받는 getAnnots( ) 함수를 확인한다.

this.getAnnots( -1023212797, -1023212797, -1023212797, -1023212797);

getAnnots( ) 함수 호출시 위와 같은 Parameter가 없다면 의심스럽다. 왜냐하면, PDF 파일의 다른 섹션으로 부터 Content를 로드하기 위해 사용되는 값이기 때문이다. 즉, JavaScript가 Annot의 Content를 Decode / Decrypt 하면, JavaScript는 eval( )과 같은 함수를 이용해 그것 ( JavaScript )을 실행 시킨다. 

[ CVE-2009-0658 :: JBIG2 ] 
이 공격 코드가 동작하려면, JBIG2Decode Filter를 사용하는 Object를 찾는다. 

<</BitsPerComponent 1/ColorSpace /DeviceGray /Filter /JBIG2Decode /Height 600/Length 4945 /Name
    /X/Subtype/Image/Type/XObject/Width 800 >>


JBIG2 취약점을 Target으로 하는 PDF파일은 Heap-Spray 기법을 사용한다. 그러나, JBIG2 취약점은 혀율성을 위해 JavaScript를 사용하는 것은 아니다. 그림 6-3은 악성 JBIG2 PDF 문서의 예를 보여준다. Object 3는  /OpenAction 태크를 포함하고 있는데 이는 Victim이 PDF 파일을 실행하면 Object 2의 Content를 Object 3가 실행시킨다는 것을 의미한다. Object 2는 8진수로 되어 있는 JavaScript로 되어 있고 Object 7이 로드되기 이전에 프로세스 메모리의 큰 섹션을 채우기 위해 Heap Spray를 이용한다. 

< 그림 6-3 :: JBIG2 취약점을 공격하는 악성 PDF 문서 >

Object 7은 기형의 JBIG2 Image Stream을 갖고 있다. 이 Image Stream은 Heap Spray로 채워진 메모리의 EIP를 나타낸다. 즉, EIP가 ShellCode에 도착하면, Object 7의 나머지를 XOR를 통해 Decode 후 Windows PE 파일을 실행한다.

[ CVE-2009-1862 and CVE-2010-1297 :: Adobe Flash ]
공격자는 PDF내부에 악성 Flash movie ( SWF )를 내장시키기 위해 /EmbeddedFile 이나 /RichMediaActiveation 태그를 사용한다. 이런 경우, 비록 PDF를 통해 전파되지만 Target Application은 Adobe Reader가 아닌 Flash Player다. 다음은 내장된 Flash Movie의 예이다.

< Flash Play 예 >

내장된 Flash Movie를 추출하기 위해, 모든 PDF Filter로 압축을 해제하고, PDF Object의 시작부터 SWF 파일 헤더인 CWS ( 압축된 경우 ) 또는 FWS ( 압축이 해제된 경우 )를 찾는다. 여러분은 이 작업을 위해 Didier Stevens의 pdf-parser.py를 사용하면 된다. 

[ NOTE ]
우리는 이책에서 SWF ( Flash ) 파일 분석을 수행하진 않는다. 그러나, 아래의 리소스를 통해 필요한 기술과 툴을 익힐 수 있다.

* Action Script를 Decompile하고 SWF 파일을 압축 해제하기 위한 툴 :: swfdump , Nemo440 , Action Script
   Viewer
* SecurityTube에서 Flash Malware Video 분석
* Sebastian Porst 와 Frank Boldewin 이 발견한 CVE-2010-1297 의 깊은 분석 정보
* CSI 에피소드 4 : Sergrei Schevchenko 의 인터넷 ( Killer 비디오의 공격 )

[ CVE-2009-2990 :: U3D ]
Universal 3D의 약자인 U3D는 애니메이션에서 사용된다. 악성 PDF 파일내의 U3D Data 문자열 Parsing과정에서의 Exploit을 탐지하기 위해, 아래와 같은 content를 찾으면 된다.

45 0 obj<< /Subtype/U3D/Length 172417/Filter/FlateDecode/VA[]/DV/F/AV
           <</Subtype/Linear/PC -1>>>>stream


일반적으로 U3D를 Exploit하는 악성 파일은 172000 ~ 172500Bytes 사이의 길이값을 사용한다. (이전 Object에서)길이 172417 는 이 범위내에 포함된다. 또한 이 Exploit은 Matasploit 모듈에서 확인할 수 있는 것처럼 JavaScript Heap Spraying 를 사용한다.

[ CVE-2009-3459 :: Colors ]
Exploit의 핵심 구성요소는 /Colors의 Argument로 제공되는 큰 Integer 값이다. Didier Stevens의 pdfid.py 툴은 /Colors 값이 2^24 보다 큰 값인지 확인하는 방식으로 Exploit을 탐지한다.  다음 예를 참고한다.

/Predictor 02 /Colors 1073741828 /BitsPerComponent 1 >>

[ CVE-2009-4324 :: media.newPlayer ]
해당 취약점( CVE-2009-4324 ) Exploit은 다음의 코드에서 보는 것과 같이, media.newPlayer를 호출한다. 이 취약점을 Exploit하기 이전에, Attacker는 JavaScript Heap Spraying을 사용한다.

try {
     this.media.newPlayer ( NULL );
} catch(e) { }
util.printd(
p@1111111111111111111111111 : yyyy111 , new Date() );

[ PDF Launch ( no CVE ) ]
/Launch 태그의 동작은 선택 메시지를 출력하는 형태이기 때문에 해당 태그를 갖는 파일을 위해 no CVE를 할당했다. Adobe Reader의 경우 Command와 함께 /Launch 태그를 포함하고 있으면, "Open" 또는 "Do not open" 의 선택을 사용자에게 보여주며 경고를 한다. CVE-2009-0836은 Foxit에서 동일한 기법을 사용한다. Attacker는 직접적으로 PDF내에부서 실행할 수 있도록 다음과 같이 태그를 사용한다.

     /Type /Action /S /Launch /Win << /F (cmd.exe)

PDF 파일내에 ( /Launch가) 포함되어 있고 사용자가 Open을 선택하면, cmd.exe가 실행된다. 더욱 세부적인 설명과 /Launch 태그를 이용해 Command를 실행하는 PoC 파일은 Didier Stevens 블로그에서 확인할 수 있다.
http://blog.didierstevens.com/2010/03/29/escape-from-pdf )

[ Detecting CVEs with Jsunpack-n ]
Jsunpack-n을 사용해 PDF나 JavaScript를 분석할 때, detection.py는 특정 Signature Set으로 Encoded / Decoded Data를 Scan하기 위해 YARA를 사용한다. 예를 들어 다음의 룰은 CVE-2008-2992를 탐지한다.

     rule Utilprintf : decodedPDF
     {
          meta :
               ref = "CVE-2008-2992"
          strings :
               $cve20082992 = "util.printf" nocase fullword
          condition :
               1 of them
     }


다음의 룰은 CVE-2009-4324 를 탐지한다.

     rule mediaNewplayer : decodedPDF
     {
          meta : 
               ref = "CVE-2009-4324"
          strings : 
               $cve20094324 = "media.newPlayer" nocase fullword
          condition :
               1 of them
     }


Jsunpack-n은 가장 최신의 YARA 룰을 사용하며 이는 Jsunpack-n 소스 코드의 "rules" 파일을 통해 확인할 수 있다.
( http://jsunpack.jeek.org/dec/current_rules )
 
***** 레시피 6-9 : Distorm을 이용한 ShellCode 디스어셈블링 *****

이번 레시피 6-9에서는 악성 PDF 파일로 부터 추출한 ShellCode를 분석하는 방법에 대해 설명한다. 물론, 각 PDF는 ShellCode를 숨기거나 난독화하기 위해 다른 방식을 사용한다. 그래서 이번 레시피에서는 대표적인 데모 샘플을 사용한다. 공격에서 있어서 일관된 부분은 Heap Spray을 위해 JavaScript를 사용했다는 점이다. 여러분은 2007년에 공격하기 위해 날짜를 뒤로 돌리는 아래과 같은 함수를 쉽게 접할 수 있을 것이다.

     function rep(count , what) {
          var v = " " ;
          while ( --count >= 0 ) v += what;
          return v;
      }


위의 rep함수는 what 값을 Count 만큼 반복적으로 갖는 문자열을 생성한다. 이는 ShellCode가 가까이 있다고 알려주는 것이다. 왜냐하면, Attacker는 메모리내에 ShellCode로 가득차게 하기 위해 Pad나 Sled를 위해 이 함수를 사용하기 때문이다. 여러분은 일반적을 Unicode-Encoded Strings과 같은 JavaScript내의 ShellCode를 찾을 수 있거 이는 unescape 함수를 이용해 바이너리 content를 변환한다.

     sc = "%u4341%u4b49%u11eb%u5bfc%u334b%u66c9%ub0b9%u8001%u0b34
             %ue2f9%uebfa%ue805%uffeb%uffff%uf911%uf9f9%ua3f9%u72ac%u7815
             %u9d15%uf9fd%u72f9%u110d%uf869%uf9f9%u0182%u1611%uf9f9%u70f9
             %u06ff%u91cf%u6254%u2684%ued11%uf9f8%u70f9%uf5bf%uvf06%ud091
            [REMOVED]

     bin = unescape( sc );

때때로 Attacker는 ShellCode를 보기 쉽게 만들고 ShellCode나 sc와 같은 의미 있는 변수 명을 사용한다. 그러나 항상 그렇지는 않는다. 아래의 예제는 변수명과 함수명을 하나 이상의 밑줄을 사용해 나타낸 코드이다. 약간의 Comment를 추가해 무슨 동작인지 이해할 수 있을 것이다. 주의할 점은 rep 함수는 암호화된 변수명임에도 불구하고 여전히 알아볼 수 있다.

     // Create the sled
     function rep(_,__) {
          val ___ = " ";
          while ( --_ >= 0 ) ___ += __;
          return ___;
     }

     var ____ = unescapte;
     var _c1 = "\x6c\x65\x6e\x67\x74\x68";
    
     // turn a string of hex bytes into Unicode-Encoded Format
     function _____(__) {
          var _= " ";
          for ( var ___ = 0; ___ < __[_c1]; ___ +=4 )
               _+='%'+'u'+__.substr(___,4);
          return _;
     }

     var sc = ___(____("9090909090909090EB90E1A5B56068A303C167E0C0460426
                                8AE480020F88C44303EB46E8E9FFE1FFFF7466515A70437050
                                707050506B6850644C504B685 [REMOVED] " ));

     // make 128 copies of the sled and shellcod buffers
     _ = rep(128, ___(____("42424242424242424242"))) + sc;


[ DiStorm을 이용한 ShellCode 디스어셈블링 ]
Unicode-Encoded ShellCode를 분석하기 위해, ShellCode를 Binary Format을 변환해야 한다. 이러한 변환 작업은 unescape 가 하는 것이나 Perl이나 Python을 이용해 동일한 동작을 할 수 있다. Perl 이나 Python에서,
%u3AFC와 같은 Character를 \xfc\x3a와 같은 Binary로 변환하기 위해 정규 표현식을 사용한다. 그리고 나서 파일로 데이터를 저장하거나 디스어셈블리와 같은 추가 동작을 수행한다.

아래의 예제는 Python을 이용해 변환하는 방법과 DiStorm을 이용해 디스어셈블하는 방법을 설명한 것이다. DiStorm은 Gil Dabag가 만든 Binary Stream 디스어셈블 툴이다. 시작하기 위해, Linux Machine( Windows와 Mac OS X 에 DiStorm을 설치할 수 있다.  ) 상에 DiStorm을 설치한다.  ::

     $ wget http://ragestorm.net/distrom/distorm64-pkg1.7.30.zip
     $ unzip distorm64-pkg1.7.30.zip
     $ cd distorm64/build/linux
     $ make
     $ bach instpython.sb


이제 Script를 이용해 ShellCode를 Binary로 변환해 Disk상에 Binary Data로 저장 후 (ShellCode.bin) 해당 파일을 Disassembly 한다.

     $ cat sc_distorm.py
< Python 내용 >     


Output 결과물은 각 Instruction의 Offset과 Size , Hex bytes , 니모닉등을 보여준다. Command Line으로 Unicode-Encoded ShellCode 문자열을 전달한다. 다음의 Sample Output 이다. :

< Sample Output >

Disassembly를 통해 하위의 것을 확인할 수 있다.

* Offset 0x4 , JMP Instruction은 0x17로 제어권을 전달한다. 
* Offset 0x17 , Call Instruction은 0x7로 제어권을 전달한다. 이 Call 문이 실행된 후, Return Address ( Offset  
  0x17 )은 Stack의 최상위에 Push된다. 0x1C는 현재 Encoded 되어 있는 두번째 Stage Payload의 위치이다. 
* Offset 0x7 , POP EBX Instruction은 Stack으로 부터 0x1C 값을 제거하고 EBX Register에 저장한다. 
* Offset 0x9 , XOR ECX , ECX Instruction 는 Loop Counter로 사용하기 위해 초기화 한다.
* Offset 0xB , MOV CX , 0x1B0 Instruction은 Loop Counter를 두번째 Stage Payload ( 432Bytes ) 크기로
   설정한다.
* Offset 0xF , 0x13 , XOR 와 LOOP Instruction은 두번째 Stage Payload를 0xF9로 Decode 한다. LOOP
   Instruction은 하나의 Argument를 갖는데 이는 실행하기 위한 주소값이다. Loop Register CX는 0이 될때까지
   실행될 때마다 1씩 감소한다. 
* Offset 0x15 , JMP Instruction은 새롭게 Decode된 두번째 Stage Payload로 제어권을 넘긴다.

Offset 0x1C 이후의 Disassembled Instruction 을 이해하기 위해선 해당 데이터를 다시 XOR해야 한다. 이를 위해, 레시피 12-1의 xortools Library를 사용해 sc_distorm.py Script를 확장한다. 즉, bin_sc 버퍼를 Disassembly 하기 이전 코드에 다음의 코드를 복사하기만 하면 된다. 그것은 두번째 Stage Payload를 확인하기 위해 0xF9로 0x1B0 Bytes 만큼 XOR 하는 것이다.

     from xortools import single_byte_xor
     
     new_sc  = bin_sc[0:0x1c]
     new_sc += single_byte_xor(bin_sc[0x1c:0x1c+0x1b0], 0xf9 )
     bin_sc = new_sc


Decode 후 해당 데이터를 다시 Disassembly 하면, 두번째 Stage Payload를 분석할 수 있다. 비록 0x1C에서 시작하지만, 간략하게 0xC6 Address 이후 부터를 나타내었다. 

< Code >

두번째 Stage ShellCode는 악성 PDF 파일의 Header를 찾기 위해 프로세스의 메모리를 확인한다. 악성 PDF 파일의 Header에서, PdPD 문자열을 갖고 있는 세번째 Stage ShellCode의 시작 지점을 찾는다. 해당 문자열부터 0x600 Bytes 만큼을 키 0xeffefeee 으로 XOR을 통해 Decode 한다. 그 후 제어권을 Decode 지점으로 전달한다.지막 Stage ShellCode ( 여기서 확인할 수는 없지만 ) 는 공격을 위한 실행파일을 Drop 후 실행시킨다.

[ NOTE ]
Unicode Character를 사용하는 것외에도 ShellCode를 Encode 하는 방법은 다양하다. Alain Rioux는 ConvertShellCode 라는 툴을 만들었다. ( 해당 툴의 다운로드 및 추가 정보는 Lenny Zeltser의 웹 사이트 :: 
http://zeltser.com/reverse-malware/convert-shellcode.html 을 참고하기 바란다. ) 해당 툴은 다음과 같은
포멧을 처리할 수 있다.

* \x90\x90\x90
* %u9090%u9090
* %90%90%90%90
* \u9090\u9090
* &#x9090&#x9090

다른 ShellCode와 데이터 타입을 변환할 수 있는 툴은 Malzilla 가 있다. ( http://malzilla.sourceforge.net/ ).
Malzilla는 Windows GUI 툴이지만 Wine과 Linux에서도 사용할 수 있다.

***** 레시피 6-10 : LIBEMU를 이용한 ShellCode Emulating *****

ShellCode를 Static하게 분석하는 대신에, libemu 에뮬레이션 Library를 이용할 수 있다. 에뮬레이션은 여러분의 시스템을 감염시킬 수 있는 위험이 없는 API 함수 프로그램을 통해 가능성 여부를 확인할 수 있다. ( 사실, Linux에서 Windows ShellCode를 에뮬레이트 할 수도 있다. ) 다음의 방식을 통해 libemu를 설치한다. :

     $ git clone http://git.carnivore.it/libemu.git libemu
     $ cd libemu
     $ sudo apt-get install autoconf libtool
     $ autoreconf -v -i
     $ ./configure --prefix=/opy/libemu --enable-python-bindings --enable-debug
     $ sudo make install


정확하게 동작하며, 여러분이 레시피 6-9에서 sctest 명령어로 생성한 ShellCode.bin 파일을 분석할 수 있게 된다. sctest 의 Output은 모든 실행가능한 명령어와 실행 후 CPU Register의 상태를 포함하고 있다. 다음의 예는
( -vvv 를 추가해 ) 다변성 ( Verbosity )을 세 단계 향상 시켰다. 

     $ /opt/libemu/bin/sctest -Ss 1000000000 -vvv < shellcode.bin

< Code >

Output에서는 오로지 sctest가 실제로 출력한 부분만을 보여준다. - 간략하게 5 Instruction 만 보여준다. 만약 레시피 6-9를 읽었다면, 5 Instruction이 두번째 Stage Payload을 보여주기 위해 XOR을 사용하는 Decoding Loop임을 알 수 있을 것이다. EIP 값은 각 Instruction 의 Virtual Address (VA)을 나타낸다. 첫번째 Instruction의 VA ( XOR ECX , ECX )는 0x00417009로 ShellCode File Offset 0x9에 해당한다. 주의 깊게 확인해야 할 부분은 ECX Register가 시작시 0으로 초기화되는 방법과 그 후 처 XOP 연산 이전에 0x1B0로 변하는 부분, 그리고 나서 두번재 XOR Instruction전에 0x1AF로 감소하는 부분이다. 이 부분은 각 반복 후 자동으로 ECX가 감소하는 Loop Instruction의 효과이다.

여러분이 확인한 것처럼, libemu를 통한 Output은 Static Disassembly과는 매우 다르다. 왜냐하면, 각 Instruction 이후 Register의 내용을 확인할 수 있기 때문이다. libemu의 다른 기능은 ShellCode가 호출한 API의 Log를 만들어 준다는 점이다. 다음은 이 기능의  예이다.

     $ /opt/libemu/bin/sctest -Ss 1000000000 < ShellCode_7da73f

< log >

에뮬레이터의 Output은 LoadLibraryA , GetSystemDirectory, URLDownloadToFile 마지막으로 WinExec를 호출했음을 보여준다. 여러분은 sctest 명령어를 약간 바꿔 ShellCode의 .dot 확장자의실행 그래프를 만들 수도 있다. 단지 Paramter -G만을 추가해 다음과 같이 설치되어 있는 Graphviz를 얻을 수 있다. 

     $ /opt/libemu/bin/sctest -Ss 100000000 -G graph.dot < shellcode.7da73f
     $ dot -T png -o graph.png graph.dot


이제 graph.png로 명명된 PNG Image를 열어서 ShellCode를 그림으로 확인해 보자. Figure 6-4는 예를 보여준다.

< Figure 6-4. Graphing the flow of instructions and calls in shellcode >



Analyzing Malicious Office Documents
일반적으로 Attacker는 개인이나 조직을 대상으로 공격하기 위해 악성 Office 문서를 사용한다. 비록 대부분의 일반적인 컴퓨터 사용자들은 E-mail등을 통해 받은 실행파일들은 열어보지 않지만, Word 문서나 Excel 문서 또는 PowerPoint 등을 열어보는 것에 대해서는 두번 생각하지 않는다. 다음의 레시피는 MS Office Files을 분석하는데 도움이 될만한 툴과 기술에 대해서 설명할 것이다.

***** 레시피 6-11 : OfficeMalScanner를 통해 MS Office 파일 분석하기 *****
Frank Boldewin의 OfficeMalScanner는 Command-Line 툴로 MS Office 문서에서 악성 코드를 탐지하기 위한 툴이다. Windows에서 실행하는 프로그램이지만 Linux의 Wine ( 레시피 3-7 참조 )에서도 동작한다. 이 레시피 6-11에서, 우리는 OfficeMalScanner 의 사용법과 Word , PowerPoint , Excel 문서에 있는 Exploit을 확인하는 방법에 대해 살펴볼 것이다.

[ OfficeMalScanner Modes ]
OfficeMalScanner를 보면, 요구 모드나 정보의 레벨을 지정할 수 있다. 아래의 목록은 가능한 모드를 요약한 것이다.

* Scan :: 입력한 파일로 부터 Generic ShellCode Patterns를 Scan한다.

* Brute :: 입력한 파일의 Content를 Decode 하기위해 0x00 ~ 0xFF 를 XOR ADD로 복호화를 시도한다.
              각 부분에서 복호화가 완료되면, OfficeMalScanner는 내부에 OLE Signature와 PE 파일이 있는지
              확인한다. 만약 어떤 부분이 확인된다면, 자동으로 해당 부분을 별도의 파일로 저장한다.

* Debug :: ShellCode를 Disassembly 후 출력하거나 문자열 , OLE Data , PE 파일등을 Hex Dump 한다.

* Info :: 파일내에서 OLE 구조체 , Offset , 길이값을 찾아 출력하고 Disk에서 Visual Basic Macro를 추출한다.

* Inflate :: Office 2007 문서 ( 즉, .docx  확장자 )의 Content를 임의의 디렉토리에 압축 해제 한다.

[ Scanning Patterns and Signatures ]
다음은 ShellCode Pattern 목록과 Scan 모드에서 탐지할 수 있는 다른 Signature 목록이다.

* Locating EIP ( 4가지 방식 존재 ) :: 명령어 순서는 EIP를 찾기 위한 방법을 나타낸다. ShellCode는 메모
                                리에 로드되면 문자열이나 두번째 Stage Payload를 찾기 위해 유효 주소를 알려고 이러
                                한 방식을 사용한다. 아래의 코드에서, reg는 32-Bit 범용 레지스터를 가리킨다.

                    CALL   NEXT
     NEXT     : POP     reg
     -----------------------------------------
                 JMP   [0xEB] 1ST
     2ND     : POP     reg
     1ST     : CALL    2ND
     -----------------------------------------
                  JMP   [0xE9] 1ST
     2ND     : POP     reg
     1ST     : CALL    2ND
     -----------------------------------------
     FLDZ
     FSTENV     [esp-0ch]
     POP           reg


* Kernel32 Base 찾기 ( 3가지 방식 존재 ) :: 이러한 명령어 흐름은 Kernel32.dll의 BaseAddress를 찾으
                                       려는 것이다. 만약 ShellCode가 GetProcAddress와 LoadLibrary를 Export하고
                                       있는 Kernel32.dll 모듈을 찾으면, 메모리에 다른 API 함수의 주소를 저장할 수
                                       있다.

     MOV     reg , DWORD PTR FS:[30h]
     ------------------------------------------------
     XOR      reg_a, reg_a
     MOV     reg_a(low-byte) , 30h
     MOV     reg_b, fs:[reg_a]
     ------------------------------------------------
     PUSH    30h
     POP      reg_a
     MOV     reg_b, FS:[reg_a]


* SEH Handler 찾기 :: Structured Exception Handler (SEH) 목록의 시작 위치는 FS Segment의 Offset 0에
                                   저장되어 있다. ShellCode는 그들의 Handler를 저장하고 고의적으로 Exception을 발
                                   생시켜 실행 흐름을 그들의 handler function으로 전달한다. 이는 실행 흐름을 숨기기
                                   위한 단순한 속임수로  코드가 다음에 어디로 이동할지 분석시 알기 어렵게 된다.

     MOV     reg, DWORD PTR FS:[00h]

* API Hashing ::  이러한 명령어 흐름은 API 함수 이름을 드러내지 않고 메모리에 API 함수를 저장하기 위해
                            ShellCode가 사용하는 속임수인 API Hashing을 의미한다. ( 그렇지 않으면 분석가는 API
                            함수 이름을 strings를 사용해 확인할 수 있다. )

     LOOP :     LODSB
                    TEST al, al
                    JZ short OK
                    ROR EDI, 0Dh ( or 07h )
                    ADD EDI, EAX
                    JMP short LOOP
     OK :         CMP EDI, ???


* 간접 함수 호출 :: 이 명령어 흐름은 스택상의 변수에 저장되어 있는 주소로 제어권을 전달하는 것을 의미
                             한다. ShellCode에서 많이 볼 수 있는 방식으로 단 한번 모든 API 함수를 확인하고 지역
                             변수에 그 주소를 저장한다.

     PUSH     DWORD PTR [EBP+val]
     CALL     [EBP+val]


* 의심 문자열 :: OfficeMalScanner는 다음과 같은 문자열이 일반적으로 다른 악성코드를 Drop하거나
                         Download를 하는 ShellCode내에서 발견되기 때문에 이러한 문자열을 탐지한다.

     - UrlDownloadToFile
     - GetTempPath
     - GetWindowsDirectory
     - GetSystemDirectory
     - WinExec
     - ShellExecute
     - IsBadReadPtr
     - IsBadWritePtr
     - CreateFile
     - CreateHandle
     - ReadFile
     - WriteFile
     - SetFilePointer
     - VirtualAlloc
     - GetProcAddress
     - LoadLibrary

* 복호화 루프 :: 이 명령어 흐름은 단순하게 표현되어 있지만, 일반적으로 Decode 루틴에서 사용된다.
                         예를 들어 ShellCode는 문자를 AL 레지스터에 로드하기 위해 LODSB를 사용하고 AL
                         XOR/ADD/SUB/ROL/ROR 동작을 수행한 후 수정된 값을 STOSB를 통해 문자로 되돌려
                         놓는다.

     LODS (x)
     XOR or ADD or SUB or ROL or ROR
     STOS (x)


* 함수 프롤로그 :: 이 명령어 흐름은 함수의 시작을 의미한다. 특히, 명령어들은 함수의 프롤로그 - 지역 변수
                            에 대한 Stack Frame 설정 를 준비한다. 

     PUSH     EBP
     MOV      EBP , ESP
     SUB       ESP , <value> or ADD ESP, <value>


* OLE 와 PE 파일 시그니처 :: OfficeMalScanner는 Office 문서 시작 부분의 시그니처
                              "\xD0\xCF\x11\xE0\xA1\xB1\x1a\xE1" 를 OLE Data에서 탐지한다. Offset을
                               사용한 경우, 잘 알려진 PE Header의 MZ Header를 찾아 PE 파일을 탐지한다.

[ Using OfficeMalScanner ]
다음은 악성 PowerPoint 문서를 분석하기 위해 OfficeMalScanner의 사용 예이다.

     $ wine OfficeMalScanner.exe 48615.ppt scan brute debug

< Output >

Output을 근거로 다음과 같이 판단할 수 있다.

* 파일은 Kernel32의 BaseAddress를 찾는 기능과 API Hashing , API 함수 간접 호출 기법들을 사용하는
   ShellCode이다.
* 내부에 OLE 문서가 존재해 OfficeMalScanner가 별도의 파일로 추출했다.
* 내부에 PE 파일이 2개 존재하며 Key 0x85를 통해 XOR 로 암호화 되어 있으며 두 파일 모두 추출해 별도의
   파일로 저장했다.
* 악성 가능 Index 률은 151이다. 

OfficeMalScanner는 악성 가능 Index를 사용해 파일의 악성적인 정도를 판단한다. 만약 폴더내의 수천개의 문서가 있고 하나는 악성 가능한 파일이라면, 모든 문서를 한번에 Scan할 수 있는 OfficeMalScanner에 포함된 ScanDir.py 를 사용할 수 있다. ( OfficeMalScanner.exe를 Python으로 감싸고 있다. ) 그리고 나서 처음으로 확인할 점은 악성 가능 Index이다. Table 6-2는 점수를 계산하는 방법을 보여준다.

===========================================================
     Description                              Score
-----------------------------------------------------------
       Executables                                        20
-----------------------------------------------------------
       Code                                                  10
-----------------------------------------------------------
       Strings                                                 2
-----------------------------------------------------------
       OLE Data                                              1
===========================================================
< Table 6-2 : 악성 가능 Index률 계산법 >

 이제 Office File로 부터 악성 가능한 Content를 추출했고 파일 타입도 알 수 있다.

     $ file *.bin

< Output >

첫번째 파일은 다른 MS Office 문서이므로, 해당 파일에 대해 이전의 파일과 같은 분석작업을 수행한다. 다음 레시피에서, 우린 OfficeMalScanner가 탐지한 ShellCode Block을 분석하는 방법을 알아 보겠다.

***** 레시피 6-12 : Disview와 Malhost-setup을 이용한 Office ShellCode 디버깅하기 *****

비록 OfficeMalScanner가 자동으로 내부의 OLE 와 PE 파일을 추출해 주지만, 여러분은 여전히 ShellCode를 분석하기 원할 것이다. 결국, XOR Decoding 을 수행하고 Disk에 다른 파일을 Drop하는 것은 ShellCode이기 때문이다. 만약 ShellCode를 분석할 수 없다면, Exploit의 중요한 부분을 빠뜨린 것이 된다.
OfficeMalScanner는 분리된 파일에서 ShellCode를 추출하지 모한다. 왜냐하면 자동으로 시작 지점과 길이를 결정하는 것은 쉽지 않기 때문이다. 그러나, OfficeMalScanner에 포함된 두개의 툴은 Office 문서내의 ShellCode를 분석하는데 도움이 된다.

* DisView.exe :: Command-Line Disassembler로 ShellCode의 시작 위치를 찾는데 사용된다.
* MalHost-Setup.exe :: 악성 Office 파일과 파일내의 ShellCode Offset이 주어지면, 이 툴은 ShellCode를
                         실행 파일로 생성해 실행하거나 디버깅해 볼 수 있다.

[ Finding the ShellCode Start ]
레시피 6-11에서, OfficeMalScanner는 각각 다른 Offset에서 3개의 ShellCode Block을 찾았다. 특히, Kernel32 Base Address를 찾는 Signature는 Offset 0xa6e이고 API-Hashing Signature는 0xd3a , 간접 호출은 0xb58이다. 이 시그니처를 기반으로, 0xa6e는 아마 시작 위치를 찾기 위한 부분일 것이다. (   ) Offset 0xa6e 부분 Disassembly 대신에 (   ) , 시작 부분을 확인하기 위해 0xa6e보다 더 낮은 부분의 Offset에서 Code Disassembly 를 해야 한다.
몇번의 실패를 거치면 아래의 코드처럼 ShellCode의 시작점이 0xa04 부터임을 알 수 있게 된다. 첫 두 Bytes
( \x81\xEC ) 가 굵은 글씨로 되어 있다. 어떻게 해당 지점에 ShellCode 시작 지점임을 알 수 있을까? 확실히는 알 수 없지만, sub esp 명령어는 스택상에 공간을 예약하기 위해 사용된다. 일반적으로 지역 변수를 위해 공간을 할당하는 것과 같이 함수의 시작 부분은 이러한 명령어들로 시작된다.

     $ wine DisView.exe 48615.ppt 0xa00

< Output >


[ Wrapping the ShellCode in an Executable ]
ShellCode의 시작 지점을 찾았다면, MalHost-Setup.exe를 이용해 실행 파일로 변환한다. 추가적으로 wait Parameter는 ShellCode 첫 두 Bytes ( \x81\xEC )를 무한 루프 형태의 명령어로 변환해 준다. 그리고 나서, 디버거로 Attach하면, Loop 명령어를 본래 2Bytes 로 바꾼 후 디버깅을 시작하게 한다. 여기 예제가 있따. - 본래 2Bytes는 Console Output에 저장되어 있다.

     $ wine MalHost-Setup.exe 48615.ppt out.exe 0xa04 wait

< Output >

[ Analyzing the ShellCode in a Debugger ]
만약 Wine에서 OfficeMalScanner.exe를 사용하고 있다면, MalHost-Setup.exe로 생성한 파일 ( 이 경우 out.exe )를 Windows 상에 복사한다. 그리고 나서 다음과 같이 실행한다. ::

     c:\out.exe

< Output >

이제 디버거를 통해 out.exe 프로세스에 Attach하면 된다. 실행중인 프로세스에 Attach하는 방법은 레시피 11-1에서 설명하고 있다. 이 예제와 차이점은 패치된 Bytes ( \xEB\xFE ) 를 본래의 Bytes ( \x81\xEC ) 로 바꿔준다는 것 뿐이다. 그렇게 하고 나면 FIgure 6-5와 같은 그림을 볼 수 있게 된다.

< Figure 6-5 : 디버거에 로드되어 있는 ShellCode >

[ Debugging ShellCode in the Context of Office Apps ]
몇몇 ShellCode는 매우 환경에 민감하게 반응한다. 공격자는 방어 기법 ( Protections ) 을 추가해 WINWORD.exe 나 EXCEL.exe와 같은 타겟 프로세스에서만 동작하게 할 수도 있다. 만약 디버거나 MalHost-Setup.exe와 같이 다른 Context에서 ( 동작 환경에 민감한 ) ShellCode를 실행하려고 한다면, 실패하게 될 것이다. 
공격자가 어떻게 하나의 (특정) 프로세스에서만 동작하도록 ShellCode를 만들 수 있는지 생각해 보자. 
첫번째, 대부분의 Exploit은 취약한 소프트웨어의 특정 빌드나 특정 버전에 맞도록 되어 있다. 리버스 엔지니어링을 해보면, 취약점이 실행될 시점에 공격자는 레지스터나 스택에 특정한 값이 저장되어 있는지를 확인한다. 
두번째 Stage Payload를 실행시키기 위해 하드 코딩된 XOR 키를 사용하는 것 대신에, ShellCode는 단순히 EDI에 있는 값을 XOR의 키 값으로 사용하게 된다. 
여전히 ShellCode를 디버깅하는 것은 가능하지만, 취약한 버전의 소프트웨어를 타겟으로 가능한 다른 방법을 강구해야만 한다. 다음의 단계를 따르자.

1. Hex Editor을 사용해, ShellCode의 첫 Byte를 0xCC로 변경한다. ( Software BP )
2. JIT 디버거로 설정한다. ( 레시피 11-2를 참조 )
3. 악성파일을 실행하고 0xcc Byte에 접근할 때까지 기다린다. 접근하면 JIT 디버거가 실행되고 제어권을 전달
    하게 된다.

[ NOTE ]     
Office 문서 분석에 대한 더욱 자세한 정보는 다음의 자료를 참고하기 바란다.
* Frank Boldewin's "Analyzing MSOffice Malware with OfficeMalScanner" paper and "New Advances in
   MS Office malware analysis" Presentation ( http://www.reconstructer.org/papers.html )
* Frank Bolewin's "Episode 2:The Image of death" 
  ( http://www.h-online.com/security/features/CSI-Internet-The-image-of-death-1030311.html )

*  Lenny Zeltser's "Extracting VB Macro Code from Malicious MS Office Documents"
  ( http://computer-forensics.sans.org/blog/2009/11/23/extracting-vb-macros-from-malicious-documents/ )
* Officecat - A tool to detect CVE exploits in Office documents
  ( http://www.snort.org/vrt/vrt-resources/officecat )

* Microsoft's OffViz - A tool to analyze the Office document structure and detect CVEs
  ( http://blogs.technet.com/b/srd/archive/2009/09/14/offvis-updated-office-file-format-training-video-created.aspx )
* ViCheck.ca - An online malicious file scanner ( https://www.vicheck.ca/



Analyzing Network Traffic
Client Application을 공격하는 대부분의 파일들은 Web이나 E-Mail을 통해 피해자 컴퓨터로 전송된다. ( 모두 그렇지는 않지만 ) 많은 회사들은 몇일동안 네트워크를 통해 송수신 되는 모든 파일을 저장한다.  만약 시스템이 손상되어 있었다면, 이방법은 Packet Capture의 사후 분석을 수행할 수 있고 감염 소스가 무엇인지 판별할 수도 있다. 다음 몇몇 레시피들은 웹 세션 ( HTTP ) 분석 , 문자열로 부터 파일을 추출하는 방법 , 자동으로 공격 가능한 취약점의 CVE 번호 확인하는 방법 , Packet Capture를 통해 URL 관계도 도식화등에 대한 기술에 초점을 맞춰져 있다. 
이 섹션내의 툴을 사용하기 위해, 네트워크 트래픽을 포함한 전체 Packet Capture가 필요할 것이다. 레시피 7-2에서 Packet Capture를 하기 위한 몇가지 방법에 대해 논의할 것이다. 주의할 점은, 만약 예전 버전의 tcpdump를 사용한다면, 모든 트래픽 ( snaplen )을 Chapture하기 위해 -s 0 옵션을 사용하길 바란다. 그렇지 않으면 각 Packet의 일부분 만이 Capture되므로 분석하기에 충분하지 않을 것이다.

***** 레시피 6-13 : Jsunpack를 이용해 Capture된 Packet으로 부터 HTTP 파일 추출하기 *****
더 나은 효율을 위해, 웹 서버는 Client에세 gzip으로 압축해 데이터를 전달한다. 또한 서버는 ( 동적으로 생성된 Content 에 대해 ) 분할 ( 역 - 개별 )Encoding 후 작은 크기의 Encoding 데이터를 Client에게 전송한다. 그 결과, Packet Capture를 통해 추출하려는 Content는 disk 상 저장 크기보다 더 작은 크기로 쪼개진다. 더 복잡하게 하기 위해, IP 계층에서 발생하는 모두 분활화 해야 한다. 
HTTP 세션으로 부터 정확하게 파일을 추출하기 위해, 여러분이 사용할 툴은 반드시 TCP Stream 재조립 , 데이터 추출 , 압축 해제 또는 하나의 데이터로 만들 수 있어야 한다. Jsunpack-n은 이러한 문제를 처리하기 위한 기능을 찾고 있다. 

* TCP stream reassembly
* HTTP Protocol Parsing
* 실행 파일 추출 ( Command-Line 옵션 -e )
* 모든 파일 추출 ( Command-Line 옵션 -s )
* 자동으로 gzip 트래픽 압축 해제
* 분할된 트래픽의 정상화 및 처리

gzip의 압축을 풀고 분할된 트래픽을 정상화하기 위해, Jsunpack-n.py 는 다음과 같이 두개의 파이썬 함수를 사용한다.

< Source >

Jsunpack-n 은 두가지의 중요한 과정에서 사용된다. : 인터페이스를 통합하고 실시간으로 트래픽을 분석하거나 pcap 파일 Scan. 다음의 예는 Jsunapck-n 으로 분류된 샘플 pcap 파일중 하나를 사용한다. -s Parameter는 ( 실행 파일 뿐만 아니라 ) 모든 파일을 추출하고, -v 는 악성으로 탐지된 모든 URL을 출력하고 , -J ( --JavaScript-decode-disable )는 Performance 향상을 위해 JavaScript Decoding을 비활성화 한다.

     $ ./jsunpackn.py ./samples/pdf.pcap -s -J -v

< Output >

확인한 것처럼, Jsunpack-n은 Packet Capture로 부터 3개의 파일을 추출했고 각각 하나의 소스 URL을 출력했다. 그 파일은 ./files 하위 디렉토리에 접두어 stream_ 과 파일의 SHA1 Hash 값으로 저장될 것이다. 다음과 같이 각 파일의 타입을 알 수 있을 것이다.

     $ cd files; file *
     
< Output >

이제 /img/pfqa.php 로 부터 전달받은 PDF 파일 , /img/uet.php 로 부터 전달받은 실행 파일 , 웹서버 루트 ( / ) 로 부터 전달받은 알수 없는 타입의 데이터를 추출했다. 만약 ( 알 수 없는 타입의 데이터를 ) Hex Viewer로 파일을 조사한다면, HTML 파일이라는 것을 알 수 있을 것이다. 그러나 file 명령어는 (알 수 없는 타입의 파일이) Binary Characters로 되어 있기 때문에 HTML로 리포팅하지 않았다.

     $ xxd stream_22cd6 [REMOVED]

< Output >

( HTML 파일로 ) 생각하든 그렇지 않든, stream_22cd6 파일에 정상적인 HTML Content이 있다. 여러분이 확인한 Binary Characters은 브라우저가 JavaScript Code로 해석할 때, ( 파일 ) 페이지 하위의 JavaScript Code에
의해 대체된다. 


***** 레시피 6-14 : Jsunapck을 이용해 URL 관계도 그리기 *****
Packet Capture를 보면, 실제 악성코드 감염의 발단에 대해 이상하게 생각될 것이다. 공격자는 다른 도메인간을
리다이렉트 하도록 설정해 둔다. 그렇지만 하나의 웹사이트를 다른 웹사이트로 연결하는 방법은 명확하지 않다.
시간 순서대로 연결을 정렬해 보면 피해자의 컴퓨터가 각 사이트를 접속한 순서를 알 수 있다. 그러나 브라우저에 사용자가 사이트의 주소를 직접 타이핑해 접근했는지, 악성 JavaScript에 의해 리다이렉트된건지, 내부의 iFrame에 의한 건지 아니면 다른 이유 때문인건지는 확답할 수 없다. 
이 레시피에서 Jsunpack-n을 이용해 (악성 여부 또는 접근 과정을) 판단할 때 도움이 될 수 있도록 Packet Chapture내의 URL 관계도를 도식화하는 방법을 알아보겠다. 아래의 예를 tshark를 사용해 Packet Capture내의 HTTP Request를 요약해 출력한 것이다.

     $ tshark -r pdf.pcap -z http_req,tree

< Output >

요약 Output을 바탕으로, 피해자는 trughsa.com 의 세 페이지에 접근했음을 알 수 있다. :: 루트 페이지 ( / ) , /img/pfqa.php , /img/uet.php. 그러나 궁금한 점은 브라우저가 접속한 페이지나 사이트가 아니다. 궁금한 점은
어떻게 브라우저가 페이지나 사이트에 접속했느냐이다. Jsunpack-n 은 Packet Capture를 읽어들여 HTTP Request 간에 관계를 확인하기 위해 Decoded JavaScript내의 참조 필드, 내부 Objects , iframes , URL로 부터 데이터를 모은다. 이 방법은 참조 문자열이 속임수 일 수 있으므로 항상 완벽하진 않지만, 다른 시각을 제시해 준다. 

Jsunpack-n으로 도식화 하기 위해, Python 그래픽 Library가 필요하다. Ubunto에서 ap-get install python-yapgvb 을 입력해 설치할 수 있다. Packet Capture가 접근한 각 URL은 그래프상에 Node로 표현된다. 만약 각 URL에 대한 HTTP 서버의 Response Content가 다른 사이트 또는 페이지로 리다이렉트되어 결과적으로 브라우저가 접근했다면, 부모 URL의 자식 Node로 표현된다.
아래의 예는 Jsunpack-n 그래픽 모드를 사용해 출력한 모습이다. 뒤의 Parameter -q는 STDOUT으로 문자열 출력을 제한하고 -v는 악성 노드 뿐만 아니라 그래픽 상에 모든 노드를 표시하고 -J는 JavaScript Decoding을 비활성화 시킨다. Figure 6-6은 PNG 출력을 보여준다.

     $ ./jsunpackn.py samples/pdf.pcap -g sample-pdf1.png -q -v -J


Figure 6-6 : JavaScript Decoding 을 사용하지 않은 URL 관계도

그래프에서 본것처럼, uet.php URL은 관계도의 다른 부분과 연결되지 않았다. 그러므로, Jsunpack-n 은 루트 노드의 자식으로 표현했다. 다른 한편으로, pfqa.php URL은 trughtsa.com 홈페이지 내부의 iFrame에 의해 접근했다. Figure 6-4은 -J 옵션을 제거해 JavaScript Decoding을 활성화 시킨 결과이다.

   $ ./jsunpackn.py samples/pdf.pcap -g sample-pdg2.png -q



Figure 6-7 : JavsScript Decoding을 사용한 실제 URL 관계도





 









Posted by GhostKei
,