Lantern HTB writeup

Walkethrough for the Lantern HTB machine.

Posted by xtromera on August 25, 2024 · 17 mins read

Report

Starting with the default nmap scan nmap Discovering ports 22, 80 Skipper proxy service running and 3000 with an unidentified service
Accessing the service on port 80 we are redirected to a domain lantern.htb nmap

Adding it to the /etc/hosts file

We get the default index page nmap

Following standard methodology, checking source code led us to nowhere.
Checking skipper proxy and identifying what it does. nmap The full documentation and source code can be found here
Here is a more in depth documentation of what it does and its services nmap

Searching for vulnerabilities, found this link nmap

#Exploit Title: X-Skipper-Proxy v0.13.237 - Server Side Request Forgery (SSRF)
#Date: 24/10/2022
#Exploit Author: Hosein Vita & Milad Fadavvi
#Vendor Homepage: https://github.com/zalando/skipper
#Software Link: https://github.com/zalando/skipper
#Version: < v0.13.237
#Tested on: Linux
#CVE: CVE-2022-38580


Summary:

Skipper prior to version v0.13.236 is vulnerable to server-side request forgery (SSRF). An attacker can exploit a vulnerable version of proxy to access the internal metadata server or other unauthenticated URLs by adding an specific header (X-Skipper-Proxy) to the http request.


Proof Of Concept:

1- Add header "X-Skipper-Proxy"  to your request
2- Add the aws metadata to the path

GET /latest/meta-data/iam/security-credentials HTTP/1.1
Host: yourskipperdomain.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36
X-Skipper-Proxy: http://169.254.169.254
Connection: close




Reference:
https://github.com/zalando/skipper/security/advisories/GHSA-f2rj-m42r-6jm2

Now checking our unidentified web application on port 3000 nmap

We get redirected to a login form
Following standard methodology, checking source code nmap

This time we get a hit ! Blazor identified
Searching about Balzor nmap

A .NET framework on a linux system… interesting
Following this link we can see the default structure of the entire framework.
While searching, came across the default ports that blazor uses and it is 5000 nmap

On our initial enumeration, this port was closed. Remembering our SSRF vulnerability, we get back to port 80
Getting back to our webpage, clicking on vacancies, a form submission can be identified nmap

Firing burpsuite nmap Making an empty pdf to test the form nmap Intercepting the request nmap Sending back to the repeater nmap Applying the exploit we found, adding the X-Skipper-Proxy header to point to an internal IP nmap We can see a success
Trying to access a random port we get an error nmap Focusing on the default port where blazor works and trying to access it nmap
We can access the internal application.
Checking the source code, we get a path nmap
Accessing it on burpsuite nmap We get a hit!
Going through Balzor documentation and digging on how to enumerate it, we come across a finding nmap The blazor.boot.json file located in the \_framework directory where it contains a list of applications and DLL to be downloaded that the application uses. nmap
All of those DLL are default ones except for the last one titled InternalLantern.dll
nmap
Downloading the file through the path \_framework/InternalLantern.dll
The file is a .NET binary nmap
Decompiling the application through DotPeek and analyzing it nmap
We can find base64 encoded strings where we saved in a file nmap
After decoding them, we can see credentials popping out nmap
admin:AJbFA_Q@925p9ap#22
Getting back to our web application running on port 3000 and giving the credentials we found, logged in as admin nmap
The application fetch the file Logs and displays it here
It displays access.log but log poisoning cannot be established as it does not use php files
Trying an arbitrary value to test the application nmap
it appends .dll to the name we put and run it from the /opt/components directory
Tried giving it ../../../../../test but receive an exception error as the application couldn’t handle path traversal here.
The application has an upload form where it uploads it to /var/www/sites/lantern.htb/static/images by default nmap
In the files link, w can see information disclosure as we can see the full path of the application, the structure and even the content. nmap
Checking the ‘app.py’ code

from flask import Flask, render_template, send_file, request, redirect, json
from werkzeug.utils import secure_filename
import os

app=Flask("__name__")

@app.route('/')
def index():
    if request.headers['Host'] != "lantern.htb":
        return redirect("http://lantern.htb/", code=302)
    return render_template("index.html")

