29 Jul 2019

Some time ago, while reviewing old samples reports passed through MalSilo, any caught my attention, below the main triggers of one of these.

- PE32 sample - some generic YARA rules matches - + AutoIT match - + DarkComent match - Persistance via schtasks.exe - svchost.exe connecting to exotic domain

Everything maliciously normal here, but after a quick check and some metadata quirks it turned out the specimen was packed with CypherIT .

As far as I can tell from few searches, the crypter is well advertised in forums and YouTube videos.

The first part of the analysis will take in consideration some of the sample’s layers, reaching its core with the RunPE (shellcode) section

The second one, will briefly map CypherIT website advertised features to its code components

The third section explores more packed malware, and their final payload thanks to MalSilo’s backends (one of which is MISP)

Finally yet importantly, we will have a look to a recent sample

Let’s start peeling …

Technical details of the sample are given below

First seen (MalSilo): 2018-11-28 File name: K2bkm.jpg drop site: https[:]//f.coka[.]la/K2bkm.jpg md5: 7ece8890e1e797843d68e73eb0ac2bc4 sha1: 4448b907f2c9f9ee8e4b13e4b6c292eef4b70930 sha256: 84d0c9352eacf92a919f972802a6a7949664f204f984aaf4b44da1b1aa7aa729 ssdeep: 24576:Fu6J33O0c+JY5UZ+XC0kGso6FapiE6kitdnsxWY:Hu0c++OCvkGs9FaeFY

Process execution flow

Behavior Graph

Pstree view

Detailed view

sample.exe | \_ ( copy of ) sample.exe \_ schtasks.exe 1368 /create /tn 5265676973747279204B6579204E616D65 /tr "C:\Users\[..]\AppData\Local\Temp\Folder Name\winint.exe" /sc minute /mo 1 /F

I - Runtime behaviour

In a nutshell, the following steps are executed by the program

sample.exe runs a basic anti-analysis check AutoIT script body gets executed AutoIT code: Start execution logic Remove Zone.Identifier Create mutex Sleep Runs decryption routine on one embedded PE resource Executes RunPE (via shellcode), in this case, self-process hollowing Install persistance task Final payload (for this sample, DarkComet) does its dirty job

Layer 1

In order to avoid execution (if) monitored, the first layer of the loader only checks if it is being debugged, the same is achieved calling the good old isDebugPresent at offset 0x00403b7A .

Which, if it is the case, will lead to a fake message displayed to the user and simply stop executing.

At this stage, no additional anti-analysis checks are performed and the execution proceeds just flawless, passing control to the AutoIT code interpreter.

Layer 2

This sample in particular is not at all heavily obfuscated and many core functions still have a descriptive name (i.e. binder , startup , persistautoinject , […]).

Nevertheless, the overall code can be broken up in 3 blocks.

top: naive obfuscation of some main native AutoIT functions + basic strings obfuscation function middle: core functionalities bottom: main execution logic

Let’s start from the bottom up; below the main steps executed at start

Function name Actions enhkoxkvrufrsntgjkoyxiard removes the Zone.identifier of the file ( [sample]:Zone.identifier ), this will avoid Windows to inform the user about the execution of a not trusted file mutex its a custom implementation (via Windows API calls -> Kernel32.dll -> CreateMutexW ) for creating / checking mutex and to ensure that only one instance of the infection is running _cryptedfile it chains together multiple functions, but in the end it reads one PE resource from the sample file and decrypts it, making it available to the next function (injector) dnqmjpfdpcuxwbwkadcaibgzw RunPE injection function, leveraging shellcode for loading the final payload (in this case Darkcomet) startup the persistency module, this will install a task executed via schtasks.exe and will run the sample every minute ughotphdsufuiehfpoegoakmi another way of checking if the sample is running and calling the RunPE injection function on it

The middle part of the code stores many more functions than the one employed by this sample; something that aligns with the crypter builder opt-in / opt-out behavior.

Between those functions, some that are not used at least in this sample, but interesting are:

PersistAutoinject

Binder

UACBypass

USBSpreader

AntiVM

PersistAutoInject

After some cleaning and functions rename, it is clearly visible how the payload is injected into RegAsm.exe .

Note that, $_cryptedfile stores the decrypted PE resource, which is the final payload carried by the crypter.

Binder

Depending on the arguments supplied to the function, the payload stored in the packer is appended to a clean file and afterwards started.

The merged files can be dropped into %temp% , %appadata% or the folder where the original file is running from.

UACBypass

Based on the OS version, two different types of UAC bypass tricks are run.

In case of Windows 7 or 8 via eventwer , and thanks to fodhelper for Windows 10.

USBSpreader

It goes by itself what if does

Removable devices enumeration For every device, folders are discovered For every file - without extension .pif - the payload is copied into the folder and renamed with the original file name, adding extension .pif . The original file is deleted



AntiVM

It boils down to three registry checks

Generic one

VMware specific

VirtualBox specific

Reaching finally the top part of the code, few calls stands immediately out from the crowd and looks good candidates or at least building blocks, for RunPE and many other direct OS calls.

