¿Cómo se utilizan las codificaciones de caracteres para omitir los desinfectantes XSS?

8

Leí en diferentes blogs que la función PHP htmlspecialchars() tiene ciertos problemas cuando uno no da el conjunto de caracteres esperado como un parámetro opcional.

¿Alguien puede explicar algunas cosas básicas sobre las vulnerabilidades de XSS que surgen del mal uso de las funciones de desinfección con algunos ejemplos relacionados con la codificación de caracteres?

¿Esto también afecta a los navegadores modernos?

    
pregunta XII 28.02.2018 - 08:26
fuente

3 respuestas

11

El problema

Abusar de las codificaciones de caracteres es un truco popular para hacer que XSS funcione, incluso cuando hay filtros en su lugar. Hay una serie de situaciones diferentes cuando funciona, pero todas comparten prerrequisitos comunes:

  • El atacante envía una carga útil en la codificación de caracteres A.
  • El servidor que realiza el filtrado o sanitazion está trabajando en la codificación de caracteres B.
  • El navegador de las víctimas está interpretando la página como si estuviera en la codificación de caracteres A.

Veamos dos ejemplos de cómo esto puede ocurrir.

Ejemplo # 1: No hay parámetro de codificación en htmlspecialchars

Esta es una vista bastante común en PHP:

echo htmlspecialchars($_GET["query"], ENT_COMPAT | ENT_HTML401);

El problema aquí es el comportamiento predeterminado al que PHP recurre cuando no se especifica ninguna codificación. De el manual :

  

Si se omite, el valor predeterminado de la codificación varía según la versión de PHP en uso. En PHP 5.6 y versiones posteriores, la opción de configuración default_charset se usa como valor predeterminado. PHP 5.4 y 5.5 utilizarán UTF-8 como predeterminado. Las versiones anteriores de PHP utilizan ISO-8859-1.

Entonces, qué codificación PHP utiliza depende de su versión y configuración. Genial. Así que ahora todo lo que se interpone entre usted y el abismo es alguien que realiza un cambio inocente en php.ini , o tal vez algo tan simple como una actualización o reinstalación del servidor. A mí también me gusta vivir peligrosamente ... pero no tan peligrosamente.

Tenga en cuenta que este ejemplo no tiene nada que ver con el navegador. Moderno o viejo, no importa, porque el problema es el servidor y no el navegador.

La solución, por supuesto, es especificar la codificación correcta y asegurarse de que se especifique lo mismo en el encabezado HTTP Content-Type de la respuesta:

echo htmlspecialchars($_GET["query"], ENT_COMPAT | ENT_HTML401, "UTF-8");

Ejemplo # 2: heurísticas del navegador que te muerden

Esto es un problema si su servidor no especifica qué codificación está usando en la respuesta (o si solo lo hace en una etiqueta meta que está demasiado abajo para que el navegador se preocupe por eso). Si no le dice al navegador qué codificación usar, tendrá que adivinar. Desafortunadamente, todos los navegadores no son tan buenos en eso :

  

Si ciertas cadenas de entrada del usuario (por ejemplo, +ADw-script+AD4-alert(1)+ADw-/script+AD4- ) se repiten lo suficientemente pronto en la página HTML, Internet Explorer puede suponer incorrectamente que la página está codificada en UTF-7. De repente, la entrada del usuario, de otro modo inofensiva, se convierte en HTML activo y se ejecutará.

La carga útil en la cotización es <script>alert(1)</script> codificada en UTF-7. Un desinfectante que trabaje en UTF-8 no verá nada peligroso en esa carga útil y lo dejará pasar, pero el navegador con el que se engaña para que funcione en UTF-7 todavía lo ejecutará.

Entiendo que es en su mayoría versiones antiguas de IE donde esto es un problema. Pero no estoy seguro, así que me encantaría ver otra respuesta donde se aclare.

EDIT: Consulte La respuesta de Xavier59 para obtener un situación en la que funciona en los navegadores modernos.

La solución

Lo que debes hacer en el servidor es simple en teoría. Debe asegurarse de que siempre se cumpla lo siguiente:

  • La codificación de caracteres de la respuesta se establece correctamente en los encabezados HTTP.
  • El filtro XSS está funcionando en la misma codificación que se especificó anteriormente.

En la práctica, es sorprendentemente fácil hacerlo mal.

    
respondido por el Anders 28.02.2018 - 14:12
fuente
5

Esto viene como una adición a la respuesta de Anders (lo cual es genial por cierto).

  

Tengo entendido que en su mayoría son versiones antiguas de IE.   un problema. Pero no tengo una fuente para eso, y no estoy seguro, entonces   Me encantaría ver otra respuesta donde se aclare.

Sí, esto afecta a los navegadores modernos.

Tomemos el siguiente saneamiento:

<?php
    header('Content-Type: text/html;charset=utf-8');
    echo preg_replace('/<\w+/', '', $_GET['name']).", can you p0wn it ?"
?>

Esto puede no parecer vulnerable porque:

  • El < seguido de una o más letras se está eliminando, por lo que un atacante no puede abrir una nueva etiqueta.
  • El encabezado Content-Type está configurado correctamente en utf-8

