Fallas graves en la seguridad de tarjetas de crédito y credenciales en Rappi

*Fallas reportadas a Rappi mediante el contacto a su CEO quien nos remitió a un cofundador y su encargado de Seguridad. Falla corregida hacia el 20 de Septiembre de 2018. Rappi no cuenta con un programa de bug bounties ni mecanismos de reporte públicos de fallas de seguridad. Nos informaron que aprobaron un pago por este reporte y a la fecha no conocemos más detalles. El tiempo de solución de la falla fue de 61 días.

#TLDR

En esta entrada describimos unas fallas muy graves que reportamos a Rappi y que pudieron permitir obtener datos personales de sus clientes en varios países, así como datos parciales de sus tarjetas de crédito e identificadores (tokens) en el sistema de almacenamiento. También encontramos errores en el código de inicio de sesiones (login). Es probable que estas fallas pudieran ser usadas para asociar las tarjetas de crédito almacenadas con cuentas de terceros y proceder a realizar cargos no autorizados tal como se observa en varios reportes en las redes sociales. Este reporte no constituye una auditoría sino un ejercicio limitado que sin embargo encontró errores graves.

Tiempo de solución de las fallas: 61 días.

Introducción

En los últimos meses notamos en Twitter varios reportes de personas que dicen haber sido víctimas de cargos no autorizados por parte de Rappi. A continuación algunos de ellos en Colombia:

Como la seguridad de tarjetas y compras en línea es un asunto, que de estar bien ejecutado no debería suponer problemas, decidimos hacer una revisión con información pública de cómo se implementaban las transacciones en Rappi. A continuación explicamos un poco más de cómo deberían funcionar las transacciones y posteriormente las fallas graves que encontramos en Rappi.

Transacciones Seguras en Internet

Normalmente, al hablar de transacciones seguras en Internet, nos han aconsejado buscar en la barra del navegador un “candado”, una palabra en color verde “Seguro” o alguna otra indicación de uso del protocolo seguro HTTPS. Infortunadamente, aunque es un aspecto de suma importancia, esto sólo garantiza que las transmisiones (comunicaciones) de datos entre nuestro computador o móvil y este otro servidor se realicen cifradas. Esto significa que aunque sean interceptadas se dificulte o haga imposible conocer el contenido, por ejemplo su contraseña. Esto funciona bien para proteger inicios de sesión y credenciales (usuarios y contraseñas).

Idealmente si un atacante conociera las credenciales en un servicio, por ejemplo su contraseña de Twitter, no debería tener efectos en otros servicios, digamos Facebook. Por esto es muy importante usar contraseñas diferentes en todos los servicios. Esto garantiza que si un atacante logra recuperar las credenciales de un servicio no tendrá acceso a los demás. El caso con los datos de las tarjetas de crédito es un poco más complicado.

En el caso de los datos de tarjetas de crédito existen otros requerimientos y la transmisión es solo un aspecto de la seguridad. Los datos de una tarjeta de crédito son válidos a lo largo del mundo y revocar una tarjeta no es tan sencillo como recuperar una cuenta y cambiar una contraseña. Si un atacante logra conocer la información de su tarjeta podría intentar usarla en cualquier lugar del planeta hasta tanto no sea detectado. Tanto en Internet como de otras formas. Por esto existen otros requerimientos como asegurar que aunque esta información viaje cifrada sea almacenada y procesada de forma segura. Es decir, que los servidores donde se almacena y procesa tengan altos estándares de seguridad. Que quien reciba y procese los pagos, que puede ser un tercero, tenga los más altos estándares de seguridad auditados idealmente por un tercero y otros aspectos más allá de la comunicación cifrada.

Debido a la necesidad de estandarizar y recomendar sobre la protección de datos y transacciones con tarjetas de crédito se creó la alianza PCI que integran los mayores emisores de tarjetas a nivel mundial (Visa, MasterCard,etc). Esta alianza publica un estándar, llamado PCI DSS (Payment Card Industry Data Security Standard), que deberían seguir todos los comercios.

Todos los comercios que acepten tarjetas de crédito, sin importar su tamaño, deberían cumplir el estándar PCI DSS. Este estándar no tienen fuerza de ley en todos los países y son los bancos adquirientes, en donde recibe pagos el comercio, generalmente los encargados de verificar que los comercios cumplan con el estándar y estén certificados. En Colombia la circular externa 008 de 2018 de la Superfinanciera se refiere al tema.

