Icmptunnel is a tool to tunnel IP traffic within ICMP echo request and response (ping) packets. It’s intended for bypassing firewalls in a semi-covert way, for example when pivoting inside a network where ping is allowed. It might also be useful for egress from a corporate network to the Internet, although it is quite common for ICMP echo traffic to be filtered at the network perimeter.
While there are a couple of existing tools which implement this technique, icmptunnel provides a more reliable protocol and a mechanism for tunneling through stateful firewalls and NAT.
The project page is located at: https://github.com/jamesbarlow/icmptunnel.
To clone the code using Git:
# git clone https://github.com/jamesbarlow/icmptunnel.git
To build the code, run 'make' from the project directory.
The tool is Linux only. First, disable ICMP echo responses on both the client and server. This prevents the kernel from responding to ping packets itself.
# echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
On the server-side, start icmptunnel in server mode, and assign an IP address to the new tunnel interface.
# ./icmptunnel –s
opened tunnel device: tun0
# /sbin/ifconfig tun0 10.0.0.1 netmask 255.255.255.0
On the client-side, point icmptunnel at the server, and assign an IP address.
# ./icmptunnel <server>
opened tunnel device: tun0
# /sbin/ifconfig tun0 10.0.0.2 netmask 255.255.255.0
At this point, you should have a functioning point-to-point tunnel via ICMP packets. The server side is 10.0.0.1, and the client-side is 10.0.0.2. On the client, try connecting to the server via SSH:
# ssh firstname.lastname@example.org
To use the remote server as an encrypted SOCKS proxy:
# ssh -D 8080 -N email@example.com
Now point your web browser at the local SOCKS server.
Ping tools work by sending an ICMP echo request packet to the target, with a segment of random data appended as a payload. The receiving system copies this payload into an ICMP echo response packet, and sends it back to the source. An identifier and sequence number is used to match request and response packets.
The Windows and Linux ping tools both send payloads of 64 bytes by default, and this is what is commonly seen in packet captures, but the protocol actually allows for up to 64 kb.
To tunnel data, we designate one endpoint to be a client, and the other to be a server. The client packs IP frames into ICMP echo request packets and sends them to the server, while the server uses matching ICMP echo response packets for return traffic. To an observer, this appears to be a sequence of matching ping requests and replies.
Stateful Firewalls and NAT
An issue arises when tunneling through a stateful firewall, or through a NAT device. The device will filter ping responses which do not have a matching request. For asymmetric connections which have much more traffic from the server to the client than vice-versa, the device is likely to block many of the ping responses, since there are more responses than requests.
The icmptunnel tool has a mechanism to get around this. The client periodically sends empty ICMP echo request packets as carriers, to punch holes through the stateful firewall or NAT. These are recorded in the firewall state table, and allow a response packet back through. By keeping several carrier packets in flight at a time, the client maintains a ‘packet window’ which the server can use to send traffic back.
On both Linux and Windows, user-mode programs require elevated privileges to interact with raw sockets. This is a drawback of ICMP tunneling – if you want to use it to pivot within a network, you need to have root or local administrator privileges on both ends of the connection.
Some thoughts on detecting malicious ICMP traffic:
Rather than a generic tunnel which can transport any type of traffic, it might be interesting to experiment with a dedicated C2/pivoting tool using ICMP tunneling.
Using ICMP to transport arbitrary protocols like HTTP is noisy, as we are potentially generating a huge number of ping packets, and often need to increase the payload size beyond the normal to provide a usable MTU. With a specialised C2 protocol using simple control signals we could take advantage of a much lower packet rate, and keep to the expected payload size of 64 bytes. This would make the traffic almost indistinguishable from real ping traffic.
Additionally, the existing tool does not provide authentication or encryption. This is by design – it’s built to transport IP packets, with the assumption that if you want security you can run a secure protocol like SSH over it. A more specialised C2 tool would likely need this capability.