code

Commodity .NET Packers use Embedded Images to Hide Payloads

Share with your network!

Most malware is distributed in "packed" form: typically an executable containing code to evade antivirus detection and sandboxes before extracting and executing the intended payload. 

There are many commodity packers written in Microsoft .NET, usually but not always containing malware also written in .NET. 

We discuss two prevalent such packers used to distribute a wide variety of malware but hiding the intended payload in images. 

Steganography 

Steganography is the technique of sending hidden messages in apparently innocent forms. For hiding data in images, the main techniques are: 

  • Store the hidden data at the end of an image file 
  • Store the hidden data within the image metadata (e.g., EXIF) 
  • Store the hidden data within the actual pixel data 

To be truly "hidden" the latter would arguably mean using only the least significant bits of the data so that the image appears "normal" when rendered. 

The packers discussed here generally use the entire image pixel data so aren't truly "hidden"; if they were displayed, the images would appear random. 

 "CyaX" packer 

In this packer, the .NET executable contains a square PNG image in a .NET resource, which is typically a large proportion of the whole file size. 

The image can be decoded to an intermediate executable, which contains a .NET resource which in turn can be decoded to the payload. Sometimes the intermediate executable uses an additional commodity packer such as ConfuserEx or .NET Reactor.  

Details 

The first stage payload is decoded from the Blue, Green, Red, and Alpha (BGRA) channels taking pixels in columns. Some versions use Red, Green, and Blue (RGB) channels instead. 

For example, in sample SHA256 - 026b38e8eb0e4f505dc5601246143e7e77bbd2630b91df50622e7a14e0728675: 

Figure 1: Image taken from sample SHA256: 026b38e8eb0e4f505dc5601246143e7e77bbd2630b91df50622e7a14e0728675 

Using channels BGRA from the image we get data starting: 

 

In general, the extracted data is then XORed with a short XOR key or the first 16 bytes of the data and possibly decompressed with gzip, yielding an intermediate stage .NET executable.    

For the above sample, the XOR key is (in hex) "74 43 74 17 74 02 74 23 74", which gives the executable: 

 

This intermediate stage is often itself packed with ConfuserEx, but after unpacking that, it contains a .NET resource which contains the payload, typically XORed with two keys:, a short (often truncated Unicode) one, followed by a 16-byte key stored at the start of the resulting file. 

In the above sample, the intermediate executable is packed with .NET Reactor. After deobfuscation with a tool such as de4dot, the deobfuscated executable contains a resource "2EJp1.resources" which starts: 

 

XORing with key "00 77 00 55 00 6c 00 59 00 71 00 79 00 4e" ("wUlYqyNZJIbjVN" in Unicode, truncated to half the length): 

 

  and then XORing with the first 16 bytes of the result gives the payload, Agent Tesla (a prevalent information stealer) in this case: 

 

In some early versions of this packer, this .NET resource was named "CyaX_Sharp.Properties.Resources.resources" hence the name we have given to this packer family. 

Gzip variant 

As mentioned above, some samples use the Red, Green, and Blue (RGB) channels, and some compress the intermediate executable with gzip. 

For example, in sample SHA256 - 083521fa4522245adc968b1b7dd18da29b193fd41572114c9d7dd927918234ea:   

Figure 2: Image taken from sample SHA256:  083521fa4522245adc968b1b7dd18da29b193fd41572114c9d7dd927918234ea 

the image uses RGB channels which decode to: 

  

XORing with key (in hex) "24 04 33" gives:

 

which is a 4-byte DWORD containing the uncompressed file size, followed by a gzip-ed file, starting with a 10-byte gzip header, which decompresses to the intermediate .NET executable: 

  

  This contains a .NET resource "d2o6x4FhIdl.resources" starting: 

 

which when XORed with keys "00 66 00 43 00 73 00 6b 00 62 00 67 00" ("fCskbgkLbLArI" in Unicode, truncated) and then "07 2e 8c d5 50 23 1b e3  be be 38 4f 0f 4b 8d ca" gives:

 

which contains the payload, Agent Tesla again.

Steganographic variant  

In a recent variation of this packer, the first stage payload is actually stored in a second PNG image extracted from the least significant bits of the Red, Green, and Blue channels in the first image, taking pixels in rows (so "proper" steganography in this case). The intermediate stage .NET executable is then extracted from the Blue, Green, Red, and Alpha channels of the second image with pixels taken in columns, without XOR this time. 

For example, in sample SHA256 – 04794ec7e7eb5c6611aada660fb1716a91e01503fb4703c7d2f2099c089c9017:  

 
Figure 3: Image taken from sample SHA256:  04794ec7e7eb5c6611aada660fb1716a91e01503fb4703c7d2f2099c089c9017 

the image has RGB channels and, taking pixels by rows first rather than columns, leads to: 

 

(There is also an Alpha channel, with all values set to 0xff.) 

Taking groups of 8 bytes and then the least significant bits in reverse order gives us (for example "ff 01 00 ff 01 00 fe 01" -> "10011011" -> 0x9b): 

 