DllStructSetData

DllStructGetSize

DllStructGetPtr

DllStructGetData

DllStructCreate

DllCall

For what concerns the strings obfuscation, once the function is cleaned up it looks like this

Deobfuscation routine calls are scattered around the script, but meaning of the strings is anyhow intuitive.

RunPE - Process Hollowing

Once the carried payload is read and decrypted (AES256) with a hardcoded password available in the script, the next steps can be outlined like in the diagram.

Bear in mind that the UPX part is an on/off feature and might not be enabled for other samples.

The shellcode, below just a small snippet, is embedded in the script and has its own function here renamed as RunPE , the whole body is hidden away thanks to the string obfuscation function uxharcuawtv .

Once extracted and converted in a suitable format, the first shellcode instructions are walking the PEB to resolve kernel32 and ntdll base addresses, later used for the respective API calls.

The shellcode is also using a basic hashing function instead of storing strings of the respective Windows APIs.

The function in charge for computing the hash is located @ 0x00000092

The assembly snippet can be easily translated to python.



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 win_apis = [ "CreateProcessW" , "VirtualAllocEx" , "VirtualAlloc" , "WriteProcessMemory" , ... ... ... ] def build_hash (api): mapping = map(ord, api) uVar2 = 0 for i in mapping: uVar2 = (uVar2 << 4 ) + i if (uVar2 & 0xF0000000 ): uVar2 = (uVar2 ^ (uVar2 & 0xf0000000 ) >> 0x18 ) & 0xfffffff return hex(uVar2) for win_api in win_apis: print ( "{} \t {}" . format(build_hash(win_api),win_api))

Once enumerated the exported functions from kernel32.dll and ntdll.dll , it becomes trivial to map the hash values found in the shellcode to their equivalent string versions - as seen at the beginning of the section.

Hash API DLL API 0x73c3a79 ntdll.dll memcpy 0xb8a4a79 ntdll.dll RtlZeroMemory 0xc8338ee ntdll.dll NtUnmapViewOfSection 0x1e16457 kernel32.dll CreateProcessW 0x8cae418 kernel32.dll VirtualAllocEx 0x3d8cae3 kernel32.dll VirtualAlloc 0x648b099 kernel32.dll WriteProcessMemory 0x394ba93 kernel32.dll TerminateProcess 0x4b9c7e4 kernel32.dll GetThreadContext 0x4b887e4 kernel32.dll SetThreadContext 0x1d72da9 kernel32.dll ReadProcessMemory 0xb3dd105 kernel32.dll VirtualFree 0xf232744 kernel32.dll ResumeThread 0xd186fe8 kernel32.dll VirtualProtectEx

At the end, calling ResumeThread , resumes the suspended process - now filled with the payload - and break free the carried malware.

Quickly checking results on the internet for similar shellcode wrappers, yielded almost an identical version, the same was released on a forum in 2016, by a user that goes by the moniker of Wardow .

One hypothesis, if the previous catch holds true, is that CypherIT’s devs copy-paste, part of the wrapper / shellcode and embedded it straightaway into the crypter.

II - CypherIT

Looking at CypherIT website, its easy at least for some of the functions, to map 1:1 the advertised features with the code just analyzed

Note: screenshots taken around April 2019

The packer has different price entries, that goes from 30 up to 300 Euro, a part from that, support is also offered - surprisingly - 24⁄ 7 + Discord group too.

I guess the good old Skype, ICQ and Jabber days are gone ;-)

III - MalSilo historical memory

MalSilo works with multiple backends, some for storing metadata and others for the samples - but there are more supporting different uses cases.

Since the focus until now was on the crypter and not on the dropped payload, I though it might be also interesting to investigate which other families were dispatched during the campaigns.

Due to MalSilo project nature it has obviously a limited view about threats around the world, but it can still provide some insights; with this in mind let’s first get an idea about how many samples passed through the system.

This can be easily achieved querying MISP (backend #2) and organizing in a chronological order every collected samples.

The chart below shows a total of 49 specimens, out of curiosity the “patient zero” previously analyzed was detected on the 2018-11-28.

Since the steps for tracking a malware family are kind of unique due to they way MalSilo works, there is no much to share with the community, but the main points are:

YARA rule is created for fingerprinting the crypter (note: at the time, the rule was covering only the version previously described, not the latest one) Backend #1, where samples are stored, is queried with the new rule + custom script is executed For every match, sample metadata is extracted from backend #2 (MISP) All samples are unpack un bulk mode For every sample The hard-coded password for the encrypted payload is gathered The carried payload is decrypted, extracted and saved to disk

Payloads are afterwards statically and dynamically fingerprinted. Dynamic checks are mandatory to overcome additional obfuscators or packers making static detection useless; the final results looks as follows.

PE resources

AutoIT provides an easy way to add custom resources to a file, this can be achieved via a specific User Defined Functions (UDF) known as #AutoIt3Wrapper_Res_File_Add .

The interesting part of this, is that it exposes the full path of the embedded resource, thus, exposing - for some samples - the Windows username of the threat actor crafting the payload.

Just keeping the first part of the Windows path, yields these names

c:\users\user

c:\users\robotmr

c:\users\lenovo pc

c:\users\hp

c:\users\bingoman-pc

w:\work\client and crypter

c:\users\administrator

c:\users\pondy

c:\users\peter kamau

Plotting the Windows paths taken from every payloads displays the following pattern

By looking at the graphs, it comes with no surprise that the packer was employed by off-the-shelf malware.

Out of curiosity, analyzing the crypters of the administrator user, which also crafted the payload investigated at the beginning of the article, it shows how all three samples were - most probably - generated by the same ( old ?) CypherIT version.

I say old , mostly because, if we look at the other samplings, its clearly visible how the overall script obfuscation technique was updated.

IV - Recent samples

The YARA rule originally developed reached its EOF - around 2019.02.11 - as soon as CypherIT received a major update.

Tearing a part a recent sample observed by MalSilo on the 2019.07.23 (7b252dbb6a39ea4814d29ebfd865f8a46a69dd9f) and also quickly skimming through some of the ones before (02.2019 - 07.2019) is clearly visible how the obfuscation technique - and not only - is more or less constantly updated.

From here we could start all over again :)

