sábado, 29 de septiembre de 2012

cafein


Este es un manual de como preparar la charla de Test Driven Secure Development que he presentado en in.cafelug.org.ar el 2012/09/29, que es una refactorización profunda de lo presentado en agiles2011, en Agile Open Seguridad 2010 y en una o dos techtalks en Teracode en 2010 o 2011.
La versión original usaba unas funciones de testing que había elaborado para la ocasión y para cambiar el estado de la demo usaba unos ingeniosos scripts, ahora reemplazado por branches de git.

¿Por qué no subo el código que he generado? Por  estricta adherencia al proverbio chino:

Regala un pescado a una persona hambrienta y le darás alimento para un día, enséñale a pescar y le salvarás la vida.

Cualquier duda, me pregunta, yo contesto. Quizas, quizas, muestre esto en Agile Open Seguridad del 24 de noviembre http://www.agiles.org/agile-open-tour/agile-open-buenos-aires-2012---seguridad

Requerimientos de software


Instalar mysql, php, pdo y apache o equivalentes y sus dependencias.

En el navegador data tamper para mostrar bien la manipulación de los post.
  
wireshark para mostrar el tráfico entre el servidor web y la base de datos.
   
wget o curl para efectuar llamadas al servidor web desde bash

grep para evaluar las respuestas

shunit2 para evaluar los resultados esperados contra los obtenidos

git para poder mostrar paso a paso todo el proceso sin escribir ni una linea en el momento de la charla.

La idea

La idea es ir procesando requerimientos o bugs. En caso de ser un bug, está bueno mostrarlo, para eso tenemos wireshark, wget y el navegador. De un modo u otro hacer un test que falle, implementar la solución hasta que el test pase, quizas ajustar el test, quizas agregar otro test. Y seguir asi...

La idea de usar versionamiento la saqué de un curso de Ruby dado por Nicolás Gaivironsky. Give credit where credit is due.

La elección de bash y php pelado como [ausencia de] framework es debido a que al usar frameworks hay mucha magia que mete ruido y no se puede ver bien que ocurre si no se conoce el framework.

Ciertos requerimientos o bugs pueden romper test existentes, hay que arremangarse y arreglarlos o tirarlos.

Aunque la doctrina dice "primero test, luego implementación", la realidad dicta que "primero algo parecido a un test, un poco de implementación, ajuste del test...", como que hay un micro loop.


Una práctica que me resultó muy efectiva es esta secuencia:


git branch 01_xxx
git checkout 01_xxx
crear test
codear
ajustar test y código hasta que funcionen bien
git add test.sh
git commit 
git branch 02_xxx
git checkout 02_xxx

git add codigo
git commit



De este modo, cada branch se comitea cuando ya está el código estable.

Git lola dice:

* a70524e (HEAD, 28_code_session_fixation) code session fixation
* d4542a1 code session fixation rompe tests
* 2b1365a test session fixation
| * 90458ef (27_test_session_fixation) test session fixation
|/ 
* 0d47ab6 (26_session_complete) Refactorizacion completa
* 83bb6c6 (25_test_refactor) Refactorizacion completa con error de xss
* bf042c9 refactorizacion de tests tras incorporacion de session
* 34ae950 (24_code_login_redirect) code login redirect
* 255077f (23_test_login_redirect) test login redirect
* 9b0501f (22_code_login_post) code login post
* fb036a3 (21_test_login_post) test login post
* 9cbe347 (20_code_login) code auth get
* 6b93405 (19_test_login) test auth get
* e4bd6c6 (18_code_session) codigo session
* 531c868 (17_test_session) test basico session
* 33289da (16_code_xss_reflected) code xss reflected
* d568fbe (15_test_xss_reflected) test xss reflected
* 8756029 (14_code_xss_stored) code no xss stored
* e7d961d (13_test_xss_stored) test xss stored
* 5352ff4 (12_code_no_sql_injection) code no sql injection
* 1a29453 (11_test_sql_injection) test sql injection
* 6ec4d4a (10_code_refactor_no_sniffing) code refactor no sniffing
* 913a49d (09_code_persistencia) codigo persistencia
* da5f08f test persistencia
| * 1750417 (08_test_persistencia) test persistencia
|/ 
* 8a1a3fd (07_code_overwrite) codigo auth overwrite
* f0ef483 (06_test_overwrite) test auth overwrite
* d01e7c1 (05_test_refactor) test auth refactor
* 470fecd (04_code_auth) codigo auth
* a7fee5d test auth
| * 65c181b (03_test_auth) test auth
|/ 
| * 765808d (02_code_post) rollback
| * 10ed237 test para auth
|/ 
* 2e63946 codigo post
* ec198a6 (01_test_post) test post
* 9766ef2 (master) inicio


