# FHTTP Kit by Xianur0
# Copyright (C) 2011 Oscar García López (http://hackingtelevision.blogspot.com)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
# xianur0.null@gmail.com
# http://hackingtelevision.blogspot.com/
package fingerprint;
use Switch;
use lib("tools");
use tools;
$mostrartotal = "";
$rotativos = "";
$soportetracea = "";
$proxysing = "";
$http10resa = "";
$http09resa = "";
$idioma = &main::mods("--lang");
# Fingerprint
sub grafico {
my $ventana = Gtk2::Window->new('toplevel');
$ventana->set_title("HTTP Fingerprint");
$ventana->set_default_icon_from_file("icono.jpg");
$ventana->set_border_width(5);
$ventana->set_default_size(20, 20);
$ventana->set_resizable(FALSE);
$hbox = Gtk2::VBox->new(0, 0);
$hbox->set_border_width(5);
$caja = Gtk2::HBox->new(0,0);
$etiqueta = Gtk2::Label->new('URL: ');
$url = Gtk2::Entry->new();
&main::share($url);
$caja->pack_start($etiqueta, FALSE,FALSE,2);
$caja->pack_start($url, FALSE,FALSE,2);
$recur = Gtk2::CheckButton->new_with_label(dic::fingerlabels($idioma,0));
&main::share($recur);
$boton = Gtk2::Button->new(dic::fingerlabels($idioma,1));
$boton->signal_connect('clicked' => sub {$threadproxy = threads->create('iniciarfingerprint'); });
my $vp = Gtk2::Viewport->new (undef,undef);
my $scrolled = Gtk2::ScrolledWindow->new();
$scrolled->add($vp);
$mostrar = Gtk2::Label->new(dic::fingerlabels($idioma,2));
$vp->add($mostrar);
&main::share($mostrar);
$imagen = Gtk2::Image->new_from_file("logo.png");
$hbox->pack_start($imagen, FALSE, FALSE, 2);
$hbox->pack_start($caja, FALSE, FALSE, 2);
$hbox->pack_start($recur,FALSE,FALSE,2);
$hbox->pack_start($boton, FALSE, FALSE, 2);
$hbox->pack_start($scrolled,FALSE,FALSE,2);
$hbox->show;
$ventana->add($hbox);
$ventana->show_all;
$ventana->resize(50, 200);
Gtk2->main;
}
sub new {
if($#ARGV >= 2 && &main::mods("Gtk2") != 1) {
iniciarfingerprint();
exit;
}
elsif(&main::mods("Gtk2") == 1) {grafico();}
else {die(dic::comunes($idioma,0).": fhttp.pl 0 [url] [".dic::fingerlabels($idioma,0)." 1|0]\n");}
}
sub datechecker {
@dates = @_;
my $contador = 0;
my $totalseg = 0;
my $contadord = 0;
my $timeanterior = 0;
my (@dia,@mes,@anio,@hora,@horas,@minutos,@segundos,@segt1,@diferencias);
foreach(@dates) {
($dia[$contador],$mes[$contador],$anio[$contador],$hora[$contador],$horas[$contador],$minutos[$contador],$segundos[$contador],$segt1[$contador]) = tools::dateparser($_);
if($contador > 0) {
my $timediff = ($segt1[$contador]-$timeanterior);
$totalseg += ($timediff > 0) ? $timediff : 0;
$diferencia[$contadord] = $segt1[$contador] - $segt1[$contador-1];
$diferencia[$contadord] =~ s/^-//;
switch(true) {
case {$dia[$contador-1] ne $dia[$contador]} {
rotativodetectado("date-day",$dia[$contador-1],$dia[$contador]);
}
case {$mes[$contador-1] ne $mes[$contador]} {
rotativodetectado("date-month",$mes[$contador-1],$mes[$contador]);
}
case {$anio[$contador-1] ne $anio[$contador]} {
rotativodetectado("date-year",$anio[$contador-1],$anio[$contador-1]);
}
case {$diferencia[$contadord] > 10 || $timediff < 0}{
rotativodetectado("date-seconds",10,$diferencia);
}
}
$contadord++;
}
$timeanterior = $segt1[$contador];
$contador++;
}
agregaramostrar(dic::comunes($idioma,1).": ".(($totalseg > 0) ? ($totalseg/$contador) : 0)." seg\n")
}
sub agregaramostrar {
$text = $_[0];
$mostrartotal .= $text;
print &main::red, $text, &main::reset;
}
sub rotativodetectado {
my ($tipo,$val1,$val2) = @_;
print dic::mensajes($idioma,0)."...\n";
$rotativos .= "[!] ".dic::mensajes($idioma,1).":\n-".dic::mensajes($idioma,2)." : ".$tipo."\n- ".dic::mensajes($idioma,3).": ".$val1."\n- ".dic::mensajes($idioma,4).": ".$val2."\n";
}
sub iniciarfingerprint {
my @encabezadoss = ("User-Agent: Mozilla/5.0 (X11; U; Linux i686; es-ES; rv:1.9.1.8) Gecko/20100214 Ubuntu/9.10 (karmic) Firefox/3.5.8");
$mostrar->set_text(dic::mensajes($idioma,5)."...\n") if(&main::mods("Gtk2"));
my $puerto = 80;
my $path = "/";
my $ssl = 0;
my $host = "";
my $resto = "";
my $scheme = "";
my $ciclos = 1;
my $keepalive;
my $keepatotal;
my $keepsoportados;
my $banner;
my $proxycoincidencias;
my $http09res;
my $http10res;
my $hostenvio = "";
my $puertoenvio = "";
my $urlactual = $ARGV[1] || ((&main::mods("Gtk2") == 1) ? $url->get_text : die("URL Invalida!\n"));
($scheme,$resto) = ($urlactual =~ /^(https?):\/\/(.*)/);
$mostrar->set_text(dic::mensajes($idioma,5).": ".$urlactual) if(&main::mods("Gtk2"));
$ssl = 1 if($scheme eq "https");
if($resto =~ /^(.*?)\/(.*)/) {
$path = "/".$2;
$resto = $1;
}
if($resto =~ /^(.+):([\d]+)$/) {
$host = $1;
$puerto = $2;
print "Host: ".$host."\nPuerto: ".$puerto."\n";
} else {
$host = $resto;
$puerto = "443" if($ssl == 1);
}
if(&main::mods("Cheat---proxy") =~ /^([^:]+):(\d+)$/) {
$hostenvio = $1;
$puertoenvio = $2;
} else {
$hostenvio = $host;
$puertoenvio = $puerto;
}
print dic::mensajes($idioma,6).": ".$hostenvio.": ".$puertoenvio."\n\n";
$mostrar->set_text(join "","SSL: ",$ssl,"\n",dic::comunes($idioma,2),": ",$puerto,"\n",dic::comunes($idioma,3),": ",$host,"\n",dic::comunes($idioma,4),": ",$path,"\n") if(&main::mods("Gtk2"));
if(($puerto != 80 && $ssl == 0) || (($puerto != 443 || $puerto ne "https") && $ssl == 1)) {
$lineaurl = join "",$scheme,"://",$host,":",$puerto,$path;
} else {
$lineaurl = join "",$scheme,"://",$host,$path;
}
$ciclos = 10 if($ARGV[2] == 1 || (&main::mods("Gtk2") && $recur->get_active));
for($ia = 0; $i< $ciclos; $i++) {
my $paquete = http->new("GET",$lineaurl,"1.1");
$paquete->agregarencabezados(0,@encabezadoss);
$paquete->modo(1);
my $tamanocontenido = length(join "","GET ",$lineaurl," HTTP/1.1\r\nHost: ",$host,"\r\nConnection: Keep-Alive\r\nProxy-Connection: Keep-Alive\r\n\r\n");
$paquete->agregarencabezadosfinal(0,("Content-Length: ".$tamanocontenido));
$paquete->siguiente("GET",$lineaurl,"1.1");
$paquete->agregarencabezados(1,@encabezadoss);
$paquete->siguiente("GET","http://localhost/","1.1");
$paquete->print;
%estructura = $paquete->enviar($hostenvio,$puertoenvio,$ssl);
# analizador
if($estructura{total} > 1) {
$persistente = 1;
$mostrar->set_text(dic::mensajes($idioma,7)."\n".dic::mensajes($idioma,8)."...\n") if(&main::mods("Gtk2") );
my $parser = parser->new();
my ($soportados,%estructuratmp) = $parser->soportados($lineaurl,$host,$puerto,$ssl,0,"",$hostenvio,$puertoenvio);
my @dates = ();
if($soportados >= 100) {
&agregaramostrar(join "","[!] ",dic::mensajes($idioma,9),"!\n");
} else {
rotativodetectado("keep-alive-supported",$estructura{total},$soportados)
if($soportados < $estructura{total});
$estructura{encabezados}[$id]{$nombre} = $valor;
&agregaramostrar(join "","[-] ",dic::mensajes($idioma,10)," ".$soportados." ",dic::mensajes($idioma,11),"\n");
}
for($ina = 0; $ina < $soportados;$ina++) {
unshift(@dates,$estructuratmp{encabezados}[$ina]{"Date"});
}
datechecker(@dates);
} else {
$mostrar->set_text(dic::mensajes($idioma,12)."!\n") if(&main::mods("Gtk2"));
}
if($ciclos > 1) {
if($keepalive =~ /^\d+$/ && $persistente != $keepalive) {
rotativodetectado("keep-alive",$keepalive,$persistente);
}
if($keepatotal =~ /^\d+$/ && $estructura{total} != $keepatotal) {
rotativodetectado("keep-alive-total",$keepatotal,$estructura{total});
}
if($keepsoportados =~ /^\d+$/ && $soportados != $keepsoportados) {
rotativodetectado("keep-alive-soportados",$keepsoportados,$soportados);
}
if($banner =~ /^(.+)$/ && $banner ne $estructura{encabezados}[0]{Server}) {
rotativodetectado("server-banner",$banner,$estructura{encabezados}[0]{Server});
}
$keepalive = $persistente;
$keepatotal = $estructura{total};
$keepsoportados = $soportados;
$soportetrace = $soportetracea;
$banner = $estructura{encabezados}[0]{Server};
# termina el if de los ciclos
}
my %signature = (
'Apache/2.x','Connection:\sKeep-Alive',
'Microsoft-IIS/7.x','Connection:\skeep-alive',
'Microsoft-IIS/6.x','^HTTP/1.(1|0)\s(.*?)(\r\n|\n)Content-Length:\s',
'Microsoft-IIS/x.x','Server:\s(.*?)(\r\n|\n)X-Powered-By:\s'
);
my %signature2 = (
'Microsoft-IIS/7.x','Server:\s(.*?)(\r\n|\n)X-AspNet-Version:\s',
'Microsoft-IIS/6.x','Server:\s(.*?)(\r\n|\n)P3P:(\w*?)=(.*?)(\r\n|\n)X-Powered-By:\sASP\.NET',
);
my %signature3 = (
'Microsoft-IIS/7.x','Server:\sMicrosoft-HTTPAPI',
);
my %proxys = (
'Squid/2.x','Via:\s(.*?)\(squid\/2',
'NetCache','Via:\s(.*?)\(NetCache',
'Proxy Generico','Proxy-Connection:\s',
);
my %proxys2 = (
'NetCache','Server:\sNetCache\sappliance',
);
my $apache = 0;
my %servidores = ();
my $total = 0;
my $totaldb = 0;
my $http09 = 0;
# if($persistente == 1) {
&agregaramostrar(join "","[-] ",dic::mensajes($idioma,13),": ",$estructura{encabezados}[0]{Server},"\n");
if($estructura{total} > 2) {
&agregaramostrar("[-] ".dic::comunes($idioma,6).": Cherokee Web Server o Servidor Proxy\n");
} else { $http09 = 1; }
for($in=0;$in<$estructura{total};$in++) {
print &main::red, dic::comunes($idioma,5).": ".dic::comunes($idioma,6)." -> FHTTP\n", &main::reset;
print $estructura{encabezado}[$in]."\n\n";
foreach $key (sort keys %proxys) {
$totaldb++;
$value = $proxys{$key};
if($estructura{encabezado}[$in] =~ m/$value/) {
$total++;
$servidores{$key}++;
}
}
foreach $key (sort keys %signature) {
$totaldb++;
$value = $signature{$key};
if($estructura{encabezado}[$in] =~ m/$value/) {
$total++;
$servidores{$key}++;
}
}
foreach $key (sort keys %signature2) {
$totaldb++;
$value = $signature2{$key};
if($estructura{encabezado}[$in] =~ m/$value/) {
$total++;
$servidores{$key}++;
}
}
foreach $key (sort keys %signature3) {
$totaldb++;
$value = $signature3{$key};
if($estructura{encabezado}[$in] =~ m/$value/) {
$total++;
$servidores{$key}++;
}
}
foreach $key (sort keys %proxys2) {
$totaldb++;
$value = $proxys2{$key};
if($estructura{encabezado}[$in] =~ m/$value/) {
$total++;
$servidores{$key}++;
}
}
&agregaramostrar(join "","[-] ",dic::mensajes($idioma,14),": ",$total,"/",$totaldb,"\n") if($total > 0);
foreach $key (sort keys %servidores) {
$value = $servidores{$key};
$servidores{$key} = "";
if($value ne "") {
$porcentaje = (100/$total)*$value;
$http09 = 1 if($porcentaje == 50);
$sing = join "",$key,": ",$porcentaje,"% (",$value," ",dic::comunes($idioma,7),")\n";
$proxysing .= $sing;
&agregaramostrar($sing);
}
}
$total = 0;
# probamos el trace para ver como pasan los datos :)...
&agregaramostrar("[-] Trace:\n");
my $paquete = http->new("TRACE",$lineaurl,"1.0");
$paquete->agregarencabezados(0,("X: 1"));
$paquete->print;
%estructura = $paquete->enviar($hostenvio,$puertoenvio,$ssl);
if($estructura{encabezado}[0] =~ /(\r\n|\n)Content-Type: message\/http(\r\n|\n)/) {
print &main::red, (dic::comunes($idioma,8).": Servidor -> FHTTP:\n"), &main::reset;
$estructura{contenidos}[0] =~ s/^(\r|\n|\s)//g;
$estructura{contenidos}[0] =~ s/(\r|\n|\s)$//g;
print $estructura{contenidos}[0];
$enviado = $paquete->paquete;
$enviado =~ s/^(\r\n|\n|\s)//g;
$enviado =~ s/(\r\n|\n|\s)$//g;
if($estructura{contenidos}[0] ne $enviado) {
$soportetracea = "\"!=\" (proxy?)";
&agregaramostrar("- \"!=\" (proxy?)\n");
} else {
$soportetracea = "==";
&agregaramostrar("- ==\n");
}
} else {
$soportetracea = dic::mensajes($idioma,15);
&agregaramostrar("- NO TRACE\n");
}
# exit if($http09 == 0);
&agregaramostrar("[-] HTTP/0.9:\n");
my $paquete = http->new("GET",$lineaurl,"0.9");
$paquete->print;
%estructura = $paquete->enviar($hostenvio,$puertoenvio,$ssl);
if($estructura{estados}[0] =~ /^HTTP\/1\.1 505/i) {
print &main::red, (dic::comunes($idioma,9).": ".dic::comunes($idioma,6)." -> FHTTP:\n"), &main::reset;
print $estructura{estados}[0]."\n\n";
$http09resa = "[!-] ",dic::comunes($idioma,6),": No IIS/Apache!\n";
&agregaramostrar($http09resa);
}
elsif($estructura{estados}[0] =~ /^HTTP\/1\.1/) {
print &main::red, (dic::comunes($idioma,9).": ".dic::comunes($idioma,6)." -> FHTTP:\n"), &main::reset;
print $estructura{estados}[0]."\n\n";
$http09resa = "- ".dic::comunes($idioma,6).": IIS\n";
&agregaramostrar($http09resa);
} else {
$http09resa = "- ".dic::comunes($idioma,6).": Apache\n";
&agregaramostrar($http09resa);
}
&agregaramostrar("[-] HTTP/1.0:\n");
my $paquete = http->new("GET",$lineaurl,"1.0");
$paquete->print;
$http10resa = "";
%estructura = $paquete->enviar($hostenvio,$puertoenvio,$ssl);
if($estructura{estados}[0] =~ /^HTTP\/1\.0/i) {
$http10resa = "[!-] No IIS/Apache!\n";
&agregaramostrar($http10resa);
}
else {
$http10resa = "- Normal (HTTP/1.1)\n";
&agregaramostrar($http10resa);
}
if($persistente == 1) {
&agregaramostrar("[-] HTTP/1.0 + Keep-Alive:\n");
my $paquete = http->new("GET",$lineaurl,"1.0");
$paquete->modo(1);
$paquete->siguiente("GET",$lineaurl,"1.0");
$paquete->print;
%estructura = $paquete->enviar($hostenvio,$puertoenvio,$ssl);
if($estructura{total} > 1) {
$http10resa .= "- Keep-Alive + HTTP/1.0 [!]\n";
&agregaramostrar($http10resa);
} else {
$http10resa .= "- NO Keep-Alive + HTTP/1.0\n";
&agregaramostrar($http10resa);
}
}
# comienza el siguiente analisis...
if($ciclos > 1) {
if($soportetrace =~ /^(.+)$/ && $soportetrace ne $soportetracea) {
rotativodetectado("result-trace",$soportetrace,$soportetracea);
}
if($proxysingb =~ /^(.+)$/ && $proxysing != $proxysingb) {
rotativodetectado("firm-proxys",$proxysingb,$proxysing);
}
if($http09res =~ /^(.+)$/ && $http09res != $http09resa) {
rotativodetectado("http-0.9-result",$http09res,$http09resa);
}
if($http10res =~ /^(.+)$/ && $http10res != $http10resa) {
rotativodetectado("http-1.0-result",$http10res,$http10resa);
}
}
$soportetrace = $soportetracea;
$proxysingb = $proxysing;
$http09res = $http09resa;
$http10res = $http10resa;
}
# termina el siguiente analisis.
# /analizador
if($rotativos ne "") {
&agregaramostrar($rotativos);
}
$persistente = "";
$estructura{total} = "";
$soportados = "";
$estructura{encabezados}[0]{Server} = "";
}
# analizamos los separadores permitidos para intentar detectar el tipo de servidor web
&agregaramostrar("[-] ".dic::comunes($idioma,10).": \n");
open REGLAS,"reglas.txt";
%reglas = ();
@estados = ("501","400","502");
my $firma = "";
while($linea = ) {
if($linea =~ /^separador:\s+/) {
($separador,$servidor) = ($linea =~ /^separador:\s+(.+)=>(.+)$/);
$servidor =~ s/