miércoles, 14 de mayo de 2008

Enviando ficheros comprimidos por red

Para enviar archivos en red local puntualmente sin tener que abrir un servicio de ftp se puede usar netcat. Si se trata de archivos grandes podemos comprimir el archivo al vuelo para disminuir el tiempo que tarda la transferencia.

En la máquina que tiene el archivo:

cat ARCHIVO | gzip --fast | netcat -l -p PUERTO

En la máquina a la que queremos enviarlo:

netcat HOST PUERTO | gunzip > ARCHIVO

martes, 13 de mayo de 2008

Generadores en python

Python es un lenguaje multiparadigma que soporta gran cantidad de conceptos de programación, pero uno del que nunca había oido hablar y me ha llamado la atención son los generadores.

Un generador es una función especial que va creando valores sobre los que iterar.

Supongamos que queremos iterar sobre el conjunto de los números primos.

#!/usr/bin/python

from math import sqrt

def esPrimo(n):
root=int(sqrt(n));
for i in range(2,root+1):
if n%i==0:
return False;
return True;


def generadorPrimos(n):
for i in filter(esPrimo, range(2,n+1)):
yield i


for i in generadorPrimos(100):
print i;

Primero debemos definir la función esPrimo que no tiene ningún misterio, en la función generadorPrimos usamos filter, este comando produce una lista a partir de la que le pasamos como parámetro, pero tan solo con los elementos que cumplen la condición pasada en el primer parámetro.

Es decir, en el ejemplo devolvería una lista con los números primos entre 2 y n (inclusive), posteriormente iteramos sobre la lista de números primos y devolvemos cada uno de ellos. En el caso de los generadores se devuelve el valor con yield.

Ahora cada vez que queramos iterar sobre los números primos podemos usar el método generadorPrimos.

Al principio puede que cueste encontrar una utilidad práctica a los generadores, sin embargo pueden ayudar en multitud de ocasiones, unos ejemplos que se me ocurren, generar n números aleatorios entre a y b.

#!/usr/bin/python

from math import sqrt
import random

def generadorAleatorios(a,b,n):
for i in range(0,n):
yield random.randint(a, b);

for i in generadorAleatorios(1,100,10):
print i;

O incluso se pueden ir generando IPs aleatorias válidas.

#!/usr/bin/python

from math import sqrt
import random

def generadorIPs(n):
for i in range(0,n):
a=random.randint(0,255);
b=random.randint(0,255);
c=random.randint(0,255);
d=random.randint(0,255);
yield str(a)+"."+str(b)+"."+str(c)+"."+str(d);

for i in generadorIPs(10):
print i;

lunes, 5 de mayo de 2008

Cifrando los datos de un pendrive

Acostumbramos a llevar en nuestros pendrives información privada. El problema es que estos dispositivos tienen una tendencia especial a perderse :P.

Una posible solución es cifrar el sistema de ficheros del pendrive, desgraciadamente la mayoría los tenemos formateados en FAT y este sistema no admite cifrado.

Ningún problema para nosotros, si no admite cifrado el sistema de ficheros, pues nos hacemos un programa que lea el dispositivo en linux y lo cifre todo haciendo a los datos XOR con nuestra clave.

#include<stdio.h>

#define PENDRIVE "/dev/sdb1"
#define BUFFERSIZE 4096

int main(){
int i, j, leido, nBytes;
FILE *fichero;
int buffer[BUFFERSIZE];

fichero=fopen(PENDRIVE, "rw+");

//Hallar el tamanio del fichero
fseek(fichero, 0, SEEK_END);
nBytes=ftell(fichero);
fseek(fichero, 0, SEEK_SET);

//Leer,escribir y encriptar el fichero/dispositivo
for(i=0;i<nBytes;i+=BUFFERSIZE){
leido=fread(buffer, 1, BUFFERSIZE, fichero);
fseek(fichero, -leido, SEEK_CUR);

for(j=0;j<leido;j++) buffer[j]=buffer[j]^0x12345678;

fwrite(buffer, leido, 1, fichero);

if(i%(BUFFERSIZE*1000)==0){
printf("%.1f%\n",(i*100.0)/nBytes);
}
}

fclose(fichero);
}

En este caso la clave es 0x12345678 (en hexadecimal), y el dispositivo /dev/sdb1.
Sirve tanto para pendrives, disquetes, ficheros, todo en linux es un fichero.
Para desencriptarlo tan solo hay que volver a ejecutar el programa.

Si alguien intenta leer los datos del pendrive cuando están cifrados, simplemente parecerá que el pendrive no tiene formato ya que también se encripta la tabla FAT.

Evidentemente el algoritmo de encriptación se puede mejorar, tan solo es una idea.

sábado, 29 de diciembre de 2007

Primeros pasos con jQuery

jQuery es una librería de JavaScript, su principal utilidad es dar un acceso más claro y sencillo a los elementos de la web mediante la filosofía DOM.

La librería es muy sencilla de instalar, tan solo hay que ir a la web de jQuery, descargar la última versión, subirla al servidor web e incluirla en donde queráis usarla de la siguiente forma (como cualquier fichero javascript):