Espero ansioso la ocasión para que alguien me enseñe como transformarlo para que quede en una sola linea, como la que tira git branch

  01_test_post
  02_code_post
  03_test_auth
  04_code_auth
  05_test_refactor
  06_test_overwrite
  07_code_overwrite
  08_test_persistencia
  09_code_persistencia
  10_code_refactor_no_sniffing
  11_test_sql_injection
  12_code_no_sql_injection
  13_test_xss_stored
  14_code_xss_stored
  15_test_xss_reflected
  16_code_xss_reflected
  17_test_session
  18_code_session
  19_test_login
  20_code_login
  21_test_login_post
  22_code_login_post
  23_test_login_redirect
  24_code_login_redirect
  25_test_refactor
  26_session_complete
  27_test_session_fixation
  28_code_session_fixation


Todo esto se reduce a la siguiente lista de requerimientos o bugs:

Requerimiento: Crear una página que permita postear comentarios

  Fácil, un formulario

Requerimiento: Agregar autenticación

  Fácil, agregar user/pass con contraseñas hardcodeadas

Bug: Se pueden pisar las variables y evitar la autenticación

La implementación era:

foreach($_POST as $key=>$value) {
  $user[$key]=$value;
}

if ($user['user']=='ana' && $user['pass'] == 'ana123') {
   $user['valid']=true;
}


El ataque es --post-data="text=post sin permiso&valid=1"

La solución es... sólo tomar los parámetros que estamos esperando.

Requerimiento: Persistir los comentarios en una base de datos

Fácil, consultar en la base en lugar de hardcoded

Bug: Se ha detectado un error de diseño que permite ver las credenciales de todos los usuarios circulando entre el servidor web y la base de datos.

El código era

$result = mysql_query('select * from user') or die('no query');

while ($entry = mysql_fetch_assoc($result)) {
  if ($entry['name'] == $user['user']
      && $entry['pass'] == $user['pass']
  ) {
    $user['valid'] = true;
    break;
  }
}


esta es la captura de wireshark entre el web server y la base de datos, ademas no escala si tenés un millón de usuarios.

Lo que me gusta de este error es que lo he visto en la vida real una vez.

Bug: Se ha detectado sql injection que permite evitar la autenticación


Reemplazamos sql pelado por Prepared Statements

Bug: Se ha detectado xss

Al menos hay que poner htmlentities() al mostrar los posts.

Requerimiento: Agregar session y una página independiente para login


Esto fue un pijazo, no hay otra palabra. Tuve que tirar todos los tests e ir recuperandolos de a poquito, va desde 17_test_session hasta   26_session_complete


Bug: Se ha detectado session fixation, que permite a un atacante "colgarse" de una sesión ajena.


Hay que agregar sesión

        if (loginOk()) {
            session_regenerate_id();
            $_SESSION['valid'] = true;
             header('Location: chat.php');
            exit();
        }

Ejemplo de un test