This is a file size stored in a DWORD (0x1e09b) followed by the second PNG image. Using BGRA and columns first, this decodes to:  

 

 which contains a .NET resource "biGzxmYEphCl": 

  

which when XORed with "4c 00 6b 00 74 00 79 00 54 00 65 00 66 00 65 00" ("LktyTefe" in Unicode): 

 

gives the payload, which in this case is Remcos RAT. 

"Hectobmp" packer 

In this packer, the .NET executable contains typically several hundred small images in .NET resources, which each contain a part of the payload and need to be reassembled in the correct order. 

Earlier versions used the BMP file format, and later versions have switched to using PNG. The name we have given to this packer comes from "hecto-" from the metric system prefix for a hundred. 

Details 

 
Figure 4: .NET resources list (from ILSpy) 

For example, in sample SHA256 – 0091c6bdceecf3e0143b4eaaefca1cd56cbfdfc55f99c167f9dd1f3a48928bb5:  
Figure 5: First image taken from sample SHA256: 0091c6bdceecf3e0143b4eaaefca1cd56cbfdfc55f99c167f9dd1f3a48928bb5 

which contains 135 images, the first image decodes, using Green, Red and Blue channels, rows first, to: 

 

This includes the start of a Windows executable.

The size of the chunk extracted from each image is stored in the first four bytes (DWORD), 0x30d in this case, less 15, and the required chunk of data starts at the 6th byte. 

The chunks need to be assembled in numerical order of the resource names, which is different from the alphabetical order they appear in the file which is: 

  

and the order they are referenced in the .NET metadata which is: 

 

  The reassembled payload in this case is Loki Bot Stealer. 

In the following sample, SHA256 – 09c8cbd9cdfda1fcb7c6a051887213dc3e3ccf00a5877eca3d3e374f077b98d5, the images are BMPs and the first one looks like: 

 
Figure 6: Image taken from sample SHA256: 09c8cbd9cdfda1fcb7c6a051887213dc3e3ccf00a5877eca3d3e374f077b98d5 

The image decodes to the following, with chunk size highlighted in green, chunk data highlighted in yellow and blue: 

 

In this case, when assembled from the images, the payload is compressed using zlib Deflate, starting at byte 0xb0, highlighted in blue. 

Decompressing gives: 

which again is Agent Tesla in this case. 

Conclusion 

Generally, packers have different features that allow them to circumvent detection mechanisms by appearing as benign files, being difficult to reverse engineer, or incorporating sandbox evasion techniques. In this blog we've looked at two packers which use embedded images to hide the payload, one using a single image and the other using hundreds of them. These are just a few of the many tools threat actors have at their disposal to aid in distributing malware, collecting sensitive information, and gaining unauthorized access to systems.  

IOCs  

IOC 

Type 

Description 

026b38e8eb0e4f505dc5601246143e7e77bbd2630b91df50622e7a14e0728675 

SHA256 

CyaX PNG sample with channels BGRA 

c8c79ba04ab76c96db913f05b4b5bab36e7e0148fd72148df170a4be94d879a3 

SHA256 

 

Agent Tesla payload in 026b38e8eb0e4f505dc5601246143e7e77bbd2630b91df50622e7a14e0728675 

083521fa4522245adc968b1b7dd18da29b193fd41572114c9d7dd927918234ea 

SHA256 

 

CyaX PNG sample with gzipped data 

a6f7edd2654412c25d7c565cb5b52e1382799a8b86d6bc44e965b554f6344618 

SHA256 

 

Agent Tesla payload in 083521fa4522245adc968b1b7dd18da29b193fd41572114c9d7dd927918234ea 

04794ec7e7eb5c6611aada660fb1716a91e01503fb4703c7d2f2099c089c9017 

SHA256 

 

CyaX PNG sample with double steganography 

6d9c861bf6f1495a4bddc7c745eb5b504692b4d6eae31e89453f0829760b1b90 

SHA256 

 

Remcos RAT payload in 04794ec7e7eb5c6611aada660fb1716a91e01503fb4703c7d2f2099c089c9017 

0091c6bdceecf3e0143b4eaaefca1cd56cbfdfc55f99c167f9dd1f3a48928bb5 

SHA256 

 

Hectobmp sample with PNGs 

1180c158968faaf0a4951e9a0c59996f0fb29cdad9443aa2097efb5bc7f123f4 

SHA256 

 

Loki Bot payload in 0091c6bdceecf3e0143b4eaaefca1cd56cbfdfc55f99c167f9dd1f3a48928bb5 

09c8cbd9cdfda1fcb7c6a051887213dc3e3ccf00a5877eca3d3e374f077b98d5 

SHA256 

 

Hectobmp sample with BMPs 

 

c3b85d8291281d73cfdd8373cb2b32cdc4c3a602233f99ab3cbbd34bd4e3c99b 

SHA256 

 

Agent Tesla payload in 09c8cbd9cdfda1fcb7c6a051887213dc3e3ccf00a5877eca3d3e374f077b98d5 

References 

De4dot  
ILSpy  
Agent Tesla: A day in a life of IR, Full description of an Agent Tesla campaign using CyaX packer (steganographic variant) 

Subscribe to the Proofpoint Blog