Myles Nieman
← All writeups

Lantern

Overview

Lantern is a hard Linux box that chains SSRF through an internal web app vulnerability to achieve remote code execution via a Blazor component backdoor. The host runs a Skipper reverse proxy on port 80 that is vulnerable to CVE-2022-38580 (SSRF via the X-Skipper-Proxy header), which is used to scan internal ports and reach a Blazor WebAssembly application on port 5000 not accessible from the outside. Decompiling the app’s DLL reveals base64-encoded credentials for the admin user. Logging into the internal Blazor app exposes the Flask web server source code, which contains a send_file call on /PrivacyAndPolicy that accepts attacker-controlled filename parameters — a path traversal primitive. A separate component-loading endpoint executes uploaded .dll files as Razor components; a crafted DLL reads tomas’s SSH private key and returns it through the rendered component. From there, procmon analysis of a root-owned process provides the final escalation path.

Path: CVE-2022-38580 SSRF → internal Blazor app → DLL credential extraction → /PrivacyAndPolicy path traversal → malicious Blazor DLL → tomas SSH key → root binary analysis.

Enumeration

$ nmap -p- -A <target>

Nmap shows SSH, port 80 (Skipper proxy), and port 3000

Three ports of interest: 22 (SSH), 80 (Skipper reverse proxy), and 3000 (a login page).

Port 3000 presents a login page

Port 80 has a /vacancies upload form

Upload form accepts resume files on /vacancies

Foothold — CVE-2022-38580 SSRF

Skipper’s X-Skipper-Proxy header is vulnerable to server-side request forgery via CVE-2022-38580:

CVE-2022-38580 advisory — SSRF via X-Skipper-Proxy header

Using the header to probe internal HTTP ports finds additional services not visible externally:

SSRF port scan reveals additional internal ports

Port 5000 internally serves a Blazor WebAssembly application — InternalLantern:

Internal Lantern Blazor app accessible via SSRF on port 5000

Extracting credentials from the DLL

Blazor WebAssembly apps serve their assemblies from /_framework/. The InternalLantern.dll is listed among the static assets:

_framework directory listing showing InternalLantern.dll

The DLL is pulled through the SSRF:

Downloading InternalLantern.dll via the Skipper SSRF

Decompiling reveals base64-encoded credential fields. Decoding them in CyberChef:

Base64 credential fields extracted from InternalLantern.dll

CyberChef decoding the base64 fields to plaintext credentials

admin:AJbFA_Q@925p9ap#22

Credential Access — Internal Blazor App

Logging into the internal app with the recovered credentials:

Successful login to the internal Lantern application

The app exposes the Flask web server’s source code. Two endpoints are particularly interesting:

/PrivacyAndPolicy — path traversal via unsanitized lang and ext parameters:

@app.route('/PrivacyAndPolicy')
def sendPolicyAgreement():
    lang = request.args.get('lang')
    file_ext = request.args.get('ext')
    try:
        return send_file(f'/var/www/sites/localisation/{lang}.{file_ext}')
    except:
        return send_file(f'/var/www/sites/localisation/default/policy.pdf', 'application/pdf')

/submit (vacancies upload) — files are stored in the uploads/ directory with the name constructed from form fields.

There is also a component-loading endpoint that executes DLLs placed in /opt/components/:

Component loader endpoint that executes DLLs from /opt/components

Source view of the component execution endpoint

User — Malicious Blazor Component DLL

The plan: compile a Blazor ComponentBase that reads tomas’s SSH private key on BuildRenderTree, upload it to the vacancies form so it lands in uploads/, traverse it into /opt/components/ with the path traversal on /PrivacyAndPolicy, then trigger the component loader to execute it.

The DLL source:

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
using System.IO;

namespace exploit
{
    public class Component : ComponentBase
    {
        protected override void BuildRenderTree(RenderTreeBuilder builder)
        {
            base.BuildRenderTree(builder);
            string file = File.ReadAllText("/home/tomas/.ssh/id_rsa");
            builder.AddContent(0, file);
        }
    }
}

After resolving dependencies, the compiled DLL appears in the uploads directory:

Compiled exploit DLL visible in the uploads folder

Adjusting the filename via the upload form to match what the component loader expects:

Renaming the DLL through the upload form parameters

Triggering the component loader:

Triggering the Blazor component loader endpoint

Component executes and returns content — working toward key exfil

Uploading through the correct endpoint with adjusted filename:

Second upload attempt through the component upload path

Filename adjusted to fit the component naming requirement

The component executes and the rendered output contains tomas’s private key:

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gt
...
-----END OPENSSH PRIVATE KEY-----

Saving the key and connecting:

SSH private key exfiltrated from the Blazor component render

$ chmod 600 id_rsa
$ ssh -i id_rsa tomas@<target>

SSH session as tomas established

Privilege Escalation — Root Binary Analysis

Process monitoring (procmon / watching running processes) identifies a binary executed regularly by root:

procmon output showing a root-owned process of interest

Inspecting the binary:

Binary inspection — checking for exploitable behavior

Further analysis of the root binary

Root binary behavior identified

Root

Exploiting the identified behavior in the root binary produces a root shell:

Root shell obtained via the identified binary vulnerability

Takeaways

  • Skipper SSRF (CVE-2022-38580) turns an external proxy into an internal port scanner — any HTTP service bound to localhost becomes reachable; this is a quick way to find Blazor, Spring, or other internal admin apps.
  • Blazor WebAssembly ships its full assembly to the browser — credentials, logic, and endpoints that a developer thought were “internal” are all present in the downloadable DLL, making decompilation a high-yield recon step against WASM apps.