1 puntos por GN⁺ 2023-10-23 | 1 comentarios | Compartir por WhatsApp
  • En el flujo de conexión OAuth de Outlook Calendar de Harvest, la URL de callback volvía a redirigir al destino indicado en el valor state, lo que producía una redirección abierta; combinada con el flujo de concesión implícita, podía exponer tokens a una URL externa
  • El problema no estaba en Microsoft, sino en la integración de Harvest: el redirect_uri de OAuth registrado se convertía en una escala de redirección que enviaba al usuario al dominio especificado por el atacante
  • state es JSON codificado como URI, y si en subdomain se coloca un dominio externo con una barra al final, como example.com/, se redirige a una forma como example.com/.harvestapp.com/...
  • El PoC muestra un flujo en el que, desde la URL de autorización OAuth de Microsoft, se usan client_id=0dcef4db-36d8-4aed-9cc5-ab43e1814884, response_type=id_token, response_mode=fragment y scope=openid, y el fragmento #id_token=... queda adjunto al destino de la redirección
  • La vulnerabilidad se reportó el 23 de agosto de 2020; el parche se confirmó el 1 de agosto de 2023, y el 22 de octubre de 2023 Harvest se disculpó diciendo que la demora se debió a un error humano

Flujo en el que se filtra el token desde el callback OAuth

  • Harvest es un software de seguimiento de tiempo que permite a los usuarios conectar Outlook Calendar mediante OAuth
  • Cuando la autorización se completa correctamente, el usuario es redirigido a https://outlook-integration.harvestapp.com/auth/outlook-calendar/…
  • Ese callback vuelve a enviar al usuario a la URL proporcionada dentro de state, y en ese proceso se produce una redirección abierta
  • El valor state de la URL de callback observada originalmente es JSON codificado como URI
    • Al decodificarlo, tiene una forma como {"return_to":"/","subdomain":"hackerone295"}
    • El valor subdomain se usa para inferir un espacio de la app Harvest, como hackerone295.harvestapp.com
  • Si se agrega una barra a subdomain, como example.com/, la URL de callback pasa a redirigir a un dominio externo
  • Como esta URL de callback es el redirect_uri registrado en la aplicación OAuth, al combinar la redirección abierta con el flujo de concesión implícita, el token puede quedar expuesto al destino de la redirección
  • La URL de autorización del PoC usa los siguientes valores
  • El usuario termina siendo redirigido a una forma como la siguiente
  • No es una vulnerabilidad del lado de Microsoft

Tiempo transcurrido desde el reporte hasta el parche

  • El equipo de Harvest respondió muy poco durante el proceso de divulgación y parcheo de la vulnerabilidad, y aun después de reconocerla en triage, pasó mucho tiempo hasta la corrección
  • La vulnerabilidad se reportó el 23 de agosto de 2020, y Harvest hizo el primer contacto el 16 de octubre de 2020
  • El 27 de noviembre de 2020, el reporte pasó al estado triaged
  • El 28 de abril de 2022, la empresa dijo que estaba trabajando en la corrección y estimó un plazo de 2 semanas, pero la corrección real tardó aproximadamente 1 año más
  • El 1 de agosto de 2023 se confirmó que la vulnerabilidad había sido parcheada
  • El 21 de octubre de 2023, el reporte se hizo público mediante una publicación
  • Para esa misma fecha, el reporte seguía en estado de triage y, aunque la política de bug bounty mencionaba recompensas, no se pagó ningún bounty ni puntos de HackerOne
  • El 22 de octubre de 2023, después de que la publicación recibiera atención, Harvest explicó que la demora se debió a un error humano y se disculpó

