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].

Let’s have a look at the sample I found. Because it’s a .Net binary, it can be easily decompiled. But, because the source code is easily accessible, many malware are often obfuscated. A classic technique is to use UFT-16 in functions, classes, variable names, etc. In the following example, the registry key name is obfuscated:

Another common behaviour of malware in .Net is to use reflective code loading techniques. Reflective code loading is the ability of a running program to inspect, load, and use code—classes, functions, libraries, even entire assemblies—that was not statically linked or explicitly referenced at compile time. Instead, the program decides at runtime what to bring into memory and how to invoke it. Therefore, when you reverse a .Net program, it’s a good idea to search for methods like .Load(), .LoadFrom() or .LoadFile(). This may indicate that more code will be loaded (passed as a parameter).

That’s what I found in this sample, but there were other interesting strings: “Bitmap”, “WebClient”, or “OpenRead”:

A Bitmap payload (read: a picture) is downloaded from a URL. Once deobfuscated, we get:

hxxps://i[.]ibb[.]co/LgqktNn/freemaosnry[.]png

The deobfuscating function is here:

Once the picture has been downloaded, a loop will process all the pixels from the top row and extract the “red” component value. All the values are added in a byte array to rebuild the next payload. We can reproduce this with a few lines of Python:

#!/usr/bin/env python3
import sys
from PIL import Image

def main():
    img = Image.open(“freemaosnry[.]png”).convert("RGBA")
    w, h = img.size
    pix = img.load()

    with open("payload.tmp", "wb") as f:
        for y in range(h):
            for x in range(w):
                r, g, b, a = pix[x, y]
                f.write(bytes([r]))

if __name__ == "__main__”:
    main()

Let’s have a look at the picture:

remnux@remnux:/MalwareZoo/20250418$ file freemaosnry.png
freemaosnry.png: PNG image data, 31744 x 1, 8-bit/color RGBA, non-interlaced

Based on the file details, we should get a payload of 31744 bytes:

remnux@remnux:/MalwareZoo/20250418$./decode_pic.py
remnux@remnux:/MalwareZoo/20250418$ ls -al payload.tmp
-rwx------ 1 501 dialout 31744 Apr 18 08:27 payload.tmp*
remnux@remnux:/MalwareZoo/20250418$ file payload.tmp
payload.tmp: PE32 executable (GUI) Intel 80386 Mono/.Net assembly, for MS Windows

Bingo! We have the next payload that, during execution, has been generated in memory. It is now ready to be invoked with:

AppDomain.CurrentDomain.Load(array).EntryPoint.Invoke(null, null);

What about this malware? The initial PE file was named “voice_recording.bat” (SHA256:ce77b1bc3431139358e2a70fa5f731d1be127e77efe8b534df5ccde59083849d[2]). It belongs to the XWorm family and has the following config:

{
    “c2": [
        "cryptoghost[.]zapto[.]org"
    ],
    "family": "latentbot"
}
{
    "attr": {
        "install_file": "MasonUSB.exe"
    },
    "rule": "Xworm",
    "family": "xworm"
}

Happy hunting!

[1] https://manytools.org/hacker-tools/steganography-encode-text-into-image/
[2] https://www.virustotal.com/gui/file/ce77b1bc3431139358e2a70fa5f731d1be127e77efe8b534df5ccde59083849d/detection

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

(c) SANS Internet Storm Center. https://isc.sans.edu Creative Commons Attribution-Noncommercial 3.0 United States License.

Leave a Reply

Your email address will not be published. Required fields are marked *