Parchando mod_headers

Posted on 9:07 by Xianur0

Bueno ahora viene la forma de parchar el mod_headers (apache2)...

Primero que nada se requiere el mod_headers.c (viene en cualquier paquete de codigo fuente del apache), luego viene lo siguiente:


static int nocrlf(char *val) {
ap_regex_t *regex;
ap_regcomp(&regex, "\n",AP_REG_EXTENDED);
if(ap_regexec(&regex, val, 0, NULL, 0) != 0) {
return 1;
}
return 0;
}




esa funcion retorna 1 en caso de que no tenga crlf lo que le demos como parametro, de lo contrario 0... esto es mediante expresiones regulares (nadamas buscamos un \n y es todo xD...).

la podemos colocar en cualquier lado (no importa mucho donde declaramos esta funcion), en mi caso lo puse en la linea 510...

lo siguiente es hacer que no setie las cabeceras cuando tienen crlf...

busquemos:

switch (hdr->action) {



y justamente antes ponemos:

if(nocrlf(process_tags(hdr, r)) == 1)



esto es, si hay crlf en el header no se entra al switch, de modo que no se setea la cabecera...

listo, ya tenemos el mod_headers parchado, ahora nos toca instalarlo:



root@Zer0-Null:/usr/local/apache2/bin# ./apxs -cia /home/xianur0/httpd-2.3.5-alpha/modules/metadata/mod_headers.c



bueno eso fue en mi caso, nadamas hay que posicionarnos en la ruta donde este instalado nuestro apache, y buscar el apxs (tiene que estar instalado, de otro modo tendriamos que recompilar el apache :S...) y darle la ruta del mod_headers.c

y ahora ya, tenemos parchado mod_headers y nuestro apache :)...

Apache mod_headers Mass Defacement

Posted on 15:46 by Xianur0

Autor: Xianur0 (Oscar García López)
CCAT Research Labs
Versiones afectadas: de momento se ha probado y todas las apache2 son afectadas, probablemente tambien la 1.3 pero no se ha realizado la prueba.
Parche: de momento ninguno, pero luego programamos uno :)...

Bueno este bug/detalle viene siendo algo muy simple, pero tiene bastante utilidad, es local, se requiere permisos para crear un .htaccess, y lo siguiente va de la siguiente forma:

Apache habia restringido las cabeceras que se pueden rescribir, por ejemplo Content-Length quedo bloqueada para basicamente todas las funciones, de modo que no se puede falsificar facilmente un content-length, pero pasa lo siguiente, mod_headers no filtra correctamente los CRLF, y apache no detecta que cabeceras se crean mediante el CRLF/LF, entonces tenemos lo siguiente:

Header set Last-Modified "Xianur0 Was Here\nContent-Length: 25"
Header set xianur0 "Xianur0 Was Here\nContent-Length: 25\n\n<h1>Xianur0 Was Here</h1>"


este .htaccess lo que haria seria rescribir la cabecera Last-Modified (esta cabecera es de las primeras en crearse), de modo que nuestra cabecera quedara antes que el content-length real, ahora hay diferencia entre el manejo de cabeceras que tienen los navegadores, por ejemplo google chrome, lee solo la primera cabecera y las siguientes repetidas son ignoradas, por el contrario firefox hace basicamente lo mismo que apache, va leyendo las cabeceras repetidas y remplazando el valor anterior por el de la cabecera mas reciente, de modo que nuestro .htaccess ya contempla esos detalles, primero edita Last-Modified (para que quede antes que el content-length real), y luego crea una cabecera "xianur0", con valor "Xianur0 Was Here", y en cada una pone un salto de linea ("\n"), y seguido de eso crea las cabeceras Content-Length que sustituiran a la real, luego en la ultima cabecera que se escribe, se insertan otros dos saltos de linea, y tenemos que lo siguiente queda en la seccion de html, los navegadores comunes, leen unicamente la cantidad de caracteres especificados en el content-length, de modo que todo lo siguiente despues de eso 25 que se especificaron, es ignorado.

y listo, tenemos un deface automatico de todas las paginas, nada se editar, solo se crea el .htaccess, pero a la vista de cualquier navegador la web estaria completamente defaceada :)...