¿ Cómo se adquiere la certificación PCI DSS ?

La certificación PCI tiene dos formas. Una autoevaluación o contratar a un tercero consultor QSA (Qualified Security Assessor). La autoevaluación es el camino que prefieren la mayoría de comercios por tiempo y costos. La posibilidad de realizar la autoevaluación depende del volúmen de transacciones anuales que realiza el comercio. Esto se refleja en el nivel de certificación PCI. La siguiente tabla describe la relación entre el volúmen de transacciones, la posibilidad de realizar la autoevaluación y el nivel PCI requerido por VISA.

Un comercio que procese menos de 6 millones de transacciones anuales tiene la posibilidad de autoevaluarse. La autoevaluación consiste en un cuestionario que debe diligenciar de forma crítica el comercio para verificar que cumple con los requerimientos de PCI. El tipo de cuestionario de autoevaluación y los requerimientos cada vez más exigentes dependen de qué tan involucrados están los servidores del comercio con el procesamiento de datos de las tarjetas de crédito. Así:

*De acuerdo con el blog de Rappi solo en Bogotá se ejecutan 10.000 transacciones al día. Al proyectar tendríamos casi 4 millones anuales solo en Bogotá. De acuerdo con esto Rappi debería tener mínimo un nivel PCI 2 o incluso superior.

¿ Cómo se certifican los comercios ?

La gran mayoría de comercios, dado el volumen de transacciones, opta por autoevaluarse y no tocar ni procesar los datos de las tarjetas de crédito. Para este fin usan servicios de empresas procesadoras de pagos que se encargan de presentar el formulario de recolección de datos de tarjetas a sus clientes y realizar los cargos y reembolsos a las tarjetas de crédito. De esta forma los datos de las tarjetas de crédito nunca pasan por los servidores del comercio y una vez el cliente realiza la transacción y se aprueba, el procesador de pagos notifica al comercio. Es el procesador de pagos quien está involucrado con el tratamiento y procesamiento de datos de tarjeta de crédito. Usualmente estos operadores cuentan con las mayores certificaciones PCI nivel 1 entregadas por consultores externos. De esta forma los datos de las tarjetas de crédito se transfieren desde el computador o móvil del usuario a los servidores del procesador de pagos. Nunca pasan por el comercio.

¿ Por qué una compra en Rappi es diferente a la compra de un tiquete ?

Al realizar la compra de un tiquete, al momento realizar el pago, siempre se nos presenta el formulario de recolección de datos de la tarjeta. La información de nuestra tarjeta no está almacenada en los servidores del comercio, ni en algún servicio, y en cada compra se deben proveer los datos para la transacción. No importa que compremos cada semana un tiquete; siempre tenemos el formulario.

Rappi, suponemos, con el fin de mejorar la experiencia del usuario, optó por no requerir los datos de la tarjeta en cada compra. Esto significa que no solo son recolectados en un formulario sino que están almacenados de alguna forma. Esto requiere mucho cuidado en la implementación ya que se incrementa la exposición de los datos .

¿ Cómo almacena Rappi los datos de las tarjetas ?

Al momento de nuestra revisión Rappi usaba los servicios de Spreedly ; un servicio reputado de procesamiento de pagos y almacenamiento con los más altos estándares PCI nivel 1.

La forma en que funciona este servicio es mediante la tokenización o generación de identificadores (tokens). La tokenización consiste en que el procesador de pagos, en servidores con muy altos estándares de seguridad, recibe de forma segura los datos de nuestra tarjeta: Nombres, número, fecha de expiración, dígitos de verificación. Los almacena en un compartimento seguro, no accesible totalmente por el comercio (el comercio nunca conoce todos los dígitos de la tarjeta ni los números de verificación CVV), y devuelve un identificador único (token), por ejemplo: H7FdKWKPOPhepzxS4MfUuvTDHxr. Es este identificador o token lo que Rappi recibe, almacena y asocia a nuestra cuenta. Por ejemplo, para un usuario con dos tarjetas de crédito asociadas, esto es lo que Rappi almacenaría:

usuario: pedro_perez@hotmail.com
tokens de tarjetas: H7FdKWKPOPhepzxS4MfUuvTDHxr y TBuWJz3OyvaDgcHyEhmY1hv9InB