<script type="text/javascript" src="jquery.js"></script>

Casi todos los códigos que usen jQuery comenzarán así:

$(document).ready(inicializar);

¿Qué significa esa línea de código? "Cuando se descargue la página web por completo llama a la función 'inicializar'".

Esa función 'inicializar' será la que asignará cada evento a cada elemento del DOM de la página.
Para los ejemplos voy a utilizar una web con 6 botones y una caja de texto:

<html>
<title>Titulillo</title>
<h1>Prueba</h1>

<body>

<input type="button" id="boton1" value="click">
<input type="button" id="boton2" value="click">
<input type="button" id="boton3" value="click">
<input type="button" id="boton4" value="click">
<input type="button" id="boton5" value="click">
<input type="button" id="boton6" value="click">
<input type="text" id="text1" value="click">

</body></html>

La función 'inicializar' sería algo como lo que sigue:

function inicializar(){
$("input").click(BotonClick);
$("input").hover(
function() { $(this).addClass("blanco"); $(this).removeClass("rojo");},
function() { $(this).addClass("rojo"); $(this).removeClass("blanco"); }
);
}

Esta función asocia a todos los elementos "input" de la página el evento "click" con la función 'BotonClick', así que cada vez que hagamos click en un botón de la página o en la caja de texto se ejecutará esa función.

La segunda hace lo mismo con el evento "hover", pero en esta ocasión se le asocian dos funciones, la primera se ejecutará cuando el ratón pase por encima de un elemento "input" y la segunda cuando salga de su espacio.

Otra diferencia es que las funciones asociadas son anónimas (no se pueden llamar desde otro sitio).

¿Qué hacen esas funciones? El código de las dos es muy parecido, añaden al objeto la clase rojo y eliminan la clase blanca y viceversa.

¿Para qué? Asociando los objetos de la página mediante clases se pueden manipular de forma más sencilla, por ejemplo, en el caso anterior si la página tuviera el siguiente código css:

<style>

.blanco{
background-color:#ffffff;
}

.rojo{
background-color:#ff0000;
}

</style>

Los elementos "input" de la página cambiarían de rojo a blanco y de blanco a rojo al pasar por encima de ellos con el ratón.

Hay muchas posibilidades, otro ejemplo de lo que se puede hacer:

function BotonClick(){
$(this).hide();
}

El elemento en el que se haga click desaparecerá, gracias a cosas como esta se puede reconstruir la interfaz de una página dinámicamente.

viernes, 21 de diciembre de 2007

Enviar formularios con javascript

Normalmente, el código html para enviar un formulario es algo parecido al siguiente:
Introduzca su nombre:
<form action="index.php" method="get">
<input name="nombre" type="text">
<input value="Enviar" type="submit">
</form>

Pero puede darse el caso, de que en nuestra página nos interese enviar el formulario al hacer click en un enlace, eso se puede solucionar mediante javascript de la siguiente forma:

Introduzca su nombre:
<form action="index.php" name="formulario" method="GET">
<input type="text" name="nombre">
<a href=javascript:document["formulario"].submit();>Enviar</a>
</form>

Aunque funciona correctamente no queda demasiado bien que el usuario vea el código javascript al pasar por encima del enlace, se puede ocultar cambiandolo por lo siguiente:

Introduzca su nombre:
<form action="index.php" name="formulario" method="GET">
<input type="text" name="nombre">
<a href=# onclick=javascript:document["formulario"].submit();>Enviar</a>
</form>

Bueno, aunque todos los enlaces los he colocado entre las etiquetas form del formulario, pueden estar en cualquier otro sitio, por ejemplo:

Introduzca su nombre:
<form action="index.php" name="formulario" method="GET">
<input type="text" name="nombre">
</form>

<a href=# onclick=javascript:document["formulario"].submit();>Enviar</a>

Igualmente, he usado enlaces para colocar el código javascript, pero es indiferente, se puede colocar el código en cualquier elemento que soporte javascript.

jueves, 6 de diciembre de 2007

¿Como hashear contraseñas en perl?

Casi todas las aplicaciones web que hay en internet requieren registro, este registro consiste normalmente un nombre de usuario y una contraseña.

Para que la aplicación web nos pueda identificar la próxima vez que introduzcamos el usuario y contraseña es necesario que almacene estos datos de alguna forma (normalmente una base de datos).

El problema de este enfoque es que si se descubre una vulnerabilidad en la aplicación web que permita listar campos de la base de datos (por ejemplo, inyección SQL) el atacante podrá leer todos los nombres de usuario y contraseñas del sitio web.

Para solucionarlo en parte, una medida común es no guardar las contraseñas como tales en la base de datos, sino un dato derivado de la contraseña, por ejemplo, se puede pasar la contraseña a una función hash y guardar el resultado obtenido.

Para el proceso de autentificación, ahora no habrá que comparar la entrada del usuario con el valor que hay en la base de datos, sino el hash de la entrada del usuario con el valor de la base de datos, si estos resultados coinciden, la autentificación será correcta.