This last section will only investigate few functions, below some take aways.

At run, the first instruction to be executed is a loop, with nested if statements, that initializes a set of variables A control variable, just set before the loop, decides which block should be jumped to next Close to the end of every if block , the control variable is re-initialized, defining the next jump to take Once a code block is executed, a custom function is resolved and called

Afterwards, execution starts almost in the same way as the old version

Control Flow Flattening CFF , the steps just described, is employed almost in every functions, together with string obfuscation - this last one, sometimes with or without CFF.

When it comes to sandbox detection there are two new functions that comes into play

Detecting typical VM guest tools from, VirtualBox and VMware

Tracking mouse movement

AntiVM_moue_check snippet using CFF and strings obfuscation

AntiVM_moue_check after clean up

AntiVM_process_check

AntiVM_process_check after clean up

For what concerns the carried payload, latest versions stores it in multiple resources, under the RESOURCE_TYPE_FONTDIR , the function in charge of rebuilding it, is shown below.

The first function parameter, $data , takes in input a list of resources separated by | and rebuilds the final payload.

$data = X|USXlhrrTcD|JqLn|hEuiNUhgRzrxs|nyFoHiqBt|PJYZYBUO|ChaHOMZLQtIa|AFpMebeesFkYteWii|FCSQpnQ|BHxAiLvVjtJlwSKA

Nothing special to add about the shellcode, which for the few samples analyzed, remained the same.

Final thoughts

CypherIT did not perform any game changer new techniques; also after peeling all obfuscation layers, it keeps under the hood the same features observed back in 2018, adding to the portfolio new tricks and functionalities (not fully outlined in the last section).

Event if recent samples rely on CFF and new string obfuscation machination for slowing down analysis, some functions and related parameters are still talkative thanks to their naming convention.

If the earlier versions of the specimen were storing the payload only in one section of the PE file, latest ones split and store it in multiple resources, but in essence, the rebuilding technique stays the same as before.

In addition, since the code skeleton logic remained unchanged between updates, once new tricks are defeated, the analysis workflow can proceed more or less the same way as before.

Based on MalSilo telemetry data outlined in the article, it can be hypothesized that the crypter is mostly common among commodity malware of category stealers.

Appendix

ATT&CK Techniques

Tactic ID Name Persistance T1053 Scheduled Task Persistance T1158 Hide Files and Directories Privilege escalation T1088 Bypass User Account Control Defense evasion T1093 Process Hollowing Defense evasion T1055 Process Injection Defense evasion T1045 Software Packing Defense evasion T1027 Obfuscation Files or Information Defense evasion T1140 Deobfuscate/Decode Files or Information

YARA rule

rule cypherit_shellcode { meta: author = "raw-data" tlp = "white" version = "1.0" created = "2019-01-25" modified = "2019-01-25" description = "Detects CypherIT shellcode" strings: $win_api1 = { c7 8? ?? ?? ?? ?? ee 38 83 0c c7 8? ?? ?? ?? ?? 57 64 e1 01 c7 8? ?? ?? ?? ?? 18 e4 ca 08 } $win_api2 = { c7 8? ?? ?? ?? ?? e3 ca d8 03 c7 8? ?? ?? ?? ?? 99 b0 48 06 } $hashing_function = { 85 c9 74 20 0f be 07 c1 e6 04 03 f0 8b c6 25 00 00 00 f0 74 0b c1 e8 18 33 f0 81 e6 ff ff ff 0f 47 49 } condition: (1 of ($win_api*)) and $hashing_function }

MISP event

Download

CypherIT samples and payload [08.2018 - 02.2019]

Malarchive

IOCs - 2019.07.23

Collection date Crypter (sha1) Drop site 2019-07-23 7b252dbb6a39ea4814d29ebfd865f8a46a69dd9f hXXp://mimiplace[.]top/invoice.exe

IOCs [08.2018 - 02.2019]

49 drop-sites and 44 unique samples