Ahora, imagine que enviamos %00%3C%00 , el analizador de expresiones regulares fallará porque < ( %3C ) no va seguido por una letra (como se define por \w ) sino por %00 (el byte nulo ). En UTF-8 , la entrada reflejada no se ejecutará, pero si podemos encontrar una manera de reflejarla en UTF-16 ...

Aquí está lo que podemos leer de W3 :

  

Si tiene una marca de orden de bytes (BOM) UTF-8 al inicio de su archivo   Luego, las versiones recientes del navegador que no sean Internet Explorer 10 u 11   lo utilizará para determinar que la codificación de su página es UTF-8. Es   tiene una prioridad más alta que cualquier otra declaración, incluyendo HTTP   encabezado.

     

Podría omitir la declaración de codificación meta si tiene una lista de materiales, pero nosotros   Le recomendamos que lo guarde, ya que ayuda a las personas que miran el   Código fuente para determinar cuál es la codificación de la página.

El carácter BOM en UTF-16 es el carácter unicode U+FEFF (la codificación BOM diferente se describe mejor en Wikipedia ). Por lo tanto, como nuestra entrada se refleja al comienzo del dom , podemos cambiar el conjunto de caracteres a UTF-16 y hacer que nuestro código se ejecute.

Carga útil completa:

%FE%FF%00%3C%00s%00c%00r%00i%00p%00t%00%3E%00a%00l%00e%00r%00t%00(%00%22%00P%000%00w%00n%00e%00d%00%22%00)%00;%00%3C%00/%00s%00c%00r%00i%00p%00t%00%3E

Aquí hay un POC que hice. La mayoría de los auditores xss no lo aceptarán, pero Firefox lo hará ya que su auditor está deshabilitado de forma predeterminada. (probado en Firefox Nightly 60.0a1 - última versión a partir de hoy)

Sin embargo, htmlspecialchars y htmlentities no caerán en ello. Sin embargo, esto demuestra que siempre hay casos difíciles de borde a la vuelta de la esquina.

Otros ataques a la codificación incluyen mapeo de caracteres que también son relevantes a partir de hoy.

    
respondido por el Xavier59 28.02.2018 - 20:22
fuente
1

De la OWASP XSS :

  

"Los ataques de secuencias de comandos entre sitios son un tipo de problema de inyección, en   que los scripts maliciosos se inyectan en el benigno y por lo demás   sitios web de confianza. Los ataques de scripts entre sitios (XSS) ocurren cuando un   el atacante usa una aplicación web para enviar código malicioso, generalmente en   la forma de un script del lado del navegador, a un usuario final diferente. Defectos que   Permitir que estos ataques tengan éxito están muy extendidos y ocurren en cualquier lugar.   una aplicación web utiliza la entrada de un usuario en la salida que genera   sin validarlo ni codificarlo.

     

Un atacante puede usar XSS para enviar un script malicioso a un confiado   usuario. El navegador del usuario final no tiene forma de saber que el script debe   No se podrá confiar, y se ejecutará el script. Porque piensa el   El script provino de una fuente confiable, el script malicioso puede acceder a cualquier   cookies, tokens de sesión u otra información confidencial retenida por   Su navegador y utilizado con ese sitio. Estos scripts pueden incluso reescribirse.   El contenido de la página HTML. "

Este es un ejemplo de malas prácticas de codificación en las que no se sanea la entrada del usuario.

Imaginemos que usted es un desarrollador web y crea este archivo en su sitio web ( name.php ):

<form action="" method="GET">
  What is your name: <input type="text" name="username"><br>
  <input type="submit" value="Submit">
</form>

<?php
  print("Entered name is: ".$_GET["username"]);
?>

Al abrir esta página en su navegador, verá algo como esto:

Pongamosunnombreyveamoselcomportamientodeestesimplearchivo,yaqueestamosusandoelmétodoGET,podremosverlosdatosenviadosenlaURL:

Pero,¿quésucedesialguienintentainyectaralgodecódigoHTMLenestecuadroinput, algocomo

<marquee><h1>Andrewng</h1></marquee>

Vealosresultadosenlaimagenacontinuación:

Laentradadelusuarioserepresentócomosiformarapartedelcódigofuenteoriginaldelarchivo.

Ahora,siintentamoslomismoconelcódigoJavascript,veamosquésucede,elcódigodeinyecciónparaprobarenlosnavegadoresserá2formasdeXSS:

<h1>Andrew</h1><script>alert("XSS");</script>

<META HTTP-EQUIV="refresh" CONTENT="0;url=data:text/html;base64,PHNjcmlwdD5hbGVydCgndGVzdDMnKTwvc2NyaXB0Pg">

En ambos casos, Google Chrome bloqueó la ejecución de este script:

Pero,enMozillaFirefox,ambassecuenciasdecomandosseejecutancorrectamente:

EsperoqueestopuedabrindarleunamejorcomprensióndeXSSylasituaciónactualconlosnavegadoresmodernos,estoseprobóen:

  • GoogleChrome64.0.3282.119(versiónoficial)(64bits)
  • MozillaFirefoxQuantum58.0(64bits)

Sobrelafunciónhtmlspecialchars()puedeencontrarmásinformación aquí .

Otro ejemplo de XSS que podría interesarte es este en mi blog.

Espero que ayude.

    
respondido por el galoget 28.02.2018 - 09:27
fuente

Lea otras preguntas en las etiquetas