HTTP/1.1 200 OK
Date: Wed, 05 May 2010 22:36:17 GMT
Server: Apache/2.3.5 (Unix)
Last-Modified: Xianur0 Was Here
Content-Length: 25
ETag: "1a4558-2d-432a5e4a73a80"
Accept-Ranges: bytes
Content-Length: 45
xianur0: Xianur0 Was Here
Content-Length: 25

<h1>Xianur0 Was Here</h1>
Content-Type: text/html

<html><body><h1>It works!</h1></body></html>



En resumen, apache bloquea la rescritura del Content-Length y otras cabeceras, pero no se requiere rescribirlas, unicamente crear otras en diferentes lugares y el funcionamiento interno de los navegadores y la inestabilidad del protocolo HTTP completan el proceso :)...


Bytez...

[Perl] Google Books Downloader

Posted on 15:42 by Xianur0

En pocas palabras, lo que hace es descargar dentro de la carpeta tmp (que tiene que estar creada en el mismo directorio que el perl), todas las paginas del libro especificado, las descarga una por una como imagen, no he tenido tiempo de buscar otra manera, pero creo que de momento es util para lo que esta planeado (bajar los libros para poder leerlos offline)...

esta diseñado para books.google.es, pero basta con cambiar el .es por .com (o lo que sea xD) y funcionara igual ;)...


xianur0@Zer0-Null:~$ perl gobookdownloader.pl 0EzERMZHkTIC 0 240 200.219.244.122:80
[-] Consulta inicial realizada, tenemos la cookie: PREF=ID=c882825959dda2ec:TM=1272916829:LM=1272916829:S=jA_XjmG4h8KbYi8K
http://books.google.es/books?id=0EzERMZHkTIC&pg=PA1&img=1&zoom=3&hl=es&sig=ACfU3U2Xm9aZPXoDIMgy91oaU-I0t892Dg
Descargada pagina: 0
http://books.google.es/books?id=0EzERMZHkTIC&pg=PA1&img=1&zoom=3&hl=es&sig=ACfU3U2Xm9aZPXoDIMgy91oaU-I0t892Dg
Descargada pagina: 1
http://books.google.es/books?id=0EzERMZHkTIC&pg=PA1&img=1&zoom=3&hl=es&sig=ACfU3U2Xm9aZPXoDIMgy91oaU-I0t892Dg
Descargada pagina: 2
http://books.google.es/books?id=0EzERMZHkTIC&pg=PA5&img=1&zoom=3&hl=es&sig=ACfU3U1cFZ1iIemGZygZ9-QCXiQSQoJLHg
Descargada pagina: 3
http://books.google.es/books?id=0EzERMZHkTIC&pg=PA6&img=1&zoom=3&hl=es&sig=ACfU3U0BFY-HtIbIjoEIdsvgcnKPhpeX8g
Descargada pagina: 4
http://books.google.es/books?id=0EzERMZHkTIC&pg=PA6&img=1&zoom=3&hl=es&sig=ACfU3U0BFY-HtIbIjoEIdsvgcnKPhpeX8g
Descargada pagina: 5
http://books.google.es/books?id=0EzERMZHkTIC&pg=PA6&img=1&zoom=3&hl=es&sig=ACfU3U0BFY-HtIbIjoEIdsvgcnKPhpeX8g
Descargada pagina: 6
http://books.google.es/books?id=0EzERMZHkTIC&pg=PA11&img=1&zoom=3&hl=es&sig=ACfU3U3G4_FjT1tZ4UR2Fl4Dh20ETPf8vw
Descargada pagina: 7
http://books.google.es/books?id=0EzERMZHkTIC&pg=PA12&img=1&zoom=3&hl=es&sig=ACfU3U1q4ErPv7WAB9OP3AYpAyAOvz-Q1A
Descargada pagina: 8
http://books.google.es/books?id=0EzERMZHkTIC&pg=PA13&img=1&zoom=3&hl=es&sig=ACfU3U2BQMNwDuVjuZkiUv_zZXXd1AAHmw
[...]


en la siguiente version programo que pase las imagenes a un PDF (para poder leer mas comodamente los libros).

Ahora sin mas el codigo:


#!/usr/bin/perl
use LWP::UserAgent;
# Google Books Downloader by Xianur0
# uxmal666@gmail.com
# nota: este codigo solo fue diseñado con la utilidad de poder leer los libros de forma offline
# el autor no se hace responsable del uso que se le de.
$ua = LWP::UserAgent->new;
$id = $ARGV[0];
$inicio = $ARGV[1];
$final = $ARGV[2];
$proxy = $ARGV[3];
die("Google Books Downloader by Xianur0\nUso: perl gobookdownloader.pl [id_libro] [pag. inicial] [pag. final] [Proxy (opcional)]") if($final eq "");
$cookie = "";
$contador = 0;

sub descargar {
$aurl = $_[0];
$id = $_[1];
$cookie = $_[2];
$proxya = $_[3];
$extencion = ".jpg";
($contenido,$cookie, $tipo) = consultar($aurl,$cookie,"http://books.google.es/books?id=".$id."&printsec=frontcover&source=gbs_slider_thumb",$proxya);
if($contenido ne "") {
if($tipo eq "image/jpeg") {
$extencion = ".jpg";
}
if($tipo eq "image/png") {
$extencion = ".png";
}
else {
$extencion = ".jpg";
}
open(ARCHIVO,">tmp/".$id."-".$contador.$extencion);
binmode ARCHIVO;
print ARCHIVO $contenido;
close(ARCHIVO);
print $aurl."\n";
print "Descargada pagina: ".$contador."\n";
$contador++;
}
}