Eligiento como función hash MD5 y como lenguaje perl, el proceso para crear el hash de una cadena es muy sencillo.

#!/usr/bin/perl

use Digest::MD5 qw(md5 md5_hex md5_base64);

$hash1=md5("pass");
$hash2=md5_hex("pass");
$hash3=md5_base64("pass");

print $hash1 . "\n";
print $hash2 . "\n";
print $hash3 . "\n";

Como se puede ver, he usado tres formas distintas para la misma función hash, la primera (md5) da el resultado en binario, la segunda (md5_hex) en hexadecimal y la tercera (md5_base64) en base 64. Se puede elegir cualquiera de ellas.

martes, 11 de septiembre de 2007

Introducción a las herramientas de depuración de linux

En todos los sistemas operativos que merezcan ese nombre hay una serie de utilidades para depurar programas. Para comentar las de linux voy a basarme en el siguiente mini-programa.

#include <stdio.h>

int main(){
char cadena[1024];
printf("Introduce el pass: ");
scanf("%s", cadena);

if(!strcmp(cadena, "esteeselpass")) printf("Correcto\n");
else printf("Incorrecto\n");
}

Si compilamos ese fichero con gcc, obtendremos un ejecutable, yo le he llamado "prueba".

La primera utilidad es objdump, con ella se puede desensamblar ejecutables, bueno, eso y algunas cosas más.

objdump -d prueba > prueba.asm

Ahora en prueba.asm tenemos el fichero con el código desensamblado.

Intentemos averiguar el password del programa anterior, para ello hay que saber algo de ensamblador. Sabemos que en algún momento hay un salto condicional (je, jne, jz, jnz...) que es el que nos lleva a la situación de error, buscando estos saltos podemos ir rápido sobre el código y averiguar la zona en la que se produce la comprobación.

8048472:    e8 d9 fe ff ff           call   8048350 
8048477: 8d 85 f0 fb ff ff lea 0xfffffbf0(%ebp),%eax
804847d: 89 85 e0 fb ff ff mov %eax,0xfffffbe0(%ebp)
8048483: c7 85 dc fb ff ff e3 movl $0x80485e3,0xfffffbdc(%ebp)
804848a: 85 04 08
804848d: c7 85 d8 fb ff ff 0d movl $0xd,0xfffffbd8(%ebp)
8048494: 00 00 00
8048497: fc cld
8048498: 8b b5 e0 fb ff ff mov 0xfffffbe0(%ebp),%esi
804849e: 8b bd dc fb ff ff mov 0xfffffbdc(%ebp),%edi
80484a4: 8b 8d d8 fb ff ff mov 0xfffffbd8(%ebp),%ecx
80484aa: f3 a6 repz cmpsb %es:(%edi),%ds:(%esi)
80484ac: 0f 97 c2 seta %dl
80484af: 0f 92 c0 setb %al
80484b2: 89 d1 mov %edx,%ecx
80484b4: 28 c1 sub %al,%cl
80484b6: 89 c8 mov %ecx,%eax
80484b8: 0f be c0 movsbl %al,%eax
80484bb: 85 c0 test %eax,%eax
80484bd: 75 0e jne 80484cd
80484bf: c7 04 24 f0 85 04 08 movl $0x80485f0,(%esp)
80484c6: e8 b5 fe ff ff call 8048380
80484cb: eb 0c jmp 80484d9
80484cd: c7 04 24 f9 85 04 08 movl $0x80485f9,(%esp)
80484d4: e8 a7 fe ff ff call 8048380

En este código vemos que se hace un scanf, unas operaciones intermedias, luego hay un jne que nos lleva a un puts o a otro (salidas por pantalla diferentes según una condición).

Ahora que ya sabemos por que zona movernos, podemos usar gdb.

gdb es un debugger gnu para linux, ejecutamos:

gdb prueba

En el listado de arriba desensamblado se puede ver que la instrucción que hace la comparación de las cadenas introducida y correcta es la siguiente:

80484aa:    f3 a6                    repz cmpsb %es:(%edi),%ds:(%esi)

asi que dentro de gdb, ejecutamos:

break *0x80484aa

Con lo que la ejecución se parará justo en esa instrucción, ejecutamos:

run

info registers

Obtenemos el valor de edi y esi, en mi caso 0x80485e3 y 0xbf86a3d8, inspeccionamos lo que hay en esas direcciones de memoria:

x/s 0x80485e3
x/s 0xbf86a3d8

Nos aparecen el pass que hemos introducido, y el ¡correcto!

Hay otra forma de conseguir que el programa nos de "su aprobación":

80484bb:    85 c0                    test   %eax,%eax
80484bd: 75 0e jne 80484cd

Vamos a la instrucción justo anterior a la del salto, el test (0x80484bb) ponemos un breakpoint ahí, si ejecutamos:

info registers

Vemos que eax vale 1, asi que la condición nos llevará al error, pero vamos ha hacer lo siguiente:

set $eax=0

Después pulsamos la 'c' para continuar...y obtenemos el mensaje que queríamos obtener aún habiendo introducido mal la contraseña.