Este identificador (token) es único dentro del compartimento seguro y no tiene validez fuera de él. Únicamente dentro del compartimento concreto podemos, usando una contraseña, realizar operaciones sobre ellos. Si Rappi fuera vulnerado estos identificadores (tokens) se podrían invalidar, y ya que Rappi no tiene los datos completos de las tarjetas, los atacantes no conocerían todos los datos de las tarjetas de crédito. Tendrían que vulnerar al procesador de pagos, lo que es menos probable.

Al momento de una transacción, Rappi, usando su contraseña (credenciales) del compartimento seguro, envía este identificador y la operación a su procesador de pagos para hacer sobre la tarjeta asociada al token. Hacer un reembolso, un cargo, etc. Por ejemplo.

Cargar 10 dólares al identificador (token) H7FdKWKPOPhepzxS4MfUuvTDHxr

De esta forma un comercio puede realizar operaciones de cargos y reembolsos sobre una tarjeta sin conocer todos los datos de la tarjeta y sin solicitarlos cada vez.

Sin embargo, la contraseña del compartimento seguro debe ser muy bien protegida . Conocer esta contraseña nos puede permitir realizar cargos arbitrarios a las tarjetas almacenadas y conocer información parcial de la tarjeta y su dueño, como los primeros y últimos números de la tarjeta así como nombres, correo electrónico, direcciones, etc. Esto es parte de lo que Rappi no estaba haciendo bien.

¿ Cuáles eran las fallas graves de Rappi* ?

Rappi, al presentar el formulario de recolección de datos de las tarjetas, opta por incluírlo desde sus servidores. Aunque los datos fueran enviados directamente al procesador de pagos esto incrementa la exposición de los datos de las tarjetas y les pone mayores exigencias en los cuestionarios de PCI, al menos SAQ A-EP. Rappi no usó los mecanismos recomendados por el procesador de pagos para recolectar la información de las tarjetas y de esta forma tener menores exigencias por exposición de la información. Aunque esto es válido no conocemos nada acerca de sus certificaciones PCI.

Pero independiente de la forma de incluir el formulario notamos una falla muy grave al examinar el código de la página web de Rappi. Dado que no usaron los métodos recomendados de recolección de tarjetas incurrieron en una falla muy grave que violaría cualquier cuestionario y nivel del estándar PCI y se advierte ampliamente en la documentación del procesador de pagos. Pudimos verificar que estaban haciendo las solicitudes para agregar tarjetas, al compartimento seguro, con un método diseñado exclusivamente para servidores protegidos, pero desde el navegador de sus clientes.

Esto significa que estaban incluyendo las credenciales (contraseñas) del compartimento seguro en el código de la página web expuestas al abuso de cualquier persona que pueda usar un navegador para cargar una página web. Estas credenciales permiten conocer información de todas las tarjetas almacenadas (creemos que todas las de Colombia, Argentina, Chile, México y Brasil) así como los identificadores únicos (tokens) y realizar cargos y otras operaciones sobre cualquiera de ellas.

A continuación lo que encontramos en un archivo de código javascript que era enviado al navegador al cargar la página de Rappi (ver en payment_gateway el api key y secret).

Credenciales del compartimento seguro Spreedly incluídas y usadas en la página web.

La documentación del operador de pagos advierte con claridad la necesidad de mantener estas credenciales privadas.

Tomado de la documentación de Spreedly https://docs.spreedly.com/basics/credentials/

2. Adicional a esto también incluían, en alguna de las 100 mil líneas de su archivo !, las credenciales privadas del servicio de inicio de sesión (login) AccountKit de Facebook así como otras credenciales.

Credenciales del servicio de login AccountKit de Facebook.
Tomado de la documentación de AccountKit https://developers.facebook.com/docs/accountkit/graphapi/

Estas credenciales protegen el inicio de sesión. No podemos confiar totalmente en el proceso de inicio de sesión (login) con esta implementación.

3. También incluían todas las credenciales de su entorno de prueba, tanto del compartimento seguro, como las de Facebook AccountKit:

Los archivos originales, de al menos dos versiones en diferentes fechas de su sitio web, pueden ser consultados en estos enlaces de copias espejo de su sitio: (Dejar cargar previamente ya que incluyen aproximadamente 100mil líneas y buscar payment_gateway)

