Dota 2 es un juego MOBA que se lanzó inicialmente el 9 de julio de 2013. A pesar de tener casi 10 años (o quizá 20 si contamos el Dota 1 original), sigue atrayendo a una gran base de jugadores, de unos 15 millones de jugadores activos mensuales. Al igual que otros juegos populares, Dota es una pieza compleja de software bajo el capó, ensamblado a partir de múltiples componentes separados. Un componente que nos interesa especialmente es el marco Panorama. Se trata de un marco diseñado por la propia Valve para permitir el desarrollo de interfaces de usuario utilizando la conocida tríada web de HTML, CSS y JavaScript. La parte JavaScript aquí era problemática porque era ejecutada por la versión vulnerable de V8. Así, un JavaScript malicioso podría explotar una vulnerabilidad de V8 y obtener el control de la máquina de la víctima. Esto no sería un problema para el juego sin modificar, porque por defecto, sólo los scripts legítimos de Valve deben ser ejecutados. Sin embargo, Dota está muy abierto a la personalización por parte de la comunidad de jugadores, lo que abre las puertas a los actores de amenazas para intentar colar piezas maliciosas de JavaScript a sus víctimas desprevenidas.
La personalización de Dota puede adoptar muchas formas: Hay objetos del juego que se pueden llevar puestos, paquetes de anuncios, pantallas de carga, emoticonos del chat y mucho más. También hay modos de juego personalizados desarrollados por la comunidad. En esencia, se trata de juegos completamente nuevos que aprovechan el potente motor de Dota para permitir que cualquiera con un poco de experiencia en programación implemente sus ideas para un juego. Los modos de juego personalizados juegan un papel importante en Dota, y Valve es muy consciente de los beneficios de permitir a los jugadores expresar su creatividad mediante el desarrollo de modos de juego personalizados. Después de todo, el propio Dota comenzó como un modo de juego para «Warcraft III: The Frozen Throne». Quizá por eso se pueden instalar modos de juego con un solo clic desde el juego. Como resultado, hay miles de modos de juego disponibles, algunos de los cuales son extremadamente populares. Por ejemplo, DOTA AUTO CHESS fue jugado por más de 10 millones de jugadores.
Antes de que un modo de juego pueda ser jugado por jugadores normales, debe ser publicado en la tienda de Steam. El proceso de publicación incluye una verificación realizada por Valve. Aunque esto podría eliminar algunos modos de juego maliciosos, ningún proceso de verificación es perfecto. Como mostraremos más adelante, al menos cuatro modos de juego maliciosos consiguieron colarse. Creemos que el proceso de verificación existe principalmente por razones de moderación para evitar que se publique contenido inapropiado. Hay muchas formas de ocultar una puerta trasera en un modo de juego, y llevaría mucho tiempo intentar detectarlas todas durante la verificación.
La lógica principal de los modos de juego personalizados está codificada en Lua. Se ejecuta en el servidor del juego, por lo que no puede utilizarse directamente para atacar a jugadores individuales. Para las secuencias de comandos del lado del cliente, existe JavaScript del marco Panorama. Se utiliza principalmente para representar los elementos de la interfaz de usuario, como los marcadores o las barras de estado de las misiones. JavaScript se ejecuta mediante el motor V8 y es totalmente compatible con muchas funciones avanzadas, como la ejecución de WebAssembly. Además, también hay una API específica de Dota que expone funcionalidades adicionales. Particularmente interesante fue la función «$.AsyncWebRequest», que, en combinación con «eval», podría haber sido utilizada para backdoor un modo de juego para que pudiera ejecutar código JavaScript adicional arbitrario descargado de Internet. Quizás fue esta preocupación la que hizo que la función «$.AsyncWebRequest» fuera obsoleta y finalmente eliminada por completo. Sin embargo, hay formas de evitarlo. Por ejemplo, la petición web puede ser hecha por el código Lua del lado del servidor, con la respuesta pasada al JavaScript del lado del cliente usando APIs de mensajería de eventos del juego.
Sólo probando
Hemos descubierto cuatro modos de juego personalizados maliciosos publicados en la tienda de Steam, todos desarrollados por el mismo autor. El primer modo de juego (id 1556548695) es particularmente interesante, ya que parece que es donde el atacante sólo probó el exploit, a juzgar por la falta de una carga útil real adjunta. Curiosamente, el atacante también utilizó este modo de juego para probar otras técnicas, dejando código comentado o funciones no utilizadas. Esto nos ofreció una gran oportunidad para entender el proceso de pensamiento del atacante.
Como se puede ver en la captura de pantalla anterior, el atacante fue muy transparente sobre la naturaleza de este modo de juego, nombrándolo «test addon plz ignore» e incluso llegando a utilizar la descripción para instar a otros jugadores a no descargar este modo de juego. Aunque esto podría parecer una expresión de buena fe, en breve demostraremos que en los otros tres modos de juego maliciosos, el mismo atacante adoptó el enfoque exactamente opuesto e intentó que el código malicioso fuera lo más sigiloso posible.
El exploit JavaScript de este modo de juego personalizado se encuentra dentro de «overthrow_scoreboard.vjs_c». Solía ser un archivo JavaScript legítimo que implementaba la funcionalidad del marcador, pero el atacante sustituyó su contenido por un exploit para CVE-2021-38003. Esta vulnerabilidad fue descubierta originalmente como un día cero por los investigadores de Google Clément Lecigne y Samuel Groß, cuando se utilizó in the wild en una cadena de exploits contra un teléfono Samsung totalmente parcheado.
Ahora hay PoCs públicos y escritos para esta CVE. Sin embargo, no estaban disponibles en marzo de 2022, cuando el atacante actualizó por última vez el modo de juego. Esto significa que tuvieron que desarrollar una gran parte del exploit ellos mismos (incluso si hubiera un PoC público en ese momento, el atacante todavía necesitaría poseer algunas habilidades técnicas para retroportarlo a la anticuada compilación V8 que Dota estaba utilizando). Aún así, el núcleo del exploit fue proporcionado en la entrada del bug tracker de Chromium para el CVE. Hay un fragmento de código que puede activar la vulnerabilidad para filtrar el objeto supuestamente inaccesible «TheHole» y luego utilizar este objeto filtrado para corromper el tamaño de un mapa. El atacante tomó este fragmento y lo pegó en su exploit, construyendo el resto del exploit sobre este mapa corrupto.
La puerta de atrás
Tras descubrir este primer modo de juego malicioso, nos preguntamos por supuesto si hay más exploits de este tipo por ahí. Dado que el atacante no se molestó en informar de la vulnerabilidad a Valve, nos pareció probable que tuviera intenciones maliciosas e intentará explotar a mayor escala. Como resultado, desarrollamos un script que descargaba todos los archivos JavaScript de todos los modos de juego personalizados publicados en la tienda de Steam. Así obtuvimos gigabytes de JavaScript que pudimos consultar en busca de patrones de código sospechosos.
No tardamos en descubrir otros tres modos de juego maliciosos, todos del mismo autor (que también resultó ser el autor del modo de juego «test addon plz ignore» analizado anteriormente). Estos modos de juego se llamaban «Overdog no annoying heroes» (id 2776998052), «Custom Hero Brawl» (id 2780728794) y «Overthrow RTZ Edition X10 XP» (id 2780559339). Curiosamente, el mismo autor también publicó un quinto modo de juego llamado «Brawl in Petah Tiqwa» (id 1590547173), que no incluía ningún código malicioso (para nuestra gran sorpresa).
Reflexiones finales
Después de descubrir los cuatro modos de juego maliciosos, intentamos cazar más – desafortunadamente, nuestro rastro se perdió. Por lo tanto, no está claro cuáles eran las intenciones últimas del atacante. Sin embargo, creemos que no eran exactamente puras intenciones de investigación, por dos razones principales. En primer lugar, el atacante no informó de la vulnerabilidad a Valve (lo que generalmente se consideraría una buena acción). En segundo lugar, el atacante intentó ocultar el exploit en una puerta trasera sigilosa. En cualquier caso, también es posible que el atacante no tuviera intenciones puramente maliciosas, ya que podría abusar de esta vulnerabilidad con un impacto mucho mayor.