Hiding files in GIF comments

Firewall, IDS, IPS, Load Balancers, Proxies, Antivirus, MAC address filtering and no USB ports. A lot of companies are filtering the information/data that is getting into their network (and out of their network). But in the end the user wants to get information from the internet. Let’s face it: Text is information. So let’s use text to get a binary executable into the corporate network. While it’s relatively easy to convert text into binaries and back on Linux and Mac (thank you bash!), it was sometimes a pain in Windows until Powershell. As far as I know Powershell is available on all Windows 7 and newer machines.

This is not a new technique, it’s already in use, for example in the SET. I read a blogpost which explains exactly what we are doing here, I just wanted to try it myself and I changed the encoding from decimal to hex, which removes the necessity for a delimiter and makes the text data smaller in general. Additional I’ll show how to hide the information in a GIF image and how to extract it on a Powershell.

Let’s first convert our binary into text (hex encoding). So first prepare the text we want to put somewhere on the internet. Here is a small python one-liner that converts notepad.exe into the required format.

In Python on Windows:

.\python.exe -c "file('C:\\Users\\user\\Desktop\\notepad_hex.txt','wb').write(file('C:\\Windows\\notepad.exe','rb').read().encode('hex'))"

In Python on Unix:

python -c "file('/tmp/notepad_hex.txt','wb').write(file('/tmp/notepad.exe','rb').read().encode('hex'))"

If you open notepad_hex.txt now, you only see hexadecimal numbers:


That’s already the text version you can put on a website and you can access from your company network and your company desktop machine (eg. pastebin). If you can access the notepad_hex.txt on a web server directly, it’s probably better if you use the “save as” dialogue of your browser to store it (it’s quite a long hex string). As soon as your back in your company network, save the contents to a file. Let’s assume you saved it to C:\Users\user\Desktop\notepad_hex.txt

So let’s convert the text back to an executable in our Powershell. I just adopted the code from the blogpost:

[string]$hex = get-content -path C:\Users\user\Desktop\notepad_hex.txt
[Byte[]]$temp = $hex -split '([a-f0-9]{2})' | foreach-object { if ($_) {[System.Convert]::ToByte($_,16)}}
[System.IO.File]::WriteAllBytes("C:\Users\user\Desktop\notepad.exe", $temp)

You should have notepad.exe on your Desktop now. This will also work with other file formats, for example zip files, although much slower with increasing file size.

Of course there are other methods of smuggling data into the corporate network. For example if you prefer to put the text data into a picture, you can use ImageMagick (included in the Ubuntu repositories and Mac Ports) in a shell. So for example to put the hex data into a gif comment, use the following commands (first rename an image to black.gif):

python -c "file('/tmp/something_hex.txt','wb').write(file('/tmp/something.exe','rb').read().encode('hex'))"
hex=`cat /tmp/something_hex.txt`
convert -comment "$hex" black.gif black2.gif

Note that this method on the command line only works for small hex data. I got an “Argument list too long” error for notepad, so use this command instead if it is a big file:

convert -comment @/tmp/notepad_hex.txt black.gif notepad.gif

But how do we get the data out of the picture in our Powershell? Let’s have a look at the nice ASCII Art for the Comment Extension in the GIF89a format spec:

    c. Syntax.

    7 6 5 4 3 2 1 0        Field Name                    Type
0  |               |       Extension Introducer          Byte
1  |               |       Comment Label                 Byte

   |               |
N  |               |       Comment Data                  Data Sub-blocks
   |               |

0  |               |       Block Terminator              Byte

          i) Extension Introducer - Identifies the beginning of an extension
          block. This field contains the fixed value 0x21.

          ii) Comment Label - Identifies the block as a Comment Extension.
          This field contains the fixed value 0xFE.

          iii) Comment Data - Sequence of sub-blocks, each of size at most
          255 bytes and at least 1 byte, with the size in a byte preceding
          the data.  The end of the sequence is marked by the Block

          iv) Block Terminator - This zero-length data block marks the end of
          the Comment Extension.

So it basically says we have to look for 0x21FE and read the number of bytes specified in the first byte. Then read again the next byte to see how many bytes we have to read and so on. Let’s do that in a Powershell:

[string]$picture = get-content -path C:\Users\user\Desktop\notepad.gif
[string]$delimiter = [Convert]::ToChar(0x21)+[Convert]::ToChar(0xFE)
[string[]]$commentarray = $picture -split $delimiter,2
[string]$junk = $commentarray[1]
[string]$hex = ""
	[int]$length = [int][char]$junk.substring(0,1)
	$hex = $hex + $junk.substring(1,$length)
	$junk = $junk.substring($length+1)
	if($length -lt 255){
[Byte[]]$temp = $hex -split '([a-f0-9]{2})' | foreach-object { if ($_) {[System.Convert]::ToByte($_,16)}}
[System.IO.File]::WriteAllBytes("C:\Users\user\Desktop\notepad.exe", $temp)

I feel like Powershell and me could get good friends. If you want to try it yourself, save the following notepad.gif on your Desktop, change the username in the paths of the code above and copy/paste it into a Powershell.