Video mostrando los archivos javacript con las credenciales

*Estas fallas fueron identificadas en un ejercicio de revisión limitado con información totalmente pública, a la que tendría acceso cualquier persona con un navegador, y no constituyen una auditoría o revisión exhaustiva.

¿ Qué datos de las tarjetas se pueden obtener con las credenciales de un compartimento seguro* ?

Con las credenciales de un compartimento seguro se puede conocer mucha información y realizar varias operaciones. En el caso concreto de este operador de pagos, según se puede ver en la documentación, esto nos permitiría conocer para todas la tarjetas almacenadas en el compartimento seguro (aparentemente de todos los clientes en Sur América de Rappi*):

  • Últimos cuatro números de la tarjeta de crédito
  • Primeros seis números de la tarjeta de crédito
  • Correo electrónico
  • Nombres
  • Apellidos
  • Año y mes de expiración de la tarjeta de crédito
  • Direcciones
  • Ciudad
  • País

y otros como ZIP code, direcciones de despacho, si decidieron usarlas.

*Verificamos mediante un servidor en cada país (proxy), revisando el código, que Rappi incluía las credenciales del mismo compartimento seguro en varios países en los que presta servicio y que no había diferencias notables en el archivo de código (Argentina, México, Brasil, Colombia,Chile)

¿ Cómo pudo un atacante explotar estas fallas ?

Con unas llamadas al procesador de pagos un atacante, que notara esta falla grave, pudo obtener los identificadores (tokens) de todas las tarjetas almacenadas, así como los datos parciales de todas las tarjetas de crédito y clientes almacenados (Datos citados en la pregunta anterior). De acuerdo a nuestra verificación Rappi usaba el mismo compartimento en Argentina, Colombia, México, Chile y Brasil.

Flujo simplificado

En un ataque más sofisticado que obtener los datos, y debido a la arquitectura errada de Rappi al momento de la revisión, un atacante pudo ejecutar otro tipo de ataque sobre las tarjetas de crédito*. La aplicación web de Rappi luego de obtener del almacenamiento seguro el identificador (token) lo enviaba a sus servidores desde el navegador (ver flujo arriba) para ser asociado. Un atacante con un identificador (token) válido podría asociar el identificador (token) que representa la tarjeta de crédito de un tercero y proceder a realizar transacciones desde su cuenta u otra, con cargo a la tarjeta de esta otra persona. Aunque los identificadores (tokens) están diseñados para no ser adivinados fácilmente, obtener identificadores válidos no le sería difícil ya que el código de la página web de Rappi incluía las credenciales del compartimento seguro, de donde se pueden obtener tanto identificadores válidos, así como datos parciales de la tarjeta, datos personales y realizar operaciones.

Al tener, también, incluídas en el código público de su página web las credenciales secretas del servicio de login AccountKit de Facebook pueden existir otras formas de explotar el proceso de inicio de sesión (login) .

*Para algunos detalles técnicos adicionales del flujo ver el Anexo técnico al final.

**Creemos que este tipo de ataque, por el tipo de arquitectura errada, y dado que no se requiere ninguna verificación ni confirmación luego de tener asociada la tarjeta para ejecutar órdenes era posible. Por obvias razones no fue probado sino informado inmediatamente a Rappi.

¿ Cómo solucionó Rappi el reporte*?

Desde el reporte inicial Rappi tardó 61 días en solucionar la falla (ver Cronología). Cuarenta y dos (42 )días para eliminar las credenciales de un archivo javascript de su página web y 19 días más cuando los contactamos, de nuevo, a informarles que a pesar de eliminar las credenciales no las habían revocado (cambiado). Este nos parece un paso lógico luego de estar expuestas varios meses (no sabemos cuánto tiempo antes de nuestro reporte) de forma totalmente pública.

A pesar de eliminar las credenciales del archivo no revocarlas permitía a un atacante tener el control del compartimento seguro: seguir obteniendo identificadores (tokens), hacer cargos sobre las tarjetas y obtener información parcial de las tarjetas almacenadas en el compartimento seguro usado para clientes en varios países.

*De acuerdo a nuestro criterio creemos que Rappi también debería invalidar los tokens ya que las credenciales estuvieron expuestas públicamente durante un tiempo considerable. Al menos dos meses desde nuestro reporte y no sabemos cuánto antes. Es probable que esto requiera que sus clientes guarden de nuevo todas las tarjetas y les sean asignados nuevos tokens.

