10 puntos por outsideris 2021-04-07 | Aún no hay comentarios. | Compartir por WhatsApp

La historia de un estudiante de último año de preparatoria que, al tener tiempo libre por el Covid, se puso a cazar bug bounties y terminó recibiendo 35,000 dólares por un bug bounty de páginas privadas de GitHub.

Lo reportó como un bug bounty de páginas privadas de GitHub y había dos bonos tipo CTF.

  • 10,000 dólares: leer la flag desde flag.private-org.github.io sin interacción del usuario. Si una cuenta fuera de la organización private-org puede leer esta flag, hay un bono adicional de 5,000 dólares.

  • 5,000 dólares: leer la flag desde flag.private-org.github.io con interacción del usuario.

Flujo de autenticación

GitHub Pages se aloja en un dominio separado, github.io, por lo que las cookies de autenticación de github.com no se envían al servidor de páginas privadas. Por eso, la autenticación de páginas privadas no puede identificar al usuario sin integración adicional con github.com. Así que GitHub creó un flujo de autenticación personalizado.

  • Al visitar una página privada, el servidor revisa si existe la cookie __Host-gh_pages_token.

  • Si la cookie no existe o no es válida, el servidor de la página privada redirige a https://github.com/login.

  • Esa redirección también establece un nonce en la cookie __Host-gh_pages_session.

    • Como esta cookie usa el prefijo __Host-, evita que JavaScript la establezca desde un dominio distinto al host correspondiente.
  • /login redirige a /pages/auth?nonce=&page_id=&path=.

  • Ahí se genera una cookie de autenticación temporal que se pasa a https://pages-auth.github.com/redirect en el parámetro token.

  • /redirect reenvía a https://repo.org.github.io/__/auth.

  • Ese endpoint final establece las cookies de autenticación __Host-gh_pages_token y __Host-gh_pages_id en el dominio repo.org.github.io.

  • Ahí también se valida el nonce de __Host-gh_pages_session que se había establecido antes.

La ruta de la solicitud original y el ID de la página se guardan en los parámetros de consulta path y page_id, respectivamente, y el nonce también se guarda en el parámetro nonce.

Explotación

Retorno CRLF

  • La primera vulnerabilidad fue una inyección CRLF en el parámetro page_id de https://repo.org.github.io/__/auth.

  • Descubrió que el parseo de page_id ignora caracteres en blanco y que este valor se establece directamente en el encabezado Set-Cookie.

  • Se puede romper el parseo con una inyección CRLF tradicional, pero no produce otro impacto.

  • Como el encabezado Location: se agrega después del encabezado Set-Cookie, aunque sea una redirección 302, el encabezado Location se ignora y se renderiza el cuerpo.

Ataque

  • Al revisar el código de GitHub Enterprise, descubrió que el servidor de páginas privadas estaba implementado con openresty nginx.

  • Logró XSS agregando un byte nulo. Como ese null byte tiene que ir al inicio del body, no se puede hacer un ataque de inyección de headers.

  • Desde aquí ya era posible ejecutar JavaScript arbitrario en el dominio de la página privada.

  • Ahora solo faltaba encontrar una forma de saltarse el nonce.

Bypass del nonce

  • Observó que páginas privadas hermanas dentro de la misma organización pueden establecerse cookies entre sí.

  • Una cookie establecida en private-org.github.io se envía a private-page.private-org.github.io.

  • Si se pudiera evadir la protección del prefijo __Host-, sería fácil saltarse el nonce.

  • No todos los navegadores lo soportan; IE no soporta el prefijo __Host-.

  • Pero, buscando una mejor forma, se le ocurrió una idea interesante.

  • Al revisar cómo manejan mayúsculas y minúsculas las cookies, descubrió que __HOST y __Host se tratan distinto, y que GitHub Private Pages ignora las mayúsculas al parsear cookies.

  • Así pudo especificar el nonce desde JavaScript.

  • Eso le dio el bono de 5,000 dólares.

Envenenamiento de caché

  • La respuesta del endpoint /__/auth? se cachea usando el valor entero del page_id falsificado.

  • Gracias a eso, si se logra envenenar la caché con el payload XSS, también afecta a usuarios sin interacción.

  • Si el atacante compromete unprivileged.org.github.io para contaminar la autenticación, el payload XSS queda cacheado.

  • Como las cookies se comparten en el dominio padre org.github.io, el atacante también puede atacar privileged.org.github.io.

Páginas privadas públicas

  • Para obtener el bono de 15,000 dólares, necesitaba que este ataque pudiera hacerlo un usuario que no perteneciera a la organización.

  • Esto era posible mediante una configuración incorrecta que dejaba páginas privadas en un repositorio público.

    • Se refiere a crear Pages en un repo privado y luego cambiar ese repositorio a público.
  • Las páginas privadas en esta configuración errónea hacen que todos los usuarios pasen por el flujo de autenticación y permiten que usuarios fuera de la organización tengan permisos de lectura.

Aún no hay comentarios.

Aún no hay comentarios.