Starting with the default nmap scan
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
Adding it to the /etc/hosts
file
We get the default index page
Following standard methodology, checking source code led us to nowhere.
Checking skipper proxy and identifying what it does.
The full documentation and source code can be found here
Here is a more in depth documentation of what it does and its services
Searching for vulnerabilities, found this link
#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
We get redirected to a login form
Following standard methodology, checking source code
This time we get a hit ! Blazor
identified
Searching about Balzor
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
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
Firing burpsuite
Making an empty pdf to test the form
Intercepting the request
Sending back to the repeater
Applying the exploit we found, adding the X-Skipper-Proxy
header to point to an internal IP
We can see a success
Trying to access a random port we get an error
Focusing on the default port where blazor works and trying to access it
We can access the internal application.
Checking the source code, we get a path
Accessing it on burpsuite
We get a hit!
Going through Balzor
documentation and digging on how to enumerate it, we come across a finding
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.
All of those DLL are default ones except for the last one titled InternalLantern.dll
Downloading the file through the path \_framework/InternalLantern.dll
The file is a .NET binary
Decompiling the application through DotPeek
and analyzing it
We can find base64 encoded strings where we saved in a file
After decoding them, we can see credentials popping out
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
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
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
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.
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
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
Step two was to go to the application and upload it
capturing the request with burpsuite
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
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
Now we will encode it back to the blazor’s format and send it to the request
Sending the request and close the intercept after it, we can see a success message
When trying to call our malicious payload we get an error unrecognized dll format
we can see why when we look at this
The difference between our DLL and the DLL accepted by the application is clear. We need to make a payload with the same specification
dotnet
latest versionrev_project
in the Class1.cs
file, we add this reverse shell payload
Then compile it. We get a DLL binary in this specific file path
We can check the file now it will be similar to the one the application uses
Doing the same steps and upload it
But still we get an error when trying to access it.
To solve the issue, I went through multiple steps
dotnet
version 6dotnet add package Microsoft.AspNetCore.Components --version 6.0.0;
dotnet add package Microsoft.AspNetCore.Components.Web --version 6.0.0;
Uploading
Now trying to run the payload
We finally get a hit!!
Reading the ssh private key of the user tomas and logging in
Following our standard methodology, the first thing we check is sudo permissions
Checking the usage of this binary
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
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
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
This is a sqlite DB file
Will send it to my machine for analysis
Runing sqlite3 to check the content of the file we can see some tables
Reading the content of ebpf
table
We can see a large group of columns. We need to understand what are the columns representing
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
Taking the output and forwarding to CyberChef to decode it from HEX
We get a very strange output.
Downloading the output and then use cat
to display the standard output from the file
We can fnd something being written into the screen we can guess it to be the root password
root:Q3Eddtdw3pMB