If you are interested in experimenting with steganography and my tools, I propose the following challenge.
Tag Archives: SANS
Steganography Analysis With pngdump.py: Bitstreams, (Thu, May 1st)
A friend asked me if my pngdump.py tool can extract individual bits from an image (cfr. diary entry "Steganography Analysis With pngdump.py").
It can not. But another tool can: format-bytes.py.
In the diary entry I mentioned, a PE file is embedded inside a PNG file according to a steganographic method: all the bytes of a channel are replaced by the bytes that make up the PE file. If one would visualize this image, it would be clear that it represents nothing. That it just looks like noise.
Often with steganography, the purpose is to hide a message in some medium, without distorting that medium too much. If it's a picture for example, then one would not notice a difference between the original picture and the altered picture upon visual inspection.
This is often achieved by making small changes to the colors that define individual pixels. Take an 8-bit RGB encoding: each pixel is represented by 3 bytes, one for the intensity of the color red, one for green and one for blue. By changing just the least significant bit (LSB) of each byte that represents the RGB color of the pixel, one can encode 3 bits, without noticable change in the final color (it's a change smaller than 0.5% (1/256)).
Take these pictures for example:
The one on the left is the original picture, the one on the right has an embedded PE file (via LSB steganography). I can't see a difference.
To extract the PE file from the picture on the right, one has to extract the LSB of each color byte, and assemble them into bytes. This can be done with format-bytes.py.
format-bytes.py takes binary data as input and parses it per the instructions of the analyst. I typically use it to parse bytes, like in this example:
format-bytes.py -f "<IBB"
This means the input data should be parsed as a unsigned 32-bit integer (I), little-endian (<), followed by two unsigned bytes (BB).
But format-bytes.py can also extract individual bits: this is done with bitstream processing. Let me show you an example.
The steganographic lake image I created contains an embedded PE file. The bits that make up the bytes of the PE file, are stored in the least significant bit of each color byte of the pixels in the image.
First I encoded the length of the PE file as an unsigned, little-endian 32-bit integer. Using the LSBs of the pixels. And then followed by the PE file itself, also encoded in the LSBs of the pixels.
The following command decodes the length:
pngdump.py -R -d lake-exe.png | cut-bytes.py 0:32l | format-bytes.py -d -f "bitstream=f:B,b:0,j:>" | format-bytes.py
pngdump.py's option -R extracts the raw bitmap of the image, option -d does a binary dump.
This bitmap data is piped into cut-bytes.py to select the first 32 bytes (0:32l). We want the first 32 bytes to extract the 32 LSBs that make up the length of the embedded PE file.
format-bytes.py's option -f "bitstream=f:B,b:0,j:>" instructs the tool to operate on the bit level (bitstream) and to treat the incoming data as individual unsigned bytes (f:B, e.g., format B), to select the least significant bit (b:0, e.g., the bit at position 0 in the byte) and to assemble the extracted bits into bytes in big-endian order (j:>, e.g., join in big-endian order).
That produces 4 bytes, that can then be piped again into another instance of format-bytes, this time to parse the integer.
This output produced by the second instance of format-bytes.py, represents the incoming data in different formats. The line that starts with 4I shows the formatting of 4-byte long integers. ul stand for unsigned & little-endian. Thus the length of the PE file is 58120, this is stored in the LSBs of the first 32 bytes of the raw image.
Now that we know the length of the PE files, we know how many bits to extract: 58120 * 8 = 464960. So from the 32nd byte in the raw image, we take 464960 bytes and process them with the same bitstream method (but this time, I do an HEX/ASCII dump (-a) to view the extracted PE file):
pngdump.py -R -d lake-exe.png | cut-bytes.py 32:464960l | format-bytes.py -a -f "bitstream=f:B,b:0,j:>" | headtail.py
This looks indeed as a PE file. Let's do a binary dump and pipe it into tools file-magic.py and pecheck.py to verify that it is indeed a valid PE file:
pngdump.py -R -d lake-exe.png | cut-bytes.py 32:464960l | format-bytes.py -d -f "bitstream=f:B,b:0,j:>" | file-magic.py
pngdump.py -R -d lake-exe.png | cut-bytes.py 32:464960l | format-bytes.py -d -f "bitstream=f:B,b:0,j:>" | pecheck.py | headtail.py
We did extract a valid PE file.
And as a final check, since I know the hash of the original file, let's validate it with hash.py:
pngdump.py -R -d lake-exe.png | cut-bytes.py 32:464960l | format-bytes.py -d -f "bitstream=f:B,b:0,j:>" | hash.py -v 0a391054e50a4808553466263c9c3b63e895be02c957dbb957da3ba96670cf34
As Johannes explained in his Stormcast episode, there are many ways to encode data using steganography, and it's often hard to detect/extract unless you know the exact algorithm. I was able to decode it with my tools, because I knew exactly how the PE file was encoded (as I did it myself ๐ ).
You can find many (online) steganography tools, but they don't always explain how they encode a payload.
If you are interested, tune in this Saturday, I will present you with a challenge diary entry. ๐
Didier Stevens
Senior handler
blog.DidierStevens.com
(c) SANS Internet Storm Center. https://isc.sans.edu Creative Commons Attribution-Noncommercial 3.0 United States License.
More Scans for SMS Gateways and APIs, (Tue, Apr 29th)
Last week, I wrote about scans for Teltonika Networks SMS Gateways. Attackers are always looking for cheap (free) ways to send SMS messages and gain access to not-blocklisted numbers. So, I took a closer look at similar scans we have seen.
There are numerous ways to send SMS messages; using a hardware SMS gateway is probably one of the more fancy ways to do so. Most websites use messaging services. For example, we do see scans for SMS plugins for WordPress:
These scans look for style sheet files (.css) that are part of the respective plugins. It is fair to assume that if the respective style sheet is present, the attacker will attempt to obtain access to the site:
/wp-content/plugins/sms-alert/css/admin.css
/wp-content/plugins/mediaburst-email-to-sms/css/clockwork.css
/wp-content/plugins/verification-sms-targetsms/css/targetvr-style.css
/wp-content/plugins/wp-sms/assets/css/admin-bar.css
/wp-content/plugins/textme-sms-integration/css/textme.css
/wp-content/plugins/sms-alert/css/admin.css
We also got a few odd, maybe broken, scans like:
/api/v1/livechat/sms-incoming/%%target%%/wp-content/themes/twentytwentyone/assets/css/print.css
/api/v1/livechat/sms-incoming/%%target%%/wp-content/themes/twentytwentyone/assets/js/responsive-embeds.js
The "%%target%%" part was likely supposed to be replaced with a directory name.
And we have scans for some configuration files that may contain credentials for SMS services like:
/twilio/.config/bin/aws/lib/.env
/twilio-labs/configure-env
/twillio_creds.php
/twilio/.secrets
/sms_config.json
/sms/actuator/env
/sms/env
And many similar URLs.
Scans also look for likely API endpoints used to send SMS messages. I am not sure if they are associated with a particular product or software:
/sms/api/
/api/v1/livechat/sms-incoming/twilio
/sms.py
/Sms_Bomber.exe
SMS_bomber.exe is a script designed to send mass SMS messages [1]. The scans may attempt to identify copies left behind by other attackers.
SMS_bomber also suggests the use of a proxy, and we have some scans that are looking for proxies to find websites used to send SMS:
https://sms-activate.org
Not properly securing SMS gateways or credentials used to connect to SMS services could result in significant costs if an attacker abuses the service. It may also make the phone number unusable, as telecom providers and end users will block it. This may also result in reputational damage, and you will likely have to use a different phone number after it has been abused.
[1] https://github.com/iAditya-Nanda/SMS_Bomber
—
Johannes B. Ullrich, Ph.D. , Dean of Research, SANS.edu
Twitter|
(c) SANS Internet Storm Center. https://isc.sans.edu Creative Commons Attribution-Noncommercial 3.0 United States License.
SRUM-DUMP Version 3: Uncovering Malware Activity in Forensics, (Sun, Apr 27th)
body { font-family: Arial, sans-serif; line-height: 1.6; margin: 20px; }
h1, h2, h3 { color: #333; }
a { color: #007bff; text-decoration: none; }
a:hover { text-decoration: underline; }
table { border-collapse: collapse; width: 100%; margin: 20px 0; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
code { background-color: #f4f4f4; padding: 2px 4px; border-radius: 4px; }
pre { background-color: #f4f4f4; padding: 10px; border-radius: 4px; }
SRUM-DUMP Version 3: Uncovering Malware Activity in Forensics
For digital forensics and incident response professionals, extracting precise evidence from Windows systems is critical to understanding and mitigating threats. I’m excited to introduce SRUM-DUMP Version 3, a powerful forensic tool I’ve developed to analyze the Windows System Resource Usage Monitor (SRUM) database. Available on GitHub at SRUM-DUMP Repository, this version offers significant improvements, including a user-friendly GUI and customizable output. In this post, I’ll guide you through using SRUM-DUMP v3’s GUI to investigate a scenario where malware (malware.exe
) exfiltrates intellectual property over a wireless network. We’ll explore the 3-step wizard, customize the analysis to highlight malware.exe
, and examine where it appears in the output spreadsheet and what each tab reveals about the incident.
What is SRUM-DUMP Version 3?
SRUM-DUMP v3 is designed to extract and analyze data from the SRUM database (C:WindowsSystem32srusrudb.dat
), which logs system resource usage for up to 30 days. This database is a treasure trove for incident response, capturing details about application executions and network activity. Key features of v3 include:
- 3-step Wizard for Rapid Analysis: Select the output directory,
srudb.dat
andSOFTWARE
registry key and you’re off! - Customizable Configuration: A short analysis generates a
srum_dump_config.json
file allowing you to highlight suspicious terms, map network interfaces, and format output. - Automated Artifact Detection: Editing the
srum_dump_config.json
lets you tag suspect processes, users, and networks before the analysis begins. - XLSX Analysis: All of the artifacts are tagged, colorized, calculated, filtered, and placed into an XLSX file for easy analysis.
Scenario: Malware Exfiltrating Intellectual Property
Imagine an attacker compromises a Windows workstation, deploying malware.exe
to steal sensitive documents over a wireless network. The malware runs as an application, quietly exfiltrating data to a remote server. There is no EDR or application logging to be found but you must determine what was stolen and how. The incident response team acquires SRUDB.dat
and the SOFTWARE registry hive (C:WindowsSystem32configSOFTWARE
) and uses SRUM-DUMP v3 to analyze the evidence.
Using SRUM-DUMP v3’s GUI: Step-by-Step
SRUM-DUMP v3’s GUI streamlines the analysis process through a 3-step wizard, followed by configuration customization and result generation.
Step 1: Launch the 3-Step Wizard
- Launch the Tool: Run the prebuilt executable, available from the Releases page.
- Select an Output Directory: Choose an empty directory where the tool will save the Excel spreadsheet and configuration file.
- Select the SRUDB.DAT File: Locate
SRUDB.dat
. Either from your forensics image or atC:WindowsSystem32srusrudb.dat
on a live system. - Select the SOFTWARE Registry Hive (Optional): Provide the SOFTWARE hive to enrich network data, such as mapping interface LUIDs to SSIDs (e.g., “CorporateWiFi”).
If you selected files that are locked by the OS on live systems, srum-dump will extract the locked files through the Volume Shadow Copies. The files are analyzed and a configuration file is built containing all of the users, network, and processes from the selected files.
Step 2: Customize the Configuration
- After selecting files, SRUM-DUMP processes the SRUM database and generates an
srum_dump_config.json
file. - Click “EDIT” to open the configuration file.
- Modify the “dirty_words” section to highlight suspect processes (
malware.exe
in this example )
{
"dirty_words": {
"malware.exe": "highlight-red"
}
}
- This ensures any instance of
malware.exe
in the output is highlighted in red. - Optionally, add additional tags to suspicious users, processes, and applications. For example, if we need to (markb) was a compromised user and "CorporateWifi" was a suspicious wifi network you could add tags to the tables in
srum_dump_config.json
file.
{
"SRUDbIdMapTable": {
"3": "S-1-5-21-1234567890-0987654321-1234567890-1001 (markb) - CompromisedUser"
},
"network_interfaces": {
"268435498": "CorporateWiFi - SuspectWifi"
}
}
- Save the configuration file and click “CONFIRM”.
Step 3: Generate and Review the Spreadsheet
- Click “CONTINUE” to run the analysis with the customized configuration.
- A progress dialog appears, and once complete, the tool saves an updated Excel spreadsheet in the output directory.
- Open the spreadsheet to examine the results.
Where Does malware.exe
Appear?
The Excel spreadsheet contains multiple tabs, each corresponding to a SRUM database table. For this scenario, we will examine just two of the locations where malware.exe
will appear:
Tab Name | Description | Relevance to malware.exe |
---|---|---|
Application Timeline | Logs application executions, including executable names, user SIDs, timestamps, and resource usage. | Directly lists malware.exe in the AppId column, highlighted if configured. |
Network Data | Records network activity, including bytes sent/received, interface LUIDs, and timestamps. | Indirectly relevant by showing network activity during malware.exe ’s execution. |
Application Timeline Tab
- Content: Each row represents an application execution event over the past 30 days.
- Where
malware.exe
Appears: In theAppId
column, rows containingmalware.exe
will be highlighted in red (based on the “dirty_words” configuration). - Key Columns:
AppId
: The application’s identifier (e.g.,malware.exe
).UserSid
: The security identifier of the user running the application, mappable to a username (e.g., “CompromisedUser”).TimeStamp
: The UTC date and time of execution (e.g.,2025-04-15 02:00:00
).CycleTime
: CPU usage, indicating the malware’s processing intensity.WorkingSetSize
: Memory usage, which may reveal unusual patterns.
- Insights for the Incident:
- Confirms
malware.exe
was executed, providing a timeline of its activity. - Identifies the user account involved, aiding in attribution.
- Reveals resource consumption, suggesting whether the malware was performing tasks like data encryption or exfiltration.
- Confirms
Network Data Tab
- Content: Each row represents a network activity event, detailing data transfers across interfaces.
- Relation to
malware.exe
: Whilemalware.exe
isn’t listed directly, you can correlate timestamps with the Application Timeline tab to identify network activity during its execution. - Key Columns:
InterfaceLuid
: Identifies the network interface (e.g., wireless adapter). With the SOFTWARE hive, this may be mapped to an SSID like “CorporateWiFi.”BytesSent
andBytesRecvd
: Quantities of data transferred (e.g., 500 MB sent).TimeStamp
: When the activity occurred (e.g.,2025-04-15 02:00:00
).
- Insights for the Incident:
- High
BytesSent
values duringmalware.exe
’s execution suggest data exfiltration. - The SSID mapping confirms the use of a specific wireless network, aligning with the scenario.
- Timestamps link network activity to the malware’s runtime, strengthening evidence of its role.
- High
Correlating Evidence
To reconstruct the incident:
- Identify
malware.exe
Activity: In the Application Timeline tab, note timestamps whenmalware.exe
was active (e.g.,2025-04-15 02:00:00
). - Check Network Activity: In the Network Data tab, look for high
BytesSent
on the wireless interface at matching timestamps. - Build the Timeline: Combine these findings to show that
malware.exe
executed and simultaneously sent large amounts of data, confirming intellectual property theft.
For example:
- Application Timeline:
malware.exe
ran at2025-04-15 02:00:00
with highCycleTime
. - Network Data: 500 MB of
BytesSent
on “CorporateWiFi” at2025-04-15 02:00:00
.
This correlation provides compelling evidence of the malware’s actions.
Getting Started
Download the prebuilt executable from the Releases page and follow the GUI steps outlined above. For advanced configuration options, consult the Configuration File Documentation.
SRUM-DUMP v3 empowers you to tackle malware investigations, insider threats, and system anomalies with precision, making it an indispensable tool for modern incident response.
Learn More
- Learn more about SRUM Windows Forensics Analysis FOR500
- Let me teach you to automate Infosed with python! Automating Infosec With Python
- Or develop more advanced infosec tools with Python Advanced Infosec Automation
- How about an introduction to Linux! Linux Security for Infosec Professionals
- Mark Baggett's YouTube Channel
- Connect with me on LinkedIn
I'm teaching at the following events. Come check it out!
- SEC673 ADVANCED Python in Miami, FL June 2, 2025
- SEC573 at SANSFire in Baltimore, MD July 14, 2025
- SEC573 in Melbourne, VIC AU August 17, 2025
- SEC573 in Las Vegas, NV September 22, 2025
(c) SANS Internet Storm Center. https://isc.sans.edu Creative Commons Attribution-Noncommercial 3.0 United States License.
Steganography Analysis With pngdump.py, (Sat, Apr 26th)
I like it when a diary entry like "Example of a Payload Delivered Through Steganography" is published: it gives me an opportunity to test my tools, in particular pngdump.py, a tool to analyze PNG files.
A PNG file consists of a header followed by chunks. pngdump.py shows this (sample c2219ddbd3456e3df0a8b10c7bbdf018da031d8ba5e9b71ede45618f50f2f4b6):
The IHDR chunk gives us information about the image: it's 31744 pixels wide and 1 pixel high. That's already unusual!
There are 8 bits and the colortype is 6. That's RGBA (Red, Green, Blue and Alpha/Transparency). So there are 4 channels in total with a resolution of 8 bits, thus 4 bytes per pixel.
The IDAT chunk contains the compressed (zlib) image: there's only one IDAT chunk in this image. And the line filter is None: this means that the pixel data is not encoded.
So let's take a look at the decompressed raw pixel data:
We see the letters M and Z: these letters are characteristic for the header of a PE file.
And a bit further we see the letters "This program …".
So it's clear that a PE file is embedded in the pixel data.
Every fourth byte is a byte of the PE file, and the first byte of the PE file is the second byte of the pixel data: so the PE file is embedded in the second channel of the pixel data.
We can select these bytes with a tool like translate.py, that takes a Python function to manipulate the bytes it receives.
data[1::4] is a Python slice that starts with the second byte (position 1), ends when there is no more data, and selects every fourth byte (a step of 4). This allows us to extract the second channel:
pngdump.py's option -d performs a binary dump, piping the raw pixel data into translate.py. translate.py's option -f reads all the data in one go (by default, translate.py operates byte per byte). lambda data: data[11:4] is a Python function that takes the raw pixel data as input (data) and returns the bytes of the second channel via a Python slice that selects every fourth byte starting with the second byte of the raw pixel data.
Finally, the extracted PE file is piped into file-magic.py to identify the file type: it is a .NET file, as Xavier explained.
We can also check that it is a PE file with a tool like pecheck.py:
And we can calculate the hashes with hash.py to look up the file on VirusTotal:
This is the SHA256 of the extracted PE file: 8f4cea5d602eaa4e705ef62e2cf00f93ad4b03fb222c35ab39f64c24cdb98462.
It's clear that the steganography works in this example: 0 detections for the PNG file on VirusTotal, and 49 detections for the embedded PE file.
Didier Stevens
Senior handler
blog.DidierStevens.com
(c) SANS Internet Storm Center. https://isc.sans.edu Creative Commons Attribution-Noncommercial 3.0 United States License.
Example of a Payload Delivered Through Steganography, (Fri, Apr 25th)
In this diary, I’ll show you a practical example of how steganography is used to hide payloads (or other suspicious data) from security tools and Security Analysts’ eyes. Steganography can be defined like this: It is the art and science of concealing a secret message, file, or image within an ordinary-looking carrier—such as a digital photograph, audio clip, or text—so that the very existence of the hidden data is undetectable to casual observers (read: security people). Many online implementations of basic steganography allow you to embed a message (a string) into a picture[1].
Honeypot Iptables Maintenance and DShield-SIEM Logging, (Wed, Apr 23rd)
It's 2025… so why are obviously malicious advertising URLs still going strong?, (Mon, Apr 21st)
While the old adage stating that “the human factor is the weakest link in the cyber security chain” will undoubtedly stay relevant in the near (and possibly far) future, the truth is that the tech industry could – and should – help alleviate the problem significantly more than it does today.
RedTail, Remnux and Malware Management [Guest Diary], (Wed, Apr 16th)
Online Services Again Abused to Exfiltrate Data, (Tue, Apr 15th)
If Attackers can abuse free online services, they will do for sure! Why spend time to deploy a C2 infrastructure if you have plenty of ways to use "official" services. Not only, they don't cost any money but the traffic can be hidden in the normal traffic; making them more difficult to detect. A very popular one was anonfiles[.]com. It was so abused that they closed in 2023![1]. A funny fact is that I still see lot of malicious scripts that refer to this domain. Of course, alternatives popped up here and there, like anonfile[.]la[2].