@app.route('/vacancies')
def vacancies():
    return render_template('vacancies.html')

@app.route('/submit', methods=['POST'])
def save_vacancy():
    name = request.form.get('name')
    email = request.form.get('email')
    vacancy = request.form.get('vacancy', default='Middle Frontend Developer')

    if 'resume' in request.files:
        try:
            file = request.files['resume']
            resume_name = file.filename
            if resume_name.endswith('.pdf') or resume_name == '':
                filename = secure_filename(f"resume-{name}-{vacancy}-latern.pdf")
                upload_folder = os.path.join(os.getcwd(), 'uploads')
                destination = '/'.join([upload_folder, filename])
                file.save(destination)
            else:
                return "Only PDF files allowed!"
        except:
            return "Something went wrong!"
    return "Thank you! We will conact you very soon!"

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

if __name__ == '__main__':
    app.run(host='127.0.0.1', port=8000)

We can spot multiple vulnerabilities here but lets focus on this specific code block

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

the /PrivacyAndPolicy directory has 2 parameters. lang and ext
Where, if set, will return a file that is located inside the /var/www/sites/localisation and append to it . and the extension from ext parameter.
This procedure can be easily bypassed and fetching the famous /etc/passwd file nmap
nmap
We can spot the user tomas
Getting back to our upload form, if we can upload a malicious dll file and then execute it like the Logs where executed, we can get a reverse shell.
Step one was to create our malicious DLL nmap
Step two was to go to the application and upload it
capturing the request with burpsuite nmap
The post data is obfuscated, after digging, found this link that tells us how to decode the post data request from blazor to json format
installing the BlazorTrafficProcessor extension from burpsuite and sending the request body nmap
We can see in clear text now the body with the file name being shown
Changing the file to make it ../../../../../opt/components/reverse.dll nmap
Now we will encode it back to the blazor’s format and send it to the request
nmap
Sending the request and close the intercept after it, we can see a success message
nmap
When trying to call our malicious payload we get an error unrecognized dll format we can see why when we look at this nmap

The difference between our DLL and the DLL accepted by the application is clear. We need to make a payload with the same specification

  1. Installed dotnet latest version
  2. make a new directory called it rev_project
  3. cd in there
  4. creating a new project

nmap

in the Class1.cs file, we add this reverse shell payload nmap
Then compile it. We get a DLL binary in this specific file path nmap
We can check the file now it will be similar to the one the application uses nmap
Doing the same steps and upload it nmap
But still we get an error when trying to access it. To solve the issue, I went through multiple steps

  1. Installed dotnet version 6
  2. Lowered my estimations by only leaking the ssh private key instead of getting a whole reverse shell
  3. Installed the required packages

nmap

dotnet add package Microsoft.AspNetCore.Components --version 6.0.0;
dotnet add package Microsoft.AspNetCore.Components.Web --version 6.0.0;

Uploading nmap
Now trying to run the payload nmap
We finally get a hit!!
Reading the ssh private key of the user tomas and logging in nmap
nmap
Following our standard methodology, the first thing we check is sudo permissions nmap
Checking the usage of this binary nmap
We can see that it listen to a specific event and trace the system calls.
When logging in by SSH, we saw that the user had a mail. When reading it, it refers to an event being executed in the background by root.
We can check the background processes nmap
We found nano /root/automation.sh with PID 1714
Now run the command

sudo /usr/bin/procmon -p 1714

We will be prompted with the following screen nmap
wait for the screen to capture a good number of events and then press F6 to export it into a file and then F9 to exit
We can see the file being exported nmap
This is a sqlite DB file
nmap

Will send it to my machine for analysis
nmap

Runing sqlite3 to check the content of the file we can see some tables nmap

Reading the content of ebpf table
nmap

We can see a large group of columns. We need to understand what are the columns representing
nmap

We can see the ‘arguments’ column to be in Binary Large Object (BLOB) format so it will not be displayed on the standard output screen
Reading it in HEX format
nmap
Taking the output and forwarding to CyberChef to decode it from HEX
nmap
We get a very strange output.
Downloading the output and then use cat to display the standard output from the file
nmap
We can fnd something being written into the screen we can guess it to be the root password

root:Q3Eddtdw3pMB

nmap