Para testear he usado sshunit2, wget y grep, veamos un ejemplo detallado, de los últimos:
testXSSstored(){el nombre "test" le permite a sshunit2 hallarlo
    setupDBversion1ponemos la base en un estado conocido
    rm cookies.txt -fpor las dudas tiramos las cookies que puedan haber
    wget -q -O - --post-data="user=ana&pass=ana123" http://127.0.0.1/login.php --keep-session-cookies \ --save-cookies cookies.txt > /dev/nullnos autenticamos salvando las cookies estoy usando header("Location: chat.php") en login. con max-redirect=0 se impide la redirección, tiramos el output a stdout con -O - y de ahi a /dev/null, le pedimos con -q que no diga nada de como le fué
    wget -q -O - --post-data="text=<script>alert(12*12)</script>" http://127.0.0.1/chat.php --load-cookies cookies.txt > /dev/nullle decimos que tome las cookies que habiamos recibido antes y hacemos el ataque
    rm cookies.txt -f
    wget -q -O - --post-data="user=ana&pass=ana123" http://127.0.0.1/login.php \ --keep-session-cookies | grep -q -F "<script>alert(12*12)</script>"volvemos a autenticarnos, aceptamos la redirección y vemos si el script está intacto
    RESULT=$? guardamos el resultado de la operación anterior
    assertEquals 1 $RESULT
}
que debe ser 1 si no hubo match, que es lo esperado en este caso y 0 si hubo, será uno u otro dependiendo de lo que estemos testeando

La implementación esta es para dejar la base de datos en un estado conocido antes de cada test que necesite datos