sub consultar {
$url = $_[0];
$cookie = $_[1];
$urlini = $_[2];
$proxy = $_[3];
my $contettype = "";
$ua->agent("Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.1.9) Gecko/20100401 Ubuntu/9.10 (karmic) Firefox/3.5.9");
$ua->proxy(['http'] => 'http://'.$proxy) if($proxy ne "");
$req = HTTP::Request->new(GET => $url);
$req->header('Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8');
$req->header('Accept-Language' => 'es-es,es;q=0.8,en-us;q=0.5,en;q=0.3');
$req->header('Accept-Charset' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7');
$req->header('Cache-Control' => 'max-age=0');
$req->header('Cookie' => $cookie);
$req->header('Referer' => $urlini) if($urlini ne "");
$res = $ua->request($req);
if ($res->is_success) {
$contenido = $res->content;
$respuesta = $res->as_string;
if($respuesta =~ /Set-Cookie: (.*?);/) {
$cookie = $1;
}
if($respuesta =~ /Content-Type: (.*?)\r?\n/) {
$contettype = $1;
}
} else {
if($res->status_line =~ /(500 Can't connect to|503 Service Unavailable)/) {
die("[x] IP Baneada (o proxy ".$proxy." invalido), usar otro proxy...\n");
}
return ("",$cookie,"text/html");
}
return ($contenido,$cookie,$contettype);
}
print "\t\t\t\tGoogle Books Downloader by Xianur0\n";
$urlbase = "http://books.google.es/books?id=".$id."&printsec=frontcover&source=gbs_slider_thumb";
($contenido,$cookie,$tipo) = consultar($urlbase,$cookie,"",$proxy);
print "[-] Consulta inicial realizada, tenemos la cookie: ".$cookie."\n";
for($i = $inicio;$i<=$final;$i++) {
$estaurl = '
http://books.google.es/books?id='.$id.'&lpg=PP1&pg=PA'.$i.'&jscmd=click3';
($contenido,$cookie,$tipo) = consultar($estaurl,$cookie,$urlbase,$proxy);
($iurl) = ($contenido =~ /^{"page":\[{"pid":".*?","src":"(.*?)"/);
$iurl =~ s/\\u0026/&/g;
if($iurl ne "") {
descargar($iurl,$id);
} else { $final++; }
}
print "Descargado exitosamente! :)\n";

Bue me decidi por escribir un ligero curso sobre programacion de mods de apache, y bueno este es el primer capitulo xD.

Notas previas:

1ro: Se requiere un minimo de conocimientos de programacion C/C++.
2do: Se requiere tener apache instalado mod_so (no voy a explicar como hacerlo xD) y apxs.

Antes que nada que vendria siendo un mod? (vaya si comenzaste a leer el texto y no sabes ni de que se trata esto es para ti xD)

Un mod (llamemoslo asi), es una extencion para apache, imaginemos que apache es un framework donde corremos nuestras aplicaciones, las aplicaciones vendrian siendo los mods, es decir una aplicacion que utiliza las respectivas APIs de apache, controla cualquier funcion realizada por el servidor, y basicamente cualquier otra cosa dentro del servidor apache (obviamente esto no se reduce a solo actuar sobre apache, pero digamos que desde apache se ejecutara todo)

Dynamic Shared  Object
El servidor HTTP Apache es un programa modular en el que el administrador puede elegir qué funcionalidades se incluyen mediante la selección de un conjunto de módulos. En primer lugar, los módulos pueden compilarse de manera estática en el binario httpd. De forma alternativa, los módulos también pueden compilarse como Objetos Dinamicos Compartidos (DSOs) que existen de forma independiente del archivo binario httpd. Los módulos que se deseen usar como objetos dinámicos compartidos pueden compilarse al mismo tiempo que el servidor, o pueden compilarse en otro momento y ser añadidos después usando la Herramienta de Extensión de Apache (apxs).

(Citado de la web oficial de apache xD)

Ahora sin mas, vamos a comenzar....



#include <http_protocol.h>
#include <http_config.h>
#include <http_core.h>

static int helloworld_handler(request_rec* r)
{
if (!r->handler || strcmp(r->handler, "helloworld"))
return DECLINED;

if (r->method_number != M_GET)
return HTTP_METHOD_NOT_ALLOWED;

ap_set_content_type(r, "text/html");
ap_rputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n", r);
ap_rputs("<html><head><title>Hi!</title></head>", r);
ap_rputs("<body><h1>Tu IP: </h1>", r);
ap_rputs(r->connection->remote_ip,r);
ap_rputs("<h1>URI: </h1>",r);
ap_rputs(r->uri,r);
ap_rputs("<h1>Request: </h1>",r);
ap_rputs(r->the_request,r);
int *contentlength = apr_pstrdup(r->pool, apr_table_get(r->headers_in, "Content-Length"));
if(contentlength) {
ap_rputs("<h1>Content-Length: </h1>",r);
ap_rputs(contentlength,r);
}
ap_rputs("</h1></body></html>",r);
return OK;
}

static void register_hooks(apr_pool_t* pool)
{
ap_hook_handler(helloworld_handler, NULL, NULL, APR_HOOK_MIDDLE);
}

module AP_MODULE_DECLARE_DATA helloworld_module = {
STANDARD20_MODULE_STUFF,
NULL,
NULL,
NULL,
NULL,
NULL,
register_hooks
};


Vamos por partes...


#include <http_protocol.h>
#include <http_config.h>
#include <http_core.h>


Incluimos las librerias basicas a usar...

static int helloworld_handler(request_rec* r)
{
[...]

Aqui se define como tal las acciones a realizar, para comenzar se toma un parametro (r), el cual
podriamos resumir como el objeto que usaremos para enviar y tomar los datos del envio
(y algunos de la respuesta, pero no viene al caso en este capitulo).

if (!r->handler || strcmp(r->handler, "helloworld"))
return DECLINED;


decimos que si no esta definido el handler "helloworld" en esta ejecucion, salgamos,
es decir si quitamos estas lineas el resto se ejecutaria en todos los directorios (al hacer consulta),
de modo que no se cargarian las webs en nuestro servidor, de modo que decimos que solo continue cuando este
definido el handler "helloworld", dicho handler lo podemos definir con un .htaccess:


SetHandler helloworld


Ese seria el ejemplo. Donde pongamos ese .htaccess se ejecutara nuestro mod.

Seguimos...

if (r->method_number != M_GET)
return HTTP_METHOD_NOT_ALLOWED;

Esto seria opcional, unicamente checa que el metodo sea GET, de no ser GET tirara un 405.

ap_set_content_type(r, "text/html");

Seteamos el content-type de la respuesta a "text/html"


ap_rputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n", r);
ap_rputs("<html><head><title>Hi!</title></head>", r);
ap_rputs("<body><h1>Tu IP: </h1>", r);
ap_rputs(r->connection->remote_ip,r);

Enviamos al navegador (r apuntando) el html inicial y su IP, esto mediante r->connection->remote_ip
Es decir:
de r llamemos al metodo connection del cual pidamos remote_ip el cual nos retornara la ip del cliente.

ap_rputs("<h1>URI: </h1>",r);
ap_rputs(r->uri,r);


Aqui se imprime nuevamente un html y luego se imprime el "URI" que en dado caso vendria siendo el directorio
consultado que en mi caso seria: "/helloworld/" (ahi defini el handler).

Como tal es vulnerable a XSS:

GET http://localhost/helloworld/<script>alert('xss')</script> HTTP/1.1
Host: localhost

El resultado sera que nos lanze un bonito alert...

Pero no se preocupen que apache ya lo tiene resuelto, para ello usar ap_escape_html

Esto es:

ap_escape_html(r->pool,r->uri)

Resumiendo parchado quedaria:

ap_rputs("<h1>URI: </h1>",r);
ap_rputs(ap_escape_html(r->pool,r->uri),r);

Seguimos...

ap_rputs("<h1>Request: </h1>",r);
ap_rputs(r->the_request,r);

Lo que hace como es obvio imprime el request enviado, es decir la primera linea de la consulta HTTP:

GET /helloworld/%3Cscript%3Ealert(%27xss%27)%3C/script%3E HTTP/1.1


Seria un ejemplo de lo que imprimiria, a simple vista pareseria que no hay XSS, pero...

GET http://localhost/helloworld/?asas=<> HTTP/1.1
Host: localhost

HTTP/1.1 200 OK
Date: Wed, 14 Apr 2010 22:49:22 GMT
Server: Apache/2.3.5 (Unix)
Content-Length: 231
Content-Type: text/html;charset=ascii


<title>Hi!</title>
<h1<Tu IP: </h1>127.0.0.1
<h1>URI: </h1>/helloworld/
<h1>Request: </h1>GET http://localhost/helloworld/?asas=<> HTTP/1.1

Todo depende de la consulta que se se llama...

Lo mismo...

ap_rputs(ap_escape_html(r->pool,r->the_request),r);


y nuevamente solucionado...

Lo siguiente en la lista:

int *contentlength = apr_pstrdup(r->pool, apr_table_get(r->headers_in, "Content-Length"));
if(contentlength) {
ap_rputs("<h1>Content-Length: </h1>",r);
ap_rputs(contentlength,r);
}

Primero que nada se intenta tomar el valor de la cabecera Content-Length, luego si lo pudo tomar lo imprime. Hablando un poco mas tecnicamente, apache utilizar tables, que vendrian siendo como hashtables en otros lenguajes de programacion, o como una matriz con indice literal. Entonces utilizamos la funcion apr_table_get() para obtener el valor que nos interesa (en este caso el valor de Content-Length), si les interesa mas info al respecto de las hashes:

Introduction to the Apache table API

Muchos me diran ahi hay otro XSS!, pero no como tal, es decir:

Apache automaticamente valida el content-length, es decir si no es numerico, entero y mayor de 0, retorna un 413 equest Entity Too Large.

Aparte de que solo estamos permitiendo GET, asi que amenos que sea una aplicacion muy mal diseñada y que trabaje con html, no deberia haber tanto problema...

Claro que si no se sienten comodos, pueden filtrarlo de la misma forma que se hizo arriba xD...

ap_rputs("</h1></body></html>",r);
return OK;
}


Se imprime el final del html y retornamos OK (ejecucion correcta).

Hasta aqui vamos programado lo que va a hacer, pero como inicializarlo?, Eso hace el resto de codigo:

static void register_hooks(apr_pool_t* pool)
{
ap_hook_handler(helloworld_handler, NULL, NULL, APR_HOOK_MIDDLE);
}

module AP_MODULE_DECLARE_DATA helloworld_module = {
STANDARD20_MODULE_STUFF,
NULL,
NULL,
NULL,
NULL,
NULL,
register_hooks
};

Ahora nos queda instalar nuestro primer "helloworld" en apache:

Paso 1:
root@Zer0-Null:/usr/local/apache2/bin# ./apxs -cia /home/xianur0/Escritorio/mod_test.c
Paso 2:
root@Zer0-Null:
/usr/local/apache2/bin# ./httpd -k restart

Si no hay problema en ninguno de los dos pasos, tendremos instalado nuestro modulo,
y si tambien ya hemos puesto el htaccess, nuestro primer modulo debe de estar funcionando :)

Bytez Xianur0