Joven hacker sonriendo

Hackeamos su software

cero falsos positivos

Inteligencia experta + automatización eficaz

Prevenir Ataques HTTP Parameter Pollution

Nuestros ethical hackers explican en que consiste el ataque HTTP Parameter Pollution (HPP) y cuales son las posibles consecuencias que se pueden sufrir al ser vulnerable a dicho ataque. Por último muestran dos manera de prevenir o solventar dicho ataque.

Necesidad

Prevenir ataques HTTP Parameter Pollution.

Contexto

A continuación se describen las circunstancias bajo las cuales la siguiente solución tiene sentido:

  1. Se está desarrollando una aplicación en Java usando servlets.

  2. La aplicación se comunica con otros servidores a través de HTTP/FTP o imprime contenido ingresado por el usuario.

  3. Debe validarse la entrada de información antes de ser usada.

Solución

Hoy día, una de las funciones normales de una aplicación web es permitir al usuario que la visita ingresar datos o información que posteriormente será procesada por la aplicación y sus servidores. El hecho de permitir el ingreso de información por parte del usuario abre la aplicación web a múltiples vulnerabilidades, entre ellas a HTTP Parameter Pollution o HPP.

Este ataque consiste en inyectar delimitadores de query en otros parámetros ya existentes, entonces, si el parámetro donde se realizó la inyección no es validado correctamente, el atacante puede insertar uno o varios parámetros que, en teoría, no deberían existir.

Las consecuencias de un ataque HPP se pueden ver reflejadas tanto del lado del servidor (backend) como en el lado del cliente (frontend). Y esto se debe a que una explotación exitosa de dicha vulnerabilidad le puede permitir a un atacante sobrescribir los parámetros con el fin de modificar el comportamiento de la aplicación, saltar los puntos de validación de los datos de entrada, tener acceso a variables fuera del alcance directo y modificar su contenido, entre otros.

En Java existen algunas formas de prevenir este tipo de ataque. En esta solución expondremos un par de ellas.

Buscando nombres de variables repetidos

  1. Se importan las clases necesarias.

    HPP.java
    1
    2
    3
    4
    5
    import java.io.*;
    import java.net.*;
    import java.util.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    
  2. Se define el nombre de la nueva clase y el método doGet.

    1
    2
    3
    public class HPP extends HttpServlet {
      public void doGet(HttpServletRequest request, HttpServletResponse response)
         throws IOException, ServletException {
    
  3. Hay que obtener la cadena de consulta Query String la cual se forma a partir de todo el contenido entre ? y # de la URL.

    1
    2
    String queryString = request.getQueryString();
    PrintWriter out = response.getWriter();
    
  4. Mostramos el mensaje de detectado o no detectado según el valor retornado por el método checkPollution

    1
    2
    3
    4
    5
    6
    7
      if (checkPollution(queryString)) {
        out.println("HTTP Parameter Pollution detected.");
      }
      else {
        out.println("HTTP Parameter Pollution not detected.");
      }
    }
    
  5. El método principal checkPollution se encargará de recibir la cadena de consulta y determinará si existen nombres de variables que se repiten.

    1
    2
    3
    private boolean checkPollution(String queryString)
      throws UnsupportedEncodingException {
        if (queryString != null) {
    
  6. Se crea un ArrayList que contendrá el nombre de las variables de la cadena de consulta.

    1
    ArrayList<String> keys = new ArrayList<String>();
    
  7. Después hay que decodificar la cadena de consulta usando URLDecoder

    1
    2
    String urlDecoded = URLDecoder.decode(queryString, "UTF-8");
    String[] key;
    
  8. Posteriormente es necesario dividir la cadena de consulta a través del delimitador & con el fin de recorrer cada elemento.

    1
    for (String param : urlDecoded.split("&")) {
    
  9. El parámetro se compone del nombre de la variable y su contenido separados por un =. Así que dividimos estos tokens y los asignamos al atributo key. De esta forma key[0] contiene el nombre de la variable y key[1] su valor.

    1
    String key = param.split("=");
    
  10. Para terminar, se busca el nombre de la variable actual en la lista de nombres de variables; si hay al menos una coincidencia, habrá que retornar verdadero indicando que el ataque está siendo realizado, en caso contrario, el nombre de la variable se agrega a la lista para búsquedas posteriores. El programa retornará falso en cualquier otro caso, indicando de esa forma que no hay ataque HPP.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
          if (key.length > 0) {
            if (keys.contains(key[0]))
              return true;
            else
              keys.add(key[0]);
          }
        }
      }
      return false;
     }
    }
    

Codificar entrada del usuario

  1. . Se importan las clases necesarias.

    HPP2.java
    1
    2
    3
    4
    5
    import java.io.*;
    import java.net.*;
    import java.util.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    
  2. Se define el nombre de la nueva clase y el método doGet. Además se obtiene el objeto para escribir la respuesta en el cliente

    1
    2
    3
    4
    public class HPP2 extends HttpServlet {
      public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException {
          PrintWriter out = response.getWriter();
    
  3. Recibimos los dos parámetros que soporta la aplicación: amount y recipient. Estos dos parámetros se usarán para hacer una transacción ficticia contra un servidor externo. Hay que tener en cuenta que lo más importante es codificar la entrada del usuario con URLEncoder.

    1
    2
    String amount = URLEncoder.encode(request.getParameter("amount"), "UTF-8");
    String beneficiary = URLEncoder.encode(request.getParameter("recipient"), "UTF-8");
    
  4. Una vez codificada, se crea la nueva URL para posteriormente hacer la petición HTTP.

    1
    2
    3
    4
      URL url = new URL("http://ejemplo.com/");
      out.println(httpRequest(url, "action=transfer&amount=" + amount +
        "&recipient=" + beneficiary));
    }
    
  5. El método httpRequest se encarga de recibir la URL y enviar la cadena especificada a través de POST.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public String httpRequest(URL url, String post) {
      String data = "";
      try {
        URLConnection conn = url.openConnection();
        conn.setDoOutput(true);
        OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
        wr.write(post);
        wr.flush();
        BufferedReader rd = new BufferedReader(new
        InputStreamReader(conn.getInputStream()));
        String line = "";
        while ((line = rd.readLine()) != null) {
          data += line;
        }
        wr.close();
        rd.close();
      }
      catch (IOException e) {}
      finally {
        return data;
      }
     }
    }
    

Descargas

Puedes descargar el código fuente pulsando en los siguientes enlaces:

hpp.java HPP ejemplo 1

hpp2.java HPP ejemplo 2




Haz un comentario

Estado de los servicios - Términos de Uso