¿ Qué está haciendo ahora Rappi con los datos de las tarjetas de crédito?

Luego de los últimos reportes Rappi modificó la arquitectura de procesamiento de tarjetas, a un caso de uso acorde a la forma de agregar tarjetas que venía siendo usada, pero que requiere las mayores exigencias en el estándar PCI DSS. Los datos de las tarjetas no van directamente al procesador de pagos sino que pasan por los servidores administrados por Rappi o Grability desde donde, suponemos, agregan las tarjetas al compartimento seguro.

A la fecha del video (abajo) el formulario se incluye desde sus servidores y dominio y adicionalmente ahora los datos de las tarjetas los envían y se procesan de alguna forma en sus servidores en el cloud de Amazon. Esta decisión aumenta la exposición de los datos de las tarjetas de crédito (ya que van directo a los servidores administrados por Rappi o Grability. A pesar de que usen el data center de Amazon la seguridad es un proceso interno bajo su administración*) y aunque no se almacenen son cobijados por el estándar más exigente de PCI SAQ-D.

Esta mayor exigencia, aún cuando no almacenen las tarjetas, es entendible ya que lo que busca el estándar en este caso es evitar que los datos de las tarjetas puedan ser obtenidos por un atacante (hackers, empleados, etc) al ser procesados en la red interna del comercio. Por ejemplo modificando el código en una página, como le ocurrió a newegg, o capturando el tráfico entre otras formas.

Esta forma de procesar las tarjetas es válida pero la seguridad de los datos de las tarjetas de crédito ya no se limita a proteger unas credenciales del conocimiento público sino a varios procesos en sus servidores y red interna (configuraciones, listas acceso, firewalls, cifrado, escaneo periódico de vulnerabilidades, parches de seguridad, etc) y por eso el estándar es más exigente.

De forma pública no existe información acerca de la certificación PCI de Rappi o Grability.

Envío de los datos completos de las tarjetas de crédito a los servidores de Rappi

Cronología

  • 23/07/2018 — Aviso al CEO de Rappi (contacto gracias a las gestiones de Juan Pablo Buriticá) mediante un mensaje en Whatsapp de una falla grave de seguridad y la necesidad de establecer un canal de comunicación seguro. Nos remitió a su cofundador.
  • 23/07/2018 — Aviso al cofundador mediante un mensaje en Whatsapp de una falla grave de seguridad y la necesidad de establecer un canal de comunicación seguro. Nos remitió a su head de Seguridad.
  • 23/07/2018 — El head de seguridad nos contactó vía Whatsapp.
  • 24/07/2018 — Le comunicamos al head de seguridad la necesidad de un canal de comunicación seguro y preguntamos sobre su programa de bug bounties. El head nos contactó vía Signal y le contamos sobre la totalidad de la falla.
  • 08/08/2018 — Verificamos que la falla seguía activa y los contactamos de nuevo. Sin respuesta.
  • 10/08/2018 — Verificamos que la falla seguía activa y los contactamos de nuevo. El head de seguridad nos comenta que por algunos inconvenientes ha estado fuera 2 semanas.
  • 03/09/2018 — Verificamos que han eliminado las credenciales de la página web. Nos comentan que necesitan un día más para verificar las correcciones. Han aprobado un bug bounty.
  • 20/09/2018 — Verificamos que no revocaron las credenciales del compartimento seguro, solamente han sido eliminadas de la página web. Decidimos contactar de nuevo a un cofundador y al head de seguridad. Si unas credenciales han sido públicas nos parece lógico que deben ser cambiadas.
  • 22/09/2018 — Verificamos que han revocado las credenciales.

¿ Cómo se almacenaban las tarjetas de crédito en Rappi (Anexo Técnico) ?

Al agregar una tarjeta de crédito en Rappi se realizaban algunas llamadas a APIs de servidores. El flujo era así:

