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

0 comentarios: