Room Hacking with Powershell - TryHackMe (Offensive Pentesting Path)
Introducción
La room se encuentra en TryHackMe. Se trata de una máquina Windows donde tendremos que superar una serie de desafíos encontrando archivos y contenido con ayuda de comandos en Powershell. Esta será más una guía de la room que un walkthrough en sí, funcionando más como un cheatsheet de este.
Por cierto, nos hemos saltado toda la sección de Active Directory ya que no son máquinas que resolver como tal, sino guías para entender cómo enumerar y los tipos de ataque que se presentan en este tipo de entornos; la misma guía que da TryHackMe para cada room es suficiente y no vi necesario hacer entradas al respecto.
Índice
- Introducción
- Índice
- Basic Powershell Commands
- What is the location of the file “interesting-file.txt”
- Specify the contents of this file
- How many cmdlets are installed on the system(only cmdlets, not functions and aliases)?
- Get the MD5 hash of interesting-file.txt
- What is the command to get the current working directory?
- Does the path “C:\Users\Administrator\Documents\Passwords” Exist(Y/N)?
- What command would you use to make a request to a web server?
- Base64 decode the file b64.txt on Windows.
- Enumeration
- How many users are there on the machine?
- Which local user does this SID(S-1-5-21-1394777289-3961777894-1791813945-501) belong to?
- How many users have their password required values set to False?
- How many local groups exist?
- What command did you use to get the IP address info?
- How many ports are listed as listening?
- What is the remote address of the local port listening on port 445?
- How many patches have been applied?
- When was the patch with ID KB4023834 installed?
- Find the contents of a backup file.
- Search for all files containing API_KEY
- What command do you do to list all the running processes?
- What is the path of the scheduled task called new-sched-task?
- Who is the owner of the C:
- Basic Scripting Challenge
- Intermediate Scripting
Basic Powershell Commands
What is the location of the file “interesting-file.txt”
Para responder esta pregunta, debemos ejecutar un comando que busque en el sistema por archivos:
Get-ChildItem -Path 'C:\' -Recurse -ErrorAction SilentlyContinue | Where-Object -Property Name -Match 'interesting-file.txt'
Con esto le indicamos que busque en el directorio C: de manera recursiva e ignorando los errores de acceso que se pudiera encontrar un archivo cuyo nombre sea el indicado.
Specify the contents of this file
Para obtener el contenido de un archivo empleamos el comando:
Get-Content 'C:\Program Files\interesting-file.txt.txt'
How many cmdlets are installed on the system(only cmdlets, not functions and aliases)?
El comando que nos devuelve el listado de cmdlets instalados en el sistema es:
Get-Command
Sin embargo este nos devolverá todo lo que esté instalado, y la pregunta especifica que solo quiere los cmdlets. Con Get-Member obtenemos los parámetros que podemos solicitar del comando principal.
El parámetro que nos permitirá filtrar por lo que buscamos es CommandType. Solo le indicamos a la salida del comando anterior que busque por los tipos cmdlet únicamente:
Get-Command | Where-Object {$_.CommandType -eq 'cmdlet'} | Measure
Measure nos permite contar todos los resultados obtenidos.
Get the MD5 hash of interesting-file.txt
Buscamos por comandos que contengan en su nombre hash:
Get-Command *hash*
La herramienta que nos ayudará es GetFileHash. Mandamos llamar a Get-Help para ver cómo podemos indicarle el algoritmo de hasheo. Esto se realiza con el parámetro -Algorithm
Por lo tanto, ejecutamos:
Get-FileHash -Algorithm MD5 'C:\Program Files\interesting-file.txt.txt'
What is the command to get the current working directory?
Buscamos por comandos que contengan en su nombre location. El comando que buscamos es:
Get-Location
Does the path “C:\Users\Administrator\Documents\Passwords” Exist(Y/N)?
Para saber si existe el directorio, solo intentamos hacer un cd a este (ignoro si este paso se realizaba de un modo diferente). Como podemos observar, no podemos acceder dado que no existe.
What command would you use to make a request to a web server?
Buscamos por comandos que contengan en su nombre reqest y web. El comando que buscamos es:
Invoke-WebRequest
De hecho, ya lo hemos estado utilizando en máquinas Windows.
Base64 decode the file b64.txt on Windows.
Proimero pasamos a una variable el contenido del archivo especificado:
$content = Get-Content 'C:\Users\Administrator\Desktop\b64.txt'
Posteriormente, ejecutamos la decodificación de base64:
$DECODED = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($content))
Y por último, solo imprimimos la variable $DECODED:
$DECODED
Enumeration
How many users are there on the machine?
El comando que nos devuelve todos los usuarios de una máquina es:
Get-LocalUser
Recordemos que con Measure obtenemos la cantidad de resultados obtenidos por el comando anterior.
Which local user does this SID(S-1-5-21-1394777289-3961777894-1791813945-501) belong to?
Seguimos empleando el mismo comando para listar a los usuarios, solo que ahora empleamos la propiedad SID para buscar a aquél que coincida con el indicado:
Get-LocalUser | Where-Object -Property SID -Match 'S-1-5-21-1394777289-3961777894-1791813945-501'
How many users have their password required values set to False?
Siguiendo el mismo principio que el ejercicio anterior, ahora empleamos el parámetro PasswordRequired y listamos aquellos que lo tengan seteado en false:
Get-LocalUser | Where-Object -Property PasswordRequired -Match 'false'
How many local groups exist?
Para listar los grupos locales empleamos:
Get-LocalGroup
What command did you use to get the IP address info?
Buscamos un comando que contenga la cadena IP en el nombre:
El comando que buscamos es:
Get-NetIPAddress
Corroboramos el output:
How many ports are listed as listening?
Este comando fue engañoso, dado que no contiene la cadena ports en su nombre, así que tuve que Googlearlo en su lugar:
Get-NetTCPConnection
Si solo queremos filtrar aquellos que estén con estatus Listen:
Get-NetTCPConnection | Where-Object -Property State -Match 'Listen'
What is the remote address of the local port listening on port 445?
Solo damos un vistazo a la salida del comando anterior para resolverlo.
::
How many patches have been applied?
De igual manera, este comando tuve que Googlearlo ya que no hay una cadena en su nombre que incluya patch o algo similar:
Get-HotFix
When was the patch with ID KB4023834 installed?
Filtramos la salida anterior en busca de un HotFixID con el valor especificado:
Get-HotFix | Where-Object -Property HotFixID -Match 'KB4023834'
Find the contents of a backup file.
Para buscar por un archivo backup, tenemos que buscar aquellos que contengan la cadena .bak en su nombre, y para ello nuevamente hacemos uso de Get-ChildItem:
Get-ChildItem -Path 'C:\' -Recurse -ErrorAction SilentlyContinue -Include *.bak* -File
Search for all files containing API_KEY
De manera similar al anterior, ahora debemos buscar por un archivo que contenga la cadena API_KEY dentro de su contenido, y para ello, hacemos uso de Select-String
Get-ChildItem -Path 'C:\' -Recurse -ErrorAction SilentlyContinue | Select-String -pattern API_KEY
Esto nos devolverá un output bastante extenso sobre archivos que contengan dicha cadena, pero el que buscamos aparecerá casi al final del escaneo y será visible al momento; una API Key.
What command do you do to list all the running processes?
Listamos comandos que contengan la cadena process en su nombre; el que buscamos es el siguiente:
Get-Process
What is the path of the scheduled task called new-sched-task?
No tengo una solución para este ejercicio, dado que el formato de respuesta en TryHackMe ya nos dice que es simplemente una diagonal, refiriéndose a la raíz:
/
Who is the owner of the C:
De manera análoga a cmd, busco un comando que contenga en su nombre la cadena ACL, que es la encargada de permisos en Windows; el comando que necesitamos es:
Get-Acl 'C:\'
Basic Scripting Challenge
El ejercicio nos pide modificar el script que encontraremos en el Escritorio (listening-ports.ps1) para poder responder a las preguntas planteadas, sin embargo, estas se responden simplemente con un comando oneliner.
What file contains the password? and What is the password?
Buscamos un archivo que en su contenido contenga la cadena password, similar al ejercicio del apartado anterior:
Get-ChildItem -Path 'C:\Users\Administrator\Desktop\emails' -Recurse -ErrorAction SilentlyContinue | Select-String -pattern password
Obtenemos respuesta para las primeras dos preguntas con solo ese comando.
What files contains an HTTPS link?
De igual manera, ahora solo buscamos por la cadena https:
Get-ChildItem -Path 'C:\Users\Administrator\Desktop\emails' -Recurse -ErrorAction SilentlyContinue | Select-String -pattern https
Intermediate Scripting
El ejercicio nos solicita un script que sea capaz de escanear puertos en el localhost y determinar si estos se encuentran abiertos o no; para corroborar su funcionamiento, solicitan saber cuántos se encuentran abiertos en el localhost en el rango de 130 a 140. Para ello, empleé el comando Test-NetConnection, el cual entabla una conexión TCP con el host y puerto que le especifiquemos:
Test-NetConnection localhost -p 80
Para resolver el ejercicio, primero declaro tres variables: host, puerto inicial y puerto final (el escaneo se lleva a cabo en un rango de puertos). Posteriormente realizo un bucle for para mandar llamar a el comando especificado con cada uno de los puertos dentro del rango declarado. Este comando devuelve varios valores, sin embargo, me centré primero en el llamado TcpTestSucceeded, el cual devuelve True si logró establecer una conexión.
Este, al ser ejecutado, devuelve que solo hay un puerto abierto, el 135:
Sin embargo, hay algo que no estoy tomando en consideración, y es el hecho de que el puerto puede estar abierto pero ser inaccesible, y para corroborarlo, debemos emplear otro de los resultados que devuelve el comando llamado PingSucceeded. Este nos indicará si el puerto está a la escucha y ha respondido, pero probablemente no sea capaz de establecer una conexión (razón por la que el TcpTestSucceeded pueda devolver False cuando el puerto sí está a la escucha). De esta manera, empleo ambas posibilidades en una operación OR dentro del if; adicional a ello, declaro un contador que me ayude a determinar cuántos puertos resultaron abiertos al final:
Si ejecutamos el script, veremos que para todos los puertos que antes habíamos considerado como cerrados, en realidad existen y responden al ping, pero son inaccesibles. Mientras que el 135, al responder al TcpTestSucceeded, sí lo es.
Por lo tanto, se concluye que los 11 puertos escaneados (entre el 130 y el 140) se encuentran abiertos.
El script resultante puedes consultarlo en mi GitHub.