setupDBversion1() {
  echo "drop database chat;
  create database chat;
  use chat;
  create table messages(message varchar(64));
  create table user (name varchar(16), pass varchar(32));
  insert into user values (\"ana\",\"ana123\");
  insert into user values (\"root\",\"root_pass\");
  insert into user values (\"master\",\"master_pass\");" \
  | mysql -u admin chat
}

. shunit2 ;# esto invoca la ejecución de todos los tests


Este es un ejemplo de ejecución donde eliminé el htmlentities() y entró el xss. Es importante romper el código una vez que el test pasa para estar seguros que el test lo detecta.




Detalles de configuración


apache

Crear un htdocs accesible tanto por apache como por el usuario de ejecucion modificar configuración apache para que apunte a la carpeta de trabajo crear repositorio de git (git init)



mysql


create user 'admin'@'localhost';

grant all on chat.* to 'admin'@'localhost';

Es una decisión controvertida quedarse sin password, pero la opción que mejor conozco es usar expect, que no aporta a la demo.

lunes, 24 de septiembre de 2012

Ekoparty 2012

Este año me he llevado varias cosas:

La práctica hace al maestro

Muy buenos los HTExploit (Soler/Katz), parece un número de teatro [1], muy bien llevado.

Plan B


Brillante como el muchacho de los ataques USSD[2] contra Android zafó cuando le falló el primer ataque. Quizo mandar un sms que nunca llegó, entonces, sin perder la calma, le metió el link a manito.

 

Exótico

Que un overflow de unos enviado a un IVR[3] provoque un stack trace y que el sistema te lo lea.

 

Ataque o accidente de Ingeniería Social

El último día fuí víctima de un ataque de ingeniería social o de un accidente.

Mientras iba en bici municipal desde el centro, o mejor dicho, mientras caminaba las ocho cuadras desde el nodo hasta el Konex pensaba que hubiera estado bueno un nodo temporario allí. En la puerta me encontré a Juan Pablo, que sé que es uno de los organizadores y lo interpelé:

-Hola, tenés medio minuto? No me conocés pero...
-Sí que te conozco- me interrumpió.
-Puede ser, del barquito del año pasado, quizas...- agregué mientras forcejeaba con mis credenciales para entrar. (TOMAR NOTA DE ESTE MOMENTO)

Ya autenticado caminamos unos metros juntos mientras le exponía la idea.

-Quizas se pueda gestionar el año que viene un centro temporario de distribución de bicicletas acá. Yo he venido tanto ayer como hoy desde el centro asi.
-Buena idea, la anoto.

Paralelamente en mi mente otro thread conversaba conmigo

-Tanto el de seguridad de la puerta como Juan Pablo deben pensar que soy el tipo más estúpido del mundo, ¡no puede ser como le dí servida la información!

Aunque es verdad que habíamos conversado algo el año pasado y si tiene algo de memoria quizas me recordaría, obsérvese como soy yo quien provée la información. Él puede estar recordando o apostando.

Lo interesante es que nunca voy a saber que ocurrió en realidad:


RecordabaNo recordaba
Lo admiteNo lo admite
Es un ingeniero socialAcá no pasó nada...Se revela como ingeniero social y que me atacó, difícil¿Qué esperabas?
No es un ingeniero socialSimplemente me recordabaEs mentirosoEs un ingeniero social nomás

Always crashing in the same car [4][5]

El primer día ya quedó claro que la resolución, ajuste de color y contraste del proyector no se correspondían con lo que había en el monitor de cada expositor. Esto provocaba que ciertas combinaciónes de colores no se vieran y desaparecieran lineas.

Mis preguntas son:

¿Ningún expositor vió como un expositor previo fallaba y por ende ajustó su presentación para que no le pasara lo mismo?

¿Nadie de la organización tuvo una reflexión similar y alertó a los siguientes expositores?

Si la respuesta fuera "Alguien reparó en ello y los expositores alertados decidieron que no valía la pena", ¿por qué cada uno de ellos mostró sorpresa o consternación cuando le llegó el turno?


Las semillas


  • Unos señores pelados mostraron lo mal que están unos sistemas hogareños y comerciales de alarmas comunes en USA. Han recopilado un montón de mensajes que se construyen con un hash, cuya fórmula desconocen. Les he solicitado que me los envíen a ver si puedo aportar algo.

  • Conversando con el master de w3af: no lo pude convencer de migrar a erlang, pero si le sembré la duda acerca de como está su sistema de testing, tema para el próximo Agile Open [6] 
  • VGA Rootkit: flashearon el firmware de la placa de video y metieron código arbitrario. Si tuviera tiempo vería de...

La llave del conocimiento

El primer día lo "perdí" en lockpicking village. Cuando mi jefa se enteró me encajó un "eso no aporta valor". Permítanme disentir.

Por un lado aprendí lo fácil que es abrir un candado o cerradura, lo cual no es relevante en sí. Pero el poder ver como un mecanismo mecánico se puede trampear una vez que ha sido comprendido (o incluso sin comprenderlo, a lo script kiddie) al menos a mi me pone en un modo mental de ver los mecanismos informáticos, de procedimiento o mentales en la misma sintonía. Estos mundos son muy abstractos y en última instancia "irreales". Así como la autoridad, la ley y todas esas cosas de la conviviencia social terminan apoyándose en un revolver, las cerraduras, las cajas fuertes, las paredes, puertas y los alambres de púa son el cimiento final de la seguridad.

Recuerdo el final de 2001 (en libro) cuando Bowman en su nuevo plano de existencia se apodera de un arma en órbita, me parece, llega al final de todos los circuitos y allí hay un relé que lo detiene momentaneamente, pues es real.

Como anécdota sabrosa, al salir busqué una persona de cerca de ocho años, le mostré como y en pocos minutos abrió dos candados con mis herramientas recientemente construidas. El tercero lo abrió con un clip en pocos segundos.

Como detalle deprimente, acabo de probar un candado que uso. Me llevó veinte segundos poner las herramientas en posición y cuatro abrirlo. Yo no tengo experiencia, ¡es muy poco!

¿Esposas? menos de diez segundos, suerte de principiante. Supongo que son muy chotas.

El postre


Expuesto por /home/$user






[1] http://www.mkit.com.ar/labs/htexploit/
[2] http://en.wikipedia.org/wiki/Unstructured_Supplementary_Service_Data
[3] http://en.wikipedia.org/wiki/Interactive_voice_response
[4] http://www.youtube.com/watch?v=l2vEtfyveeY
[5] http://www.metrolyrics.com/always-crashing-in-the-same-car-lyrics-david-bowie.html
[6] http://www.agiles.org/agile-open-tour/agile-open-buenos-aires-2012---seguridad

sábado, 1 de septiembre de 2012

Automatización de test - eci 2012

Resumen práctico del curso "Generación Automática de Tests Unitarios" (ECI 2012 N2) a cargo de Nazareno Aguirre, Universidad Nacional de Río Cuarto, Argentina


Esta reseña es solo un disparador, no es una guía ni una explicación detallada, es el resultado de hacer la práctica y el examen. Omito cosas importantes que supongo conocidas, pongo el foco en detalles secundarios y mecho con mis opiniones. Aclaro que mi relación con java es meramente académica, carezco de experiencia profesional. Sí tengo experiencia en unit testing, TDD y desarrollo en general.

Lo que se vió en el curso fue diversas maneras de automatizar el testing, ya sea generando tests, generando entrada para los tests o probando la resistencia de los tests.

Mi stack fue:
windowslinux
oracle java 1.7 (ups! la del 0day exploit!!openjdk con JavaSE-1.6 como execution environment para que funcione randoop
eclipse 3.7.2 indigo for java developerseclipse 4.2? juno for java developers
codecover 1.0.1.2
randoop 0.1.0.201107281327
jumble 1.0.0
korat 1.0
korattester 0.0.5 (FAIL)


CodeCover


Herramienta de análisis de cobertura de código.

La idea es que diversos aspectos de un programa como cada linea, cada decisión y cada camino posible sean recorridos por los test. Esta herramienta mide justamente eso.

Hay que habilitar para el proyecto (Propiedades->CodeCover->Enable Code Cover) y seleccionar criterios, luego seleccionar una clase a analizar (right click -> "Use for code coverage measurement") y finalmente ejecutar un test como "CodeCover measurement for junit".

Si hay distintos test cases se pueden agrupar en una suite o ejecutar cada uno separado y luego activar ambos resultados. Al activar (o como se llame) cada resultado, en el código fuente se ve la cobertura o su falta.

Instalación


via repo

Randoop


Herramienta de generación test al azar con feedback.

Para cada método, intenta generar código tal que se pueda llamar a ese método y dependiendo de los resultados, fallas y excepciones declaradas y lanzadas, detecta situaciones de falla y genera código de test para regresiones. Requiere que cada clase tenga un método repOk() que comprueba que el objeto esté en un estado válido. No es necesario que este método haga una validación completa.

Un ejemplo de repOK() para una pila

@CheckRep
public boolean repOk() {
    if (numItems < 0 ) return false;
    if (numItems == 0 && tope != null) return false;
    return true;
}


Uno mas completo que comprueba que el número de items corresponda a la realidad y que no sea una lista con un loop:

@CheckRep
public boolean repOK() {
    int cantidad = numItems;
    Nodo corr = tope;
    while (cantidad>0 && corr!=null) {
        corr = corr.obtenerSiguiente();
        cantidad--;
    }
    return (cantidad==0 && corr==null);   
}



Un ejemplo del código de test generado:

public void test49() throws Throwable {
    myUtils.PilaSobreListasEnlazadas var0 = 

        new myUtils.PilaSobreListasEnlazadas();
    var0.apilar((java.lang.Object)'#');
    java.lang.Object var3 = var0.tope();
    var0.desapilar();
    boolean var5 = var0.esVacia();
    var0.apilar((java.lang.Object)0L);
   
    // Regression assertion (captures the current behavior of the code)
    assertTrue("'" + var3 + "' != '" + '#'+ "'", var3.equals('#'));
   
    // Regression assertion (captures the current behavior of the code)
    assertTrue(var5 == true);
}


Hay que elegir una clase, right click -> Run as Randoop test input, poner un criterio de stop, algunos maximums y ejecutar. En el package/name provisto se generarán los test.


Tiene varias utilidades:

  • Teniendo tests, ver si no hay algún errorcito extra por ahi.
  • A partir de una implementación correcta pero ineficiente, tener una referencia para optimizarla.
  • A partir de una implementación ajena, tener una referencia para reimplementarla. ¡Ups!, ¿no será ilegal?
  • Testear código legacy, aunque con algunas restricciones. Si este código legacy no tiene tests, por algo será, ¿no? Probablemente tenga interdependencias y partes no mockeables que pueden imposibilitar la ejecución. Nada mejor que correr secuencias interminables de código al azar sobre un sistema en producción conectado a una base de datos.


Instalación


Bajar el jar y ponerlo en plugins

Jumble


Herramienta de code mutation.

Lo que hace es dada una clase y su testcase, cambiar en la clase algunas cosas como operadores aritméticos y lógicos y ejecutar el test. Si no falla, considera que está mal el test.

Sólo hay que elegir una clase, right click y "jumble class".

Al usar Parametrized Test Classes, me encontré con un problema. Como resuelve la clase de test por convención de nombres, hay que poner en un solo testcase los test parametrizados y los no parametrizados, lo que produce una ejecución de los tests no parametrizados repetida tantas veces como los parámetros, totalmente innecesaria. Hay una anotación, @TestClass, pero no logré que la respete ni apuntando a uno y otro test ni a una test suite con ambos.

Instalación


bajar el zip y copiar

cp -r jumble_1_1_0/eclipseplugin/plugin-export/jumble eclipse/plugins/

Korat


Herramienta para generar datos de entrada para test exhaustivos acotados.

Supongamos que queremos probar algún método con arrays de 4 posiciones con 4 valores. Se pueden generar todas las combinaciones sin problemas. Ahora bien, si la estructura es más compleja, como un árbol, la cosa se complica pues ya no sólo hay que generar los datos si no la estructura, lo cual produce varios inconvenientes:

  • muchas combinaciones
  • resultados redundantes (si tienen la misma forma, ¿que me importan los nodos en si?)
  • hay estructuras que pueden ser inválidas (loops, desconexiones)
  • pueden haber otros constraints, como que los datos estén ordenados en un árbol binario de búsqueda.

Korat, mediante una invariante y una breve descripción, puede generar estructuras válidas, no redundantes.



La mejor (única) manera que encontré de usar korat es bajar el snapshot del svn y agregar a examples la clase a analizar, luego se llama como en los ejemplo provistos, pero usando nuestra clase.

java -cp korat.jar korat.Korat --class korat.examples.colas.ColaSobreListasEnlazadas --args 4,0,1 --visualize

Los ejemplos son muy claros para estructuras, pero no hallé la manera de poblar los nodos de las estructuras cuando estos usaban objetos genéricos.

En eclipse he agregado korat.jar al build path para autocompletar con todo éxito.

Intenté usar un plugin de korat para eclipse, korattester, pero no funciona.

Instalación


svn co https://korat.svn.sourceforge.net/svnroot/korat/trunk/ korat


Pex


Este es el que menos pude investigar, ya que es para .NET.

No tengo nada que decir, sólo que pex4fun es muy divertido, si sos nerd.

Referencias


[eci n2] http://www.dc.uba.ar/events/eci/2012/cursos/aguirre

[docente]  http://dc.exa.unrc.edu.ar/staff/naguirre/Pagina_personal_de_Nazareno_Aguirre/Principal.html

[practica] https://sites.google.com/site/genunittests/


[java] http://www.oracle.com/technetwork/java/javase/downloads/index.html

[eclipse] http://www.eclipse.org

[codecover] http://codecover.org/

[codecover eclipse] http://update.codecover.org/

[randoop] http://code.google.com/p/randoop/

[randoop eclipse] http://randoop.googlecode.com/hg/plugin.updateSite/

[jumble] http://jumble.sourceforge.net/

[korat] http://korat.sourceforge.net/

[korattester] http://code.google.com/p/korattester/

[pex] http://research.microsoft.com/en-us/projects/pex/

[pex for fun] http://www.pexforfun.com

[pex standalone download] http://research.microsoft.com/en-us/downloads/d2279651-851f-4d7a-bf05-16fd7eb26559/default.aspx