Fscan 1.0: Programando con la API de HTTP de FSCAN
Para los que lo estabais esperando, aquí está la versión compilada para win32 de Fscan 1.0 (FHScan), orientado a automatizar las tareas de revisión de routers y otros dispositivos HTTP.
FHscan Core api es una librería de HTTP/1.1 que fue desarrollada a raíz del proyecto «Fast HTTP Vulnerability Scanner«, hasta llegar a convertirse en el núcleo del mismo. Esta librería debía cumplir una serie de requisitos, velocidad, sencillez y flexibilidad, y por supuesto, dado que su objetivo principal era ser utilizada para ataques de fuerza bruta, soporte de varios mecanismos de autenticación (basic, digest y NTLM) así como soporte de compresión gzip/deflate, callbacks y SSL. El resultado es prometedor y dado que es portable y que me gustaría que la gente pudiese colaborar en su desarrollo, voy a dejar el rollo de exploits por una vez y os voy a contar algún ejemplo de como realizar aplicaciones mas o menos sencillas usando esta API.
Lo único que debéis incluir en vuestra aplicación es el fichero «HTTP.h» y una vez hecho esto, inicializar el motor de HTTP con InitHTTPApi(). Esta función se encarga de manter en memoria varias tablas que gestionan las conexiones activas, aunque eso es totalmente transparente para nosotros.
Antes de establecer una conexión es necesario generar un pseudoHandle al sistema remoto. Esto se consigue con la llamada InitHTTPConnectionHandle() cuyos parámetros son el host remoto, el puerto, y si la conexión usa o no SSL.
HTTPHANDLE HTTPHandle=InitHTTPConnectionHandle("blog.48bits.com",80,0);
Una vez generado el Handle, podemos empezar a generar peticiones. Todas estas peticiones se almacenan en una estructura PREQUEST que comentaremos más adelante. Véase un ejemplo de como realizar una peticion a la web de 48bits.
void main(int argc, char *argv[]) {
InitHTTPApi(); //Inicialización del motor HTTP
HTTPHANDLE HTTPHandle = InitHTTPConnectionHandle("blog.48bits.com",80,0);
PREQUEST DATA=SendHttpRequest(HTTPHandle,NULL,"GET","/",NULL,NULL,NULL,NO_AUTH);
//do stuff with the data….
if (DATA) FreeRequest(DATA); //liberamos la memoria de la petición
CloseHTTPConnectionHandle(HTTPHandle); //Liberamos el Handle
CloseHTTPApi(); //Paramos el motor HTTP
}
La función SendHttpRequest() tiene 8 parámetros de los cuales 5 de ellos son opcionales.
– El primer parámetro es HANDLE al servidor HTTP remoto.
– El segundo parámetro es un vhost opcional que se enviará en la cabecera «Host: vhost». Si no se especifica, se utilizará el valor de la llamada InitHTTPConnectionHandle()
– El tercer parámetro es el método HTTP utilizado. Este puede ser «GET»,»POST»,»PUT»,»WHATEVER»,…
– El cuarto parámetro son los datos enviados al servidor. en una petición GET, para acceder a «http://blog.48bits.com/?p=287» deberíamos incluir «p=287» en ese parámetro
– El quinto y sexto parámetro son también opcionales y especifican el usuario y la contraseña.
– El séptimo y último parámetro, es el tipo de autenticación utilizado. Si dejamos el valor por defecto ( 0 o NO_AUTH) el sistema lo negociará automáticamente.
Dado que ya está más o menos claro como enviar una petición, vamos a ver como se estructura la información devuelta, es decir, la estructura PREQUEST.
int ip; //<- dirección ip de un sockaddr_in
int port; //<- puerto al que se establece la conexión
int NeedSSL; //<- Indica si la petición ha utilizado SSL (1) o no ( 0)
char url [512]; //<- dirección URL contra la que se ha realizado la peticion HTTP
PHTTP_DATA request; //<- DATOS ENVIADOS
PHTTP_DATA response; //<- DATOS RECIBIDOS
char * server; //<- banner del servidor Web
unsigned int status //<- código HTTP de la respuesta (200 si la pagina existe, 401 para acceso denegado,..)
unsigned int challenge //<- tipo de autenticacion requerida por el servidor web (en base a la cabecera www-authenticate)
un sencillo ejemplo:
devolvería:
Host: blog.48bits.com port: 80 URL: /index.html – status: 200
Por último queda comentar los datos almacenados dentro de la estructura PHTTP_DATA (campos request y response). Esta es también una estructura sencilla que contiene los siguientes campos
unsigned int HeaderSize; //Tamaño de las cabeceras HTTP
char *Data; //Datos enviados (por ejemplo en una peticion POST) o recibidos (por ejemplo el codigo html)
unsigned int DataSize; //tamaño del buffer
para ilustrar con mas detalle esto, aqui viene el ejemplo final 🙂
void main(int argc, char *argv)
{
InitHTTPApi();
HTTPHANDLE HTTPHandle = InitHTTPConnectionHandle("blog.48bits.com",80,0);
if (HTTPHandle) {
PREQUEST DATA= SendHttpRequest(HTTPHandle,NULL,"GET","/","p=290",NULL,NULL,NO_AUTH);
if (DATA) {
printf("Host: %s port: %i URL: %s – status: %i\n",DATA->hostname, DATA->port, DATA->url, DATA->status);
printf("Peticion %i bytes:\n%s\n",DATA->request->HeaderSize,DATA->request->Header);
printf("Respuesta %i bytes\n%s\n",DATA->response->HeaderSize,DATA->response->Header);
printf("Datos %i bytes\n%s\n",DATA->response->DataSize,DATA->response->Data);
FreeRequest(DATA);
}
CloseHTTPConnectionHandle(HTTPHandle);
}
}
y la salida devuelta por la aplicación
Host: blog.48bits.com port: 80 URL: / – status: 200
Peticion 136 bytes:
GET /?p=290 HTTP/1.1
Host: blog.48bits.com
User-Agent: Mozilla/5.0 (FSCAN)
Accept-Encoding: gzip, deflate
Connection: keep-alive
Respuesta 433 bytes
HTTP/1.1 200 OK
Date: Thu, 13 Nov 2008 13:12:15 GMT
Server: Apache/2.2.3 (Debian) DAV/2 SVN/1.4.2 mod_python/3.2.10 Python/2.4.4 PHP/5.2.0-8+etch13 mod_ssl/2.2.3
OpenSSL/0.9.8c mod_perl/2.0.2 Perl/v5.8.8
X-Powered-By: PHP/5.2.0-8+etch13
X-Pingback: http://blog.48bits.com/xmlrpc.php
Vary: Accept-Encoding
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8
Content-Length: 19038
Datos 19038 bytes
//aqui va todo el código html devuelto por la página web..
Obviamente este es un ejemplo sencillo, pero es mucho más potente. Como primicia, si queréis mas información, podéis descargar la librería HTTP de Fscan en http://www.tarasco.org/security/fscan-core/ y consultar la documentación HTML que hay generada.