curl ‘https://v2.grability.rappi.com/api/paymentez/cc/url-add?env=pro' -H ‘origin: https://www.rappi.com' -H ‘accept-encoding: gzip, deflate, br’ -H ‘accept-language: en-US,en;q=0.9,es;q=0.8’ -H ‘authorization: Bearer Qgs1rWkO6YSHXLPVvMsJssIF0w93YiWYYLbsuoS0’ -H ‘content-type: application/json’ -H ‘accept: application/json, text/plain, */*’ -H ‘referer: https://www.rappi.com/' -H ‘authority: v2.grability.rappi.com’ --compressed

el servidor respondía con:

{"url":"https:\/\/ccapi.paymentez.com\/api\/cc\/add?auth_timestamp=1531915286&uid=152177469&email=yoresongo%40mail.ru&session_id=gbARsFzSJpFKeLPKRKhxGrlW7RxMk5O&application_code=RAPPI-ADD&auth_token=e507820edd15cb0ec0ffb5dc3ad14feed21dec99f55abc5bd3c9da5905124360"}

Esta es una URL para agregar tarjetas en el servicio PAYMENTEZ usando una API vieja. Al parecer en versiones anteriores Rappi usaba el procesador de pagos Paymentez y no han eliminado esta llamada. Código descuidado, parece. Mantener 100mil líneas de código en un mismo archivo, que incluye el código de producción y de pruebas, no sugiere las mejores prácticas de programación.

URL Paymentez

2.

curl ‘https://core.spreedly.com/v1/payment_methods.json' -H ‘Accept: application/json, text/plain, */*’ -H ‘Referer: https://www.rappi.com/' -H ‘Origin: https://www.rappi.com' -H ‘Authorization: Basic NnZneVFYekRFTHYzSUtvOXNJOTRCTHl1cjJwOlQyRnJ4NDRyWWwyUlBBZVA0c2xvTU9VZzBVaDBwcjZ0NExBRXFaWnVjRUN5cVRyTWRpNFhTdlhYYlE4bjltNkU=’ -H ‘DNT: 1’ -H ‘Content-Type: application/json’ — data-binary ‘{“payment_method”:{“credit_card”:{“first_name”:”PEDRO”,”last_name”:”PEREZ”,”number”:”487xxxxxxxxxx",”verification_value”:”xxx",”month”:”11",”year”:”2022"},”email”:”pedro@hotmail.com”}}’ --compressed

El servidor responde con:

{“transaction”:{“token”:”aQ3ZSWnZ0JMAfXaHqYPC2xJCIB0",”created_at”:”2018–07–18T11:56:04Z”,”updated_at”:”2018–07–18T11:56:04Z”,”succeeded”:true,”transaction_type”:”AddPaymentMethod”,”retained”:false,”state”:”succeeded”,”message_key”:”messages.transaction_succeeded”,”message”:”Succeeded!”,”payment_method”:{“token”:”XJS5ztaguRALShxY2Ai0xp5DBKK”,”created_at”:”2018–07–18T11:56:04Z”,”updated_at”:”2018–07–18T11:56:04Z”,”email”:”pedro@hotmail.com.ru”,”data”:null,”storage_state”:”cached”,”test”:false,”last_four_digits”:”xxxx",”first_six_digits”:”xxxxxx",”card_type”:”visa”,”first_name”:”PEDRO”,”last_name”:”PEREZ”,”month”:11,”year”:2022,”address1":null,”address2":null,”city”:null,”state”:null,”zip”:null,”country”:null,”phone_number”:null,”company”:null,”full_name”:”PEDRO PEREZ”,”eligible_for_card_updater”:true,”shipping_address1":null,”shipping_address2":null,”shipping_city”:null,”shipping_state”:null,”shipping_zip”:null,”shipping_country”:null,”shipping_phone_number”:null,”payment_method_type”:”credit_card”,”errors”:[],”fingerprint”:”4bd66c82e909990b7fb34fb3cd21e78d56de”,”verification_value”:”XXX”,”number”:”XXXX-XXXX-XXXX-****"}}}

En este punto notamos que llaman al servicio de API de pagos de Spreedly (editamos algunos valores pero esta llamada incluye todos los datos de la tarjeta) usando un método exclusivo para servidores protegidos que incluye las credenciales (ver Authorization Basic) de uso de TODO el compartimento seguro !

Rappi estaba usando el método de llamada con las credenciales del compartimento seguro. Esto expone todos los tokens de las tarjetas y permite a quien conozca esta contraseña realizar operaciones arbitrarias de cargos o reembolsos así como obtener datos personales y datos parciales de las tarjetas de crédito.

