Skip to content

Commit

Permalink
Process Doppelganging - hooks, API signature and payload extraction
Browse files Browse the repository at this point in the history
package.
  • Loading branch information
kevoreilly committed Dec 31, 2017
1 parent db33916 commit 762de1b
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 6 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ The techniques or behaviours that CAPE detects and has packages for include:
- Shellcode injection
- DLL injection
- Process Hollowing
- Process Doppelganging
- Decompression of executable modules in memory
- Extraction of executable modules or shellcode in memory

Expand All @@ -38,11 +39,13 @@ CAPE has config parsers/decoders for the following malware families, whose paylo
- TrickBot
- RCSession/Screech

Many other malware families have their payloads extracted by some of the behavioural packages, with their configuration in the clear in the resulting output. Configuration parsing may then be performed on this by virtue of Yara-based detection, and config parsing based on either of CAPE's config parsing frameworks, the RATDecoders framework from malwareconfig.com and DC3-MWCP (Defense Cyber Crime Center - Malware Configuration Parser). The many parsers/decoders from malwareconfig.com are also included, comprising among many others: Sakula, Trickbot, DarkComet, PredatorPain and PoisonIvy. Thanks to Kevin Breen/TechAnarchy for this framework and parsers (https://github.com/kevthehermit/RATDecoders), and to DC3 for their framework (https://github.com/Defense-Cyber-Crime-Center/DC3-MWCP).

CAPE also has Yara signatures to detect payloads that are extracted by a behavioural package. This list is growing, and includes:
- QtBot, ZeroT, WanaCry, Sedreco, NetTraveler, Locky, Emotet, Cerber, Ursnif, Enfal, BadRabbit, Magniber, Redsip, RCSession, Hancitor, Kronos, PetrWrap, Kovter, Azer, Petya, Dreambot, Atlas, NanoLocker, Mole, Codoso, Cryptoshield, Loki, Jaff, Dridex, RedLeaf, ChChes, EvilGrab, HttpBrowser, IcedID, Scarab

Many other malware families have their payloads extracted by some of the behavioural packages, with their configuration in the clear in the resulting output. Configuration parsing may then be performed on this by virtue of Yara-based detection, and config parsing based on either of CAPE's config parsing frameworks, the RATDecoders framework from malwareconfig.com and DC3-MWCP (Defense Cyber Crime Center - Malware Configuration Parser). The many parsers/decoders from malwareconfig.com are also included, comprising among many others: Sakula, Trickbot, DarkComet, PredatorPain and PoisonIvy. Thanks to Kevin Breen/TechAnarchy for this framework and parsers (https://github.com/kevthehermit/RATDecoders), and to DC3 for their framework (https://github.com/Defense-Cyber-Crime-Center/DC3-MWCP).

A utility package 'DumpOnAPI' is included which allows a module to be dumped when it calls a specific API function which can be specified in the web interface. This can be useful for quickly unpacking/dumping novel samples.

There are a number of other behavioural and malware family packages and parsers currently in the works, so watch this space.

Packages can be written based on API hooks, the CAPE debugger, or a combination of both.
Expand Down
Binary file modified analyzer/windows/dll/CAPE.dll
Binary file not shown.
Binary file modified analyzer/windows/dll/CAPE_x64.dll
Binary file not shown.
Binary file added analyzer/windows/dll/Doppelganging.dll
Binary file not shown.
Binary file added analyzer/windows/dll/Doppelganging_x64.dll
Binary file not shown.
44 changes: 44 additions & 0 deletions analyzer/windows/modules/packages/Doppelganging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Copyright (C) 2010-2015 Cuckoo Foundation, Optiv, Inc. ([email protected])
# This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org
# See the file 'docs/LICENSE' for copying permission.

import os
import shutil
from subprocess import call
from lib.common.abstracts import Package

class Doppelganging(Package):
"""Dump-on-API package."""

def __init__(self, options={}, config=None):
"""@param options: options dict."""
self.config = config
self.options = options
self.pids = []
self.options["dll"] = "Doppelganging.dll"
self.options["dll_64"] = "Doppelganging_x64.dll"

def start(self, path):
args = self.options.get("arguments")
appdata = self.options.get("appdata")
runasx86 = self.options.get("runasx86")

# If the file doesn't have an extension, add .exe
# See CWinApp::SetCurrentHandles(), it will throw
# an exception that will crash the app if it does
# not find an extension on the main exe's filename
if "." not in os.path.basename(path):
new_path = path + ".exe"
os.rename(path, new_path)
path = new_path

