Skip to main content

Cómo detectar y mitigar eficazmente los ataques Trojan Source en bases de código JavaScript con ESLint

Escrito por

10 de noviembre de 2021

0 minutos de lectura

El 1 de noviembre de 2021, la divulgación pública de un artículo titulado Trojan Source: vulnerabilidades invisibles describió cómo los actores maliciosos pueden usar caracteres de control bidireccional basados en Unicode para introducir código fuente malicioso en una base de código aparentemente inofensiva. Este ataque se basa en confundir a quienes revisan el código para que interpreten el código fuente malicioso ofuscado como comentarios.

¿Qué es un ataque Trojan Source?

Los editores de código tradicionales y las prácticas de revisión de código no detectan los caracteres bidireccionales presentes en el código fuente. Esto permite que los atacantes inyecten código malicioso que parece inofensivo. Esta vulnerabilidad se hizo pública el 1 de noviembre de 2021 y se le asignó el identificador CVE-2021-42574.

A continuación, se muestra un fragmento de código en VS Code que presenta un ataque Trojan Source en código fuente de JavaScript:

// running internal logic for privileged users:
var accessLevel = "user";
if (accessLevel != "user‮ ⁦// Check if admin⁩ ⁦") {
    console.log("You are an admin.");
}

¿Y ahora, con esta captura de pantalla?

Fragmento de código JavaScript que verifica si accessLevel es distinto de "user" y registra un mensaje de administrador

¿Detectaste el problema en el código fuente anterior? Si no, intenta examinar el fragmento de código con más detenimiento.

Esto es lo que sucede: se trata de un ataque de tipo Stretched String. El código de la línea 3 hace parecer que la expresión condicional verifica si la variable accessLevel es igual al valor user. Al final de la línea hay un comentario sobre las verificaciones lógicas que puede parecer inofensivo, pero la realidad es muy distinta.

De hecho, el uso de caracteres Unicode bidireccionales en la línea 3 oculta el valor real de la cadena que se verifica para la variable accessLevel. Esta es la línea 3 real, tal como la ejecutaría el compilador:

If (accessLevel != "user // Check if admin") {

El artículo describe varios tipos de uso indebido de caracteres de control bidireccional para inyectar código malicioso en el código fuente: Commenting-Out, Stretched String, Invisible Functions y Homoglyph Function. Los investigadores proporcionaron ejemplos en JavaScript de todos estos ataques en el repositorio trojan-source de GitHub.

Aunque el uso de caracteres de control bidireccional es un enfoque novedoso, este tipo de ataque no es nuevo y ya se había mencionado en listas de correo y foros de discusión. Por ejemplo, puedes consultar este problema de Golang de 2017 sobre la prohibición de caracteres RTL/LTR o esta entrada de Bugzilla de 2011, titulada [BiDi] Visualización engañosa de cadenas bidireccionales cuando se usa RLO, LRO o PDF (ten en cuenta que se usa Google Cache para acceder a ella).

¿Cómo se corrigen los ataques Trojan Source?

Los autores del artículo académico sugieren que el problema está en los editores de código y el software de IDE, que deberían corregirse para que esos caracteres Unicode sean visibles, así como en los compiladores, que deberían advertir a los usuarios sobre ellos.

Cómo detectar ataques Trojan Source en el código fuente

Es posible que tus procesos de edición y revisión de código se realicen en plataformas o herramientas que no admiten el resaltado de estos peligrosos caracteres Unicode bidireccionales. Esto significa que quizá ya tengas esos caracteres bidireccionales en tu base de código.

Entonces, ¿cómo puedes averiguar si tienes código fuente con caracteres Unicode bidireccionales? Para ayudarte, creé un paquete npm llamado anti-trojan-source que analiza un directorio o lee datos de la entrada estándar (STDIN) y busca en el texto la presencia de estos caracteres Unicode.

Puedes usar npx para analizar archivos de la siguiente manera:

npx anti-trojan-source --files='src/**/*.js'

O, si quieres usarlo como biblioteca en un proyecto de JavaScript:

import { hasTrojanSource } from 'anti-trojan-source'
const isDangerous = hasTrojanSource({
  sourceText: 'if (accessLevel != "user) {' // Check if admin
})

Cómo prevenir ataques Trojan Source en JavaScript con ESLint

Nota del editor: Desde la publicación original de esta entrada, se agregaron reglas contra Trojan Source a Snyk Code. Obtén más información en nuestro artículo sobre cómo prevenir ataques Trojan Source con Snyk Code.

Pero es aún mejor proteger tu base de código de forma proactiva para garantizar que los ataques Trojan Source no lleguen a tu código fuente, en lugar de limitarte a encontrar problemas existentes. En la comunidad de JavaScript, solemos usar ESLint y sus distintos complementos para aplicar estándares de calidad y estilo de código.

Por eso, con eslint-plugin-anti-trojan-source, ahora también puedes incluir un complemento de ESLint para asegurarte de que ninguno de tus desarrolladores ni tus sistemas de integración continua y compilación combine por error código potencialmente malicioso debido a la presencia de caracteres Unicode bidireccionales.

Este es un ejemplo de configuración de ESLint para un proyecto de JavaScript:

"eslintConfig": {
    "plugins": [
        "anti-trojan-source"
    ],
    "rules": {
        "anti-trojan-source/no-bidi": "error"
    }
}

Y este es un ejemplo del resultado para un fragmento de código vulnerable que se incorporó a la base de código:

$ npm run lint

/Users/lirantal/projects/repos/@gigsboat/cli/index.js
  1:1  error  Detected potential trojan source attack with unicode bidi introduced in this comment: ' begin admins only '  anti-trojan-source/no-bidi if (isAdmin) {
  1:1  error  Detected potential trojan source attack with unicode bidi introduced in this comment: ' end admin only    anti-trojan-source/no-bidi }

/Users/lirantal/projects/repos/@gigsboat/cli/lib/helper.js
  2:1  error  Detected potential trojan source attack with unicode bidi introduced in this code: '"user" // Check if admin

¿Cómo está mitigando el ecosistema los ataques Trojan Source?

Los IDE, como VS Code, han lanzado versiones que resaltan estos caracteres Unicode para que los programadores los detecten y actúen con el contexto adecuado al revisar y editar código. De manera similar, GitHub publicó advertencias para que las bases de código visualizadas en GitHub ahora resalten el uso de estos caracteres Trojan potencialmente peligrosos:

Vista de código de GitHub con una advertencia de que el archivo JavaScript contiene texto Unicode bidireccional y una condición que verifica si el usuario es administrador.
Fuente: https://github.com/nickboucher/trojan-source/blob/main/JavaScript/stretched-string.js

Sin embargo, ten en cuenta que GitHub no resalta todos los tipos de ataques de malware Trojan. Por ejemplo, considera el siguiente caso que el artículo presenta y denomina Invisible Functions:

Editor de código que muestra dos funciones isAdmin con nombres similares que devuelven false y true, seguidas de una condición de acceso de administrador.

Como puedes ver en el fragmento de código JavaScript anterior, GitHub no muestra ninguna advertencia al revisar este código. ¿Qué está pasando en realidad?

La declaración de función de la línea 7 está escrita con un carácter de control Unicode de espacio de ancho cero, identificado como U200B, que hace que visualmente parezca una función function isAdmin() legítima.

Podemos verificarlo si imprimimos el código con una herramienta como bat, un clon de la herramienta cat de UNIX que ofrece un mejor resaltado de sintaxis e integración con Git:

Código JavaScript que muestra nombres de funciones visualmente similares con caracteres Unicode invisibles: una devuelve false y otra, true.

¿Los compiladores y los entornos de ejecución deben mitigar los ataques Trojan Source?

¿Y qué pasa con los compiladores y los entornos de ejecución de lenguajes? La mayoría de los lenguajes, incluido Node.js, han decidido no actualizar sus compiladores para que rechacen los caracteres Unicode. En la práctica, esto traslada el riesgo a los editores de código y a las personas, que deben tener más cuidado al leer código y realizar revisiones de código.

Dicho esto, algunos entornos de ejecución de lenguajes, como Zig, han considerado positivamente la posibilidad de generar un error del compilador al detectar el uso de caracteres Unicode bidireccionales en el código fuente y permitir omitir los errores mediante un comentario explícito.

Recursos sobre los ataques Trojan Source

Espero que esta publicación te haya resultado útil para entender los ataques Trojan Source y cómo pueden aparecer en el ecosistema de JavaScript. Para obtener más información sobre estos ataques, te recomiendo consultar los siguientes recursos:

  1. Artículo de blog: Cómo prevenir ataques Trojan Source con Snyk Code

  2. Sitio web oficial de Trojan Source: https://www.trojansource.codes

  3. Repositorio oficial de Trojan Source con ejemplos de código y pruebas de concepto: https://github.com/nickboucher/trojan-source

  4. Artículo oficial del anuncio de Trojan Source:  https://www.lightbluetouchpaper.org/2021/11/01/trojan-source-invisible-vulnerabilities

Protege tu código con información de vanguardia

Conoce todas las funcionalidades de SAST de Snyk Code en solo 30 minutos.