Authorization Basic

El header Authorization incluye la palabra Basic y el valor:

NnZneVFYekRFTHYzSUtvOXNJOTRCTHl1cjJwOlQyRnJ4NDRyWWwyUlBBZVA0c2xvTU9VZzBVaDBwcjZ0NExBRXFaWnVjRUN5cVRyTWRpNFhTdlhYYlE4bjltNkU=

Este tipo de autorización no es más que la concatenación con “:” de los valores de la llave de ambiente y el secret, todo en base64. Al hacer el decode tenemos:

6vgyQXzDELv3IKo9sI94BLyur2p:T2Frx44rYl2RPAeP4sloMOUg0Uh0pr6t4LAEqZZucECyqTrMdi4XSvXXbQ8n9m6E

Que corresponden a lo que encontramos en el archivo javascript

Al revisar el flujo por primera vez llegamos a creer que los programadores de Rappi erróneamente incluyeron las credenciales en base64 confundiendo esto con algún tipo de cifrado o bearer token, pero no, luego constatamos que estaban incluídas en texto plano en el archivo javascript junto con otras credenciales como las del AccountKit de Facebook !.

3.

curl ‘https://v2.grability.rappi.com/api/payment/assign-card' -H ‘origin: https://www.rappi.com' -H ‘accept-encoding: gzip, deflate, br’ -H ‘accept-language: en-US,en;q=0.9,es;q=0.8’ -H ‘authorization: Bearer Qgs1rWkO6YSHXLPVvMsJssIF0w93YiWYYLbsuoS0’ -H ‘content-type: application/json’ -H ‘accept: application/json, text/plain, */*’ -H ‘referer: https://www.rappi.com/' -H ‘authority: v2.grability.rappi.com’ --data-binary ‘{“token”:”XJS5ztaguRALShxY2Ai0xp5DBKK”}’ --compressed

El servidor responde con:

{"application_user_id":152177469,"bin":"487267","name":"PEDRO PEREZ","card_reference":10913714,"expiry_year":2022,"termination":"6191","expiry_month":11,"transaction_reference":null,"type":"visa","default":false,"deleted_at":null,"payment_gateway_type":null,"country_code":null,"bank_name":null,"status":"valid","payment_source_id":null,"restriction_message":[],"sanitized_type":"visa","available":true,"has_document":false,"payment_origin":"spreedly"}

Rappi asocia el token con el usuario desde el navegador del usuario !. Este tipo de arquitectura permitía asociar tokens a una cuenta. Un usuario que conociera algún token podría asociar los tokens de estas tarjetas con su cuenta. De dónde puede obtener los tokens ? Rappi tenía las credenciales de todo su compartimento seguro expuestas, lo que permite conocer los tokens de TODAS las tarjetas y otros datos del propietario.

4. Finalmente se obtenía la lista de tarjetas almacenadas para ser mostradas

curl ‘https://v2.grability.rappi.com/api/payment/card' -H ‘origin: https://www.rappi.com' -H ‘accept-encoding: gzip, deflate, br’ -H ‘accept-language: en-US,en;q=0.9,es;q=0.8’ -H ‘authorization: Bearer Qgs1rWkO6YSHXLPVvMsJssIF0w93YiWYYLbsuoS0’ -H ‘content-type: application/json’ -H ‘accept: application/json, text/plain, */*’ -H ‘referer: https://www.rappi.com/' --compressed

REPORTE

Dado que la probabilidad de emplear este tipo de ataque era muy alta (cualquier persona con conocimientos técnicos podría intentar hacerlo con éxito incluso usando un navegador) y las consecuencias eran graves al comprometer la seguridad esta se trataba de una vulnerabilidad crítica y decidimos reportarla y documentarla.

Invitamos a las personas y empresas de la comunidad informática a realizar auditorías independientes de seguridad a sus productos y a reportar de forma responsable a las empresas, que como en este caso atendieron amablemente el reporte.

Dada la importancia del tema y ya que puede servir de ejemplo de cómo no hacer un sistema de transacciones con tarjetas de crédito, y que está corregido de acuerdo a Rappi, hemos decidido documentar y publicar el caso en su totalidad. Para más información contáctenos en info@advisability.co o en la página https://www.advisability.co en donde encontrará nuestra llave PGP para comunicación segura.