if appdata:
# run the executable from the APPDATA directory, required for some malware
basepath = os.getenv('APPDATA')
newpath = os.path.join(basepath, os.path.basename(path))
shutil.copy(path, newpath)
path = newpath
if runasx86:
# ignore the return value, user must have CorFlags.exe installed in the guest VM
call(["CorFlags.exe", path, "/32bit+"])
return self.execute(path, args, path)
5 changes: 5 additions & 0 deletions modules/processing/CAPE.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
COMPRESSION = 1
INJECTION_PE = 3
INJECTION_SHELLCODE = 4
INJECTION_SECTION = 5
EXTRACTION_PE = 8
EXTRACTION_SHELLCODE = 9
PLUGX_PAYLOAD = 0x10
Expand Down Expand Up @@ -232,6 +233,10 @@ def process_file(self, file_path, CAPE_output, append_file):
file_info["target_path"] = metastrings[4]
file_info["target_process"] = metastrings[4].split("\\")[-1]
file_info["target_pid"] = metastrings[5]
if file_info["cape_type_code"] == INJECTION_SECTION:
file_info["cape_type"] = "Injected Section"
if len(metastrings) > 4:
file_info["section_handle"] = metastrings[4]
if file_info["cape_type_code"] == EXTRACTION_PE:
file_info["cape_type"] = "Extracted PE Image"
if len(metastrings) > 4:
Expand Down
12 changes: 8 additions & 4 deletions modules/reporting/submitCAPE.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@
log = logging.getLogger(__name__)

cape_package_list = [
"Cerber", "Compression", "Compression_dll", "Compression_doc", "Compression_zip", "DumpOnAPI", "EvilGrab", "Extraction",
"Extraction_dll", "Extraction_regsvr", "Extraction_zip", "Extraction_ps1", "Injection", "Injection_dll", "Injection_doc",
"Injection_pdf", "Injection_zip", "Injection_ps1", "PlugX", "PlugXPayload", "PlugX_dll", "PlugX_doc", "PlugX_zip", "Sedreco",
"Sedreco_dll", "Shellcode-Extraction", "UPX", "UPX_dll", "Ursnif"
"Cerber", "Compression", "Compression_dll", "Compression_doc", "Compression_zip", "DumpOnAPI", "Doppelganging", "EvilGrab",
"Extraction", "Extraction_dll", "Extraction_regsvr", "Extraction_zip", "Extraction_ps1", "Injection", "Injection_dll",
"Injection_doc", "Injection_pdf", "Injection_zip", "Injection_ps1", "PlugX", "PlugXPayload", "PlugX_dll", "PlugX_doc",
"PlugX_zip", "Sedreco", "Sedreco_dll", "Shellcode-Extraction", "UPX", "UPX_dll", "Ursnif"
];

def pirpi_password(strings):
Expand Down Expand Up @@ -178,6 +178,10 @@ def run(self, results):
continue
detections.add('Compression')

elif entry["name"] == "Doppelganging":
if report["info"].has_key("package"):
detections.add('Doppelganging')

##### Specific malware family packages
#####
elif entry["name"] == "PlugX":
Expand Down
33 changes: 33 additions & 0 deletions modules/signatures/CAPE.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,3 +402,36 @@ def on_call(self, call, process):
def on_complete(self):
if self.config_copy == True and self.compressed_binary == True:
return True

class CAPE_Doppelganging(Signature):
name = "Doppelganging"
description = "CAPE detection: Process Doppelganging"
severity = 1
categories = ["injection"]
authors = ["kevoreilly"]
minimum = "1.3"
evented = True

def __init__(self, *args, **kwargs):
Signature.__init__(self, *args, **kwargs)
self.lastprocess = None

filter_categories = set(["process", "thread", "filesystem",])

def on_call(self, call, process):
if process is not self.lastprocess:
self.section_handles = set()
self.lastprocess = process
self.filehandle = None
self.sectionhandle = None

if call["api"] == "CreateFileTransactedA" or call["api"] == "CreateFileTransactedW":
self.filehandle = self.get_argument(call, "FileHandle")
elif call["api"] == "NtCreateSection":
if self.filehandle and self.filehandle == self.get_argument(call, "FileHandle"):
self.sectionhandle = self.get_argument(call, "SectionHandle")
elif call["api"] == "NtCreateProcessEx":
if self.get_argument(call, "SectionHandle") == self.sectionhandle:
return True


6 changes: 6 additions & 0 deletions web/templates/analysis/CAPE/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@
<td>{{file.virtual_address}}</td>
</tr>
{% endif %}
{% if file.cape_type_code == 5 %}
<tr>
<th>Section Handle</th>
<td>{{file.section_handle}}</td>
</tr>
{% endif %}
{% if file.cape_type_code == 3 or file.cape_type_code == 4 %}
<tr>
<th>Target Process</th>
Expand Down

0 comments on commit 762de1b

Please sign in to comment.