1 comentarios

 
GN⁺ 2023-10-23
Opiniones en Hacker News
  • Como responsable del programa de bug bounty, voy a explicar qué pasó internamente. Ya me disculpé con @0xcrypto y lo expliqué internamente, pero creo que corresponde resumirlo también aquí.
    Desde el principio no pudimos reproducir por completo este problema y tampoco podíamos cerrarlo por miedo a que se nos estuviera escapando algo. Justo después de mi última respuesta diciendo que “buscaría una solución”, ya estábamos más cerca de concluir que no era reproducible, y al entrar un reporte relacionado con OAuth similar hubo confusión interna y pensé erróneamente que ya lo habíamos procesado y comunicado.
    Por la configuración de notificaciones me perdí los mensajes de seguimiento, y el issue quedó indefinidamente en estado de Triage sin actualizaciones. Esto no es una excusa; durante mucho tiempo fui bug bounty hunter, así que sé muy bien lo frustrante que es esperar actualizaciones de una empresa. La seguridad de los clientes es nuestra máxima prioridad, y lo que dice nuestra página de seguridad es cierto.

    • Puede haber errores, pero aún no queda explicado que, durante 3 años, incluso tras contactar varias veces a HackerOne, HackerOne no haya podido comunicarse con Harvest.
      Además, ahora tampoco queda claro cómo se va a manejar un reporte que ya no se puede reproducir. Quería seguir conversándolo en HackerOne, pero después del mensaje de disculpa parece que volvieron a quedar en silencio.
    • Me da curiosidad saber si, en última instancia, creen que la vulnerabilidad realmente funcionaba de la manera descrita y, de ser así, por qué no pudieron reproducirla.
    • Qué bueno poder escuchar una explicación directa. Aunque no se pudiera reproducir, me pregunto si no habría sido fácil confirmar viendo el código fuente si era posible un open redirect.
    • Al menos me alegra que hayan publicado algo diciendo que se lo están tomando en serio. Cualquiera puede cometer errores, pero creo que, si no se asume la responsabilidad cuando ocurre un error, el problema se agranda.
    • Uso Harvest y me gusta, pero ojalá también arreglaran ya la nueva app móvil de iOS. Se acumularon tantos problemas pequeños que dejé incluso de reportarlos a soporte.
      El estado de la app suele desincronizarse del estado del servidor; los cambios del servidor solo se ven tras forzar una actualización, o los cambios del cliente se revierten después de guardarlos. La experiencia de usuario para el seguimiento de tiempo también es incómoda: a veces hay que hacer scroll para ver los botones, o la posición de los botones de iniciar/detener/reiniciar/eliminar cambia constantemente según el estado del ítem. La app anterior no era bonita, pero funcionaba sin problemas.
  • Es bastante inquietante. Cuando usé Harvest, el soporte fue realmente excelente: respondían rápido, entendían con mucho detalle cómo los clientes usaban el producto y explicaban en profundidad formas creativas de aprovechar funciones existentes.
    Para funciones no implementadas, la respuesta era “lo pondremos en el backlog, pero no podemos garantizarlo”. Se indica que tienen 30 personas en ingeniería [1], pero no tengo muy claro en qué se está usando esa capacidad, porque tampoco vi que salieran otras funciones rápidamente.
    Empecé a recibir spam como “usuario de Harvest” y sospeché que habían vendido la lista de clientes, pero los responsables de la empresa se pusieron en contacto de inmediato, lo negaron tajantemente y se lo tomaron tan en serio como para investigarlo al instante. Eso estuvo bien.
    Pero al final esto también parece un problema de ingeniería. Encontré una forma bastante sencilla de estimar los clientes activos, y eso también entró al “backlog” y lleva meses sin arreglarse. La corrección parecía muy trivial. Además, MFA solo está disponible cuando se inicia sesión con Google [2]. Aun así, la app en sí hace realmente bien su trabajo.
    1: https://www.getharvest.com/about/meet-the-team
    2: https://support.getharvest.com/hc/en-us/articles/36005266713...

    • Gracias por la buena valoración. Sin duda coincido en que el equipo de soporte es excelente. Es un equipo pequeño, pero trata todos los asuntos con mucha seriedad y también participó directamente en la investigación que mencioné antes.
      La mala comunicación con la persona que reportó esto en este hilo fue completamente error mío y, como expliqué en la respuesta de arriba, me aseguraré de que no vuelva a ocurrir.
    • No sé si te gusta o no. ¿Es sarcasmo?
    • La calidad del soporte sí fue claramente buena. Las solicitudes siempre las atendía gente muy competente y, por lo general, recibía respuesta en cuestión de minutos.
      Algunas de mis solicitudes de funciones incluso terminaron entrando al producto real. Tal vez no fue por mi influencia, pero al menos parece que teníamos ideas parecidas sobre lo que es un buen rastreador de tiempo.
  • El título me parece bastante injusto con Microsoft. Da la impresión de querer aprovechar la atención reciente sobre Microsoft por sus incidentes de autenticación, y apenas vi el título pensé: “¿otro compromiso de MS?”.
    En realidad se trata de tokens de Harvest, y por una vulnerabilidad de inyección en el código de Harvest solo se expusieron indebidamente permisos de acceso a la app de Harvest. Habría sido igual de vulnerable detrás de cualquier otro proveedor de identidad.

    • Soy el autor del post del blog. Entiendo la preocupación e intenté quitar el nombre de Microsoft del título, pero no se me ocurrió una buena forma de expresarlo.
      Esta vulnerabilidad afecta únicamente la implementación de OAuth para la conexión de cuentas Microsoft. El título original era “Microsoft OAuth token leak via open redirect in Harvest App”, y luego lo cambié a “Microsoft Account's OAuth tokens leaking via open redirect in Harvest App”. Todavía estoy dispuesto a cambiarlo y acepto sugerencias.
    • Pensé lo mismo. Incluso me hizo dudar de si el artículo realmente entendía cómo funciona OAuth y aun así lo llamaba token de MS.
  • RFC 6749 aborda en detalle cómo un servidor de autorización debe prevenir este tipo de ataques.
    El servidor de autorización debe exigir el registro de URI de redirección para clientes públicos, y se recomienda que también lo exija para clientes confidenciales. Si en la solicitud se proporciona una URI de redirección, el servidor de autorización debe validarla comparándola con el valor registrado.
    Entonces, me pregunto cómo fue posible esto, si la app de Harvest no habría registrado un redirect_uri malicioso. ¿Será que el servidor OAuth de Microsoft ignora los parámetros de URL dentro del redirect_uri al compararlo con la URI de redirección registrada del cliente OAuth?

    • Parece que montaron una segunda redirección encima y la pusieron en el parámetro state. Probablemente la intención era redirigir a cualquier destino.
      El flujo previsto sería: ir a la URL de autenticación de Harvest → redirigir a la URL de autenticación de Microsoft con redirect_uri=registered_uri y state=some_encoded_final_uri → el usuario ingresa sus credenciales → se redirige a la URI registrada → se lee state y se vuelve a redirigir a la URI que contiene.
      Este ataque sigue redirigiendo a una URI permitida, pero ese endpoint lee state y reenvía tal cual la respuesta/el token. Hay tres errores: abuso de state, no cifrar ni validar state si iban a abusar de él, y haber activado la concesión implícita. Si la necesitaban, debieron crear un registro aparte para un uso limitado.
    • El redirect_uri de Harvest está registrado en Microsoft. Después de que el servidor OAuth de Microsoft redirige a Harvest, Harvest implementa su propia redirección con base en los datos de state.
  • La concesión implícita es bastante terrible por razones como las que se ven en este artículo.
    Como referencia, se eliminará en la próxima especificación OAuth 2.1: https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-09.htm...

    • ¿No estaba ya marcada para deprecación desde hace unos 6 años? CORS reemplazó ese caso de uso, así que no hay razón para mantenerla en la nueva especificación.
  • ¿O sea que tardaron 3 años en corregir la vulnerabilidad? De agosto de 2020 a agosto de 2023; no sé qué tamaño tenga el equipo de Harvest, pero aun así parece un nivel absurdo.

    • Sospecho que, como pasa en muchas empresas, entró al backlog con baja prioridad, pasó por varias reorganizaciones de Jira y cambios organizacionales, y al final alguien lo encontró después y lo arregló.
    • Soy del equipo de seguridad de Harvest. Como ya respondí en otro comentario, básicamente no pudimos reproducirlo y no hubo una corrección explícita. Pero un issue que debió haberse cerrado quedó en estado Triage por un error humano mío.
  • Me gustaría que alguien experto en OAuth explicara este problema con un poco más de detalle. Leí el blog varias veces, pero todavía no entiendo la vulnerabilidad real.
    Con mi conocimiento muy limitado de OAuth, ¿no funciona así?: la app de Harvest le pide a Microsoft que verifique al usuario; Microsoft verifica al usuario y, si tiene éxito, redirige a la URL de callback entregando el token de acceso en el cuerpo de la respuesta.
    En ese caso, ¿el autor del blog no simplemente creó una URL hecha a mano para que la URL de retorno fuera a example.com en vez de a la URL de retorno real?

    • Correcto. El autor del blog creó una URL hecha a mano de ese tipo. Pero la URL de callback en la URL de ataque está en el dominio harvestapp, y la parte que controla el atacante está dentro de state, que desde la perspectiva del servidor OAuth es casi opaco.
      Con esa URL, puedes enviarle a alguien un enlace de login.microsoftonline.com, mostrarle un prompt de inicio de sesión para “iniciar sesión en Harvest”, y luego el atacante puede obtener permisos reales relacionados con la cuenta de Harvest.
      Normalmente eso no sería posible. El atacante puede registrar una app nueva que redirija a example.com, pero entonces no obtendría un token de acceso con permisos relacionados con Harvest, así que no serviría.
      La app OAuth del lado de Microsoft tiene una lista de redirecciones válidas permitidas, así que un intento como login.microsoftonline.com/authorize?client_id=$harvestAppID&redirect_uri=attacker.com da error del lado de Microsoft. El ataque es posible porque una URL válida de outlook-integration.harvestapp.com recibe el token de acceso y luego redirige de nuevo al sitio del atacante, pasando también el token de acceso.
    • La vulnerabilidad salió de outlook-integration.harvestapp.com. Después de que el callback de OAuth2 tenía éxito, usaban como state un objeto JSON con instrucciones sobre qué hacer.
      La propiedad subdomain se usaba para redirigir el navegador a un subdominio de harvestapp.com pasando el #id-token. El problema es que el valor de subdomain se inyectaba tal cual en la siguiente URL:
      https://${subdomain}.harvestapp.com/...#id-token=...
      Si en el payload JSON configuras subdomain con un valor que termina en slash, como attacker-controlled.com/, la URL se convierte en https://attacker-controlled.com/.harvestapp.com/...#id-token=.., y el navegador va a otro dominio, filtrando el token.
    • Microsoft verifica que la URL de retorno esté en la lista de permitidas que especificó Harvest. Probablemente Harvest agregó encima su propio mecanismo de redirección para admitir varias instancias del software, pero no saneó correctamente el valor de entrada de la redirección.
      Por lo tanto, no es un problema implícito de OAuth en sí, sino una mala implementación.
    • No lo sé con exactitud, pero creo que el problema fue que Harvest permitió todas las URL como URL de callback. Deben indicarle a Microsoft que solo permita URL específicas como callback.
      Al configurar el flujo de trabajo, es posible que en vez de crear una lista real de URL de callback confiables, hayan usado un comodín en la lista de callback permitidos. También podría estar completamente equivocado.
  • No entiendo por qué esperaron 3 años. Un período de gracia antes de la divulgación de 90 días debería ser suficiente.

    • Podría ser más de 90 días si se necesita un cambio enorme y un equipo bastante grande dedica la mayor parte de su tiempo de trabajo a este problema. O puede que ya exista una solución, pero que por la notificación a los clientes haya que avanzar según un calendario específico y relativamente corto.
      Pero cualquier prórroga adicional así debería ser algo que el investigador, o su abogado/representante, permita. Es el tipo de cosa que una empresa puede pedir de buena fe para un caso más grande de lo habitual.
  • Si HackerOne permite que las empresas dejen estas cosas guardadas durante 3 años, parece que no está cumpliendo bien su papel.

    • HackerOne depende de la empresa que opera el programa de bug bounty. El grado de involucramiento depende mucho del servicio ofrecido, por ejemplo si se encargan o no de la clasificación.
      En el nivel más básico, solo ofrece una plataforma de divulgación de vulnerabilidades y texto legal estándar para que los investigadores no sean demandados por el equipo legal.
      En la mayoría de los casos, las empresas rechazan las solicitudes de divulgación. Si el investigador divulga sin permiso, incumple los acuerdos con HackerOne y con la empresa, y queda expuesto a responsabilidad legal. En este caso, parece que la empresa aceptó la divulgación, y aunque su respuesta haya sido muy lenta, creo que eso se puede reconocer.
      Personalmente, también he tenido varias veces bugs con recompensas de cuatro cifras que no se corrigieron durante más de un año, pero no pensé que fuera culpa de HackerOne.
    • He tratado issues de HackerOne desde el lado de la empresa, y un participante de HackerOne violaba constantemente las propias reglas de HackerOne. Hubo incumplimientos del calendario de divulgación, publicaciones falsas en redes sociales sobre el bug e incluso amenazas a empleados.
      A HackerOne no le importó. Aunque les avisamos varias veces que esa persona estaba violando sus reglas, dijeron que no podían hacer nada.
      Daba la impresión de que habían reducido una empresa que ya funcionaba normalmente a un equipo mínimo de operación, con personal de soporte sin autoridad respondiendo preguntas. Fue hace bastante tiempo, así que quizás ahora sea distinto, pero esa fue la impresión en ese momento.
    • Entre las tres partes —HackerOne, la empresa y el investigador que encontró el bug—, es la empresa la que tiene todo el poder de negociación.
      Si las empresas sienten que HackerOne se extralimita y decide qué “permitirles” hacer, simplemente se irán de HackerOne y crearán una solución interna.
    • Quizás haga falta reseñar a las empresas, para poder evitar a las pésimas que alargan los casos durante años y ni siquiera pagan recompensas.
  • No entiendo por qué este issue no se escaló a Microsoft. Microsoft podría haber revocado el acceso de esta aplicación OAuth hasta que se corrigiera el problema.
    Aunque seguramente hay miles de implementaciones igual de malas conectadas a Microsoft mediante OAuth.

    • No sabía que eso fuera posible. Personalmente, creo que nunca se me habría ocurrido.