在Unix系统平台上的网络安全工具开发中,目前最为流行的CAPIlibrary有libnet、
libpcap、libnids和libicmp等。它们分别从不同层次和角度提供了不同的功能函数。使
网络开发人员能够忽略网络底层细节的实现,从而专注于程序本身具体功能的设计与开发
。其中,
*libnet提供的接口函数主要实现和封装了数据包的构造和发送过程。
*libpcap提供的接口函数主要实现和封装了与数据包截获有关的过程。
*libnids提供的接口函数主要实现了开发网络入侵监测系统所必须的一些结构框架。
*libicmp等相对较为简单,它封装的是ICMP数据包的主要处理过程(构造、发送、接收等
)。
利用这些C函数库的接口,网络安全工具开发人员可以很方便地编写出具有结构化强、健
壮性好、可移植性高等特点的程序,如scanner、sniffer、firewall、IDS等。
---[]------------------------------------------
libnet库的最新版本为1.0.0,它一共约7600行C源代码,33个源程序文件,12个C头文件
,50余个自定义函数,提供的接口函数包含15种数据包生成器和两种数据包发送器(IP层
和数据链路层)。目前只支持IPv4,不支持IPv6。已经过测试的系统平台包括:
*OpenBSD2.6snap,2.5,2.4,2.3,2.2(i386)
*FreeBSD4.0-STABLE,3.3-STABLE,3.2-RELEASE,3.1-CURRENT,3.0,2.2(i386)
*NetBSD1.3.2(i386)
*BSD/OS3.x(i386)
*BSDi3.0(i386)
*Linux2.2.x,2.0.3x,2.1.124(i386,alpha)(libc:2.4.x,glibc:2.0.x)
*Solaris7(SPARC,gcc2.7.2,2.8.2),2.6(SPARC,gcc2.8.2),
2.5.x(SPARC,gcc2.7.2)
*IRIX6.2
*MacOS5.3rhapsody(powerpc)
libnet提供的接口函数按其作用可分为四类:
*内存管理(分配和释放)函数
*地址解析函数
*数据包构造函数
*数据包发送函数
以下分别列出这些接口函数及其功能(其参数含义简单易懂,不再解释):
★内存管理函数
单数据包内存初始化:
intlibnet_init_packet(u_shortpacket_size,u_char**buf);
单数据包内存释放:
voidlibnet_destroy_packet(u_char**buf);
多数据包内存初始化:
intlibnet_init_packet_arena(structlibnet_arena**arena,
u_shortpacket_num,u_shortpacket_size);
访问多数据包内存中的下一个数据包:
u_char*libnet_next_packet_from_arena(structlibnet_arena**arena,
u_shortpacket_size);
多数据包内存释放:
voidlibnet_destroy_packet_arena(structlibnet_arena**arena);
★地址解析函数
解析主机名:
u_char*libnet_host_lookup(u_longip,u_shortuse_name);
解析主机名(可重入函数):
voidlibnet_host_lookup_r(u_longip,u_shortuse_name,u_char*buf);
域名解析:
u_longlibnet_name_resolve(u_char*ip,u_shortuse_name);
获取接口设备IP地址:
u_longlibnet_get_ipaddr(structlibnet_link_int*l,
constu_char*device,constu_char*ebuf);
获取接口设备硬件地址:
structether_addr*libnet_get_hwaddr(structlibnet_link_int*l,
constu_char*device,
constu_char*ebuf);
★数据包构造函数
ARP协议数据包:
intlibnet_build_arp(u_shorthrdw,u_shortprot,u_shorth_len,
u_shortp_len,u_shortop,u_char*s_ha,
u_char*s_pa,u_char*t_ha,u_char*t_pa,
constu_char*payload,intpayload_len,
u_char*packet_buf);
DNS协议数据包:
intlibnet_build_dns(u_shortid,u_shortflags,u_shortnum_q,
u_shortnum_answ_rr,u_shortnum_auth_rr,
u_shortnum_add_rr,constu_char*payload,
intpayload_len,u_char*packet_buf);
以太网协议数据包:
intlibnet_build_ethernet(u_char*daddr,u_char*saddr,u_shortid,
constu_char*payload,intpayload_len,
u_char*packet_buf);
ICMP协议数据包(ICMP_ECHO/ICMP_ECHOREPLY):
intlibnet_build_icmp_echo(u_chartype,u_charcode,u_shortid,
u_shortseq,constu_char*payload,
intpayload_len,u_char*packet_buf);
ICMP协议数据包(ICMP_MASKREQ/ICMP_MASKREPLY):
intlibnet_build_icmp_mask(u_chartype,u_charcode,u_shortid,
u_shortseq,u_longmask,
constu_char*payload,intpayload_len,
u_char*packet_buf);
ICMP协议数据包(ICMP_UNREACH):
intlibnet_build_icmp_unreach(u_chartype,u_charcode,
u_shortorig_len,u_charorig_tos,
u_shortorig_id,u_shortorig_frag,
u_charorig_ttl,u_charorig_prot,
u_longorig_saddr,u_longorig_daddr,
constu_char*payload,intpayload_len,
u_char*packet_buf);
ICMP协议数据包(ICMP_TIMEXCEED):
intlibnet_build_icmp_timeexceed(u_chartype,u_charcode,
u_shortorig_len,u_charorig_tos,
u_shortorig_id,u_shortorig_frag,
u_charorig_ttl,u_charorig_prot,
u_longorig_saddr,u_longorig_daddr,
constu_char*payload,intpayload_len,
u_char*packet_buf);
ICMP协议数据包(ICMP_REDIRECT):
intlibnet_build_icmp_redirect(u_chartype,u_charcode,u_longgateway,
u_shortorig_len,u_charorig_tos,
u_shortorig_id,u_shortorig_frag,
u_charorig_ttl,u_charorig_prot,
u_longorig_saddr,u_longorig_daddr,
constu_char*payload,intpayload_len,
u_char*packet_buf);
ICMP协议数据包(ICMP_TSTAMP/ICMP_TSTAMPREPLY):
intlibnet_build_icmp_timestamp(u_chartype,u_charcode,u_shortid,
u_shortseq,n_timeotime,n_timertime,
n_timettime,constu_char*payload,
intpayload_len,u_char*packet_buf);
IGMP协议数据包:
intlibnet_build_igmp(u_chartype,u_charcode,u_longip,
constu_char*payload,intpayload_len,
u_char*packet_buf);
IP协议数据包:
intlibnet_build_ip(u_shortlen,u_chartos,u_shortip_id,u_shortfrag,
u_charttl,u_charprotocol,u_longsaddr,
u_longdaddr,constu_char*payload,intpayload_len,
u_char*packet_buf);
OSPF路由协议数据包:
intlibnet_build_ospf(u_shortlen,u_chartype,u_longrouter_id,
u_longarea_id,u_shortauth_type,
constchar*payload,intpayload_s,u_char*buf);
OSPF路由协议数据包(Hello):
intlibnet_build_ospf_hello(u_longnetmask,u_shortinterval,
u_charoptions,u_charpriority,
u_intdead_interval,u_longdes_router,
u_longbackup,u_longneighbor,
constchar*payload,intpayload_s,
u_char*buf);
OSPF路由协议数据包(DataBaseDescription(DBD)):
intlibnet_build_ospf_dbd(u_shortlen,u_charoptions,u_chartype,
u_intsequence_num,constchar*payload,
intpayload_s,u_char*buf);
OSPF路由协议数据包(LinkStateRequest(LSR)):
intlibnet_build_ospf_lsr(u_inttype,u_intls_id,u_longadv_router,
constchar*payload,intpayload_s,
u_char*buf);
OSPF路由协议数据包(LinkStateUpdate(LSU)):
intlibnet_build_ospf_lsu(u_intnum,constchar*payload,
intpayload_s,u_char*buf);
OSPF路由协议数据包(LinkStateAcknowledgement(LSA)):
intlibnet_build_ospf_lsa(u_shortage,u_charoptions,u_chartype,
u_intls_id,u_longadv_router,
u_intsequence_num,u_shortlen,
constchar*payload,intpayload_s,
u_char*buf);
OSPF路由协议数据包(OSPFLinkSateNetworkLinkStateRouter):
intlibnet_build_ospf_lsa_net(u_longnetmask,u_introuter_id,
constchar*payload,intpayload_s,
u_char*buf);
OSPF路由协议数据包(LinkStateRouter):
intlibnet_build_ospf_lsa_rtr(u_shortflags,u_shortnum,u_intid,
u_intdata,u_chartype,u_chartos,
u_shortmetric,constchar*payload,
intpayload_s,u_char*buf);
OSPF路由协议数据包(LinkStateSummary):
intlibnet_build_ospf_lsa_sum(u_longnetmask,u_intmetric,u_inttos,
constchar*payload,intpayload_s,
u_char*buf);
OSPF路由协议数据包(LinkStateASExternal):
intlibnet_build_ospf_lsa_as(u_longnetmask,u_intmetric,
u_longfwd_addr,u_inttag,
constchar*payload,intpayload_s,
u_char*buf);
RIP路由协议数据包:
intlibnet_build_rip(u_charcmd,u_charver,u_shortdomain,
u_shortaddr_fam,u_shortroute_tag,u_longip,
u_longmask,u_longnext_hop,u_longmetric,
constu_char*payload,intpayload_len,
u_char*packet_buf);
TCP协议数据包:
intlibnet_build_tcp(u_shortth_sport,u_shortth_dport,u_longth_seq,
u_longth_ack,u_charth_flags,u_shortth_win,
u_shortth_urg,constu_char*payload,
intpayload_len,u_char*packet_buf);
UDP协议数据包:
intlibnet_build_udp(u_shortsport,u_shortdport,constu_char*payload,
intpayload_len,u_char*packet_buf);
IP协议数据包选项:
intlibnet_insert_ipo(structipoption*opt,u_charopt_len,
u_char*packet_buf);
TCP协议数据包选项:
intlibnet_insert_tcpo(structtcpoption*opt,u_charopt_len,
u_char*packet_buf);
★数据包发送函数
打开rawsocket:
intlibnet_open_raw_sock(intprotocol);
关闭rawsocket:
intlibnet_close_raw_sock(intsocket);
选择接口设备:
intlibnet_select_device(structsockaddr_in*sin,
u_char**device,u_char*ebuf);
打开链路层接口设备:
structlibnet_link_int*libnet_open_link_interface(char*device,
char*ebuf);
关闭链路层接口设备:
intlibnet_close_link_interface(structlibnet_link_int*l);
发送IP数据包:
intlibnet_write_ip(intsocket,u_char*packet,intpacket_size);
发送链路层数据包:
intlibnet_write_link_layer(structlibnet_link_int*l,
constu_char*device,u_char*packet,
intpacket_size);
检验和计算:
intlibnet_do_checksum(u_char*packet,intprotocol,intpacket_size);
★相关的支持函数
随机数种子生成器:
intlibnet_seed_prand();
获取随机数:
u_longlibnet_get_prand(intmodulus);
16进制数据输出:
voidlibnet_hex_dump(u_char*buf,intlen,intswap,FILE*stream);
端口列表链初始化:
intlibnet_plist_chain_new(structlibnet_plist_chain**plist,
char*token_list);
获取端口列表链的下一项(端口范围):
intlibnet_plist_chain_next_pair(structlibnet_plist_chain*plist,
u_short*bport,u_short*eport);
端口列表链输出显示:
intlibnet_plist_chain_dump(structlibnet_plist_chain*plist);
获取端口列表链:
u_char*libnet_plist_chain_dump_string(structlibnet_plist_chain*plist);
端口列表链内存释放:
voidlibnet_plist_chain_free(structlibnet_plist_chain*plist);
---[]------------------------------------------
一、简介
libnids的英文意思是NetworkIntrusionDetectSystemlibrary,即网络入侵监
测系统函数库。它是在前面介绍的两种C函数接口库libnet和libpcap的基础上开发的,封
装了开发NIDS所需的许多通用型函数。linids提供的接口函数监视流经本地的所有网络通
信,检查数据包等。除此之外,还具有重组TCP数据段、处理IP分片包和监测TCP端口扫描
的功能。利用libnids接口函数库,NIDS开发者不需要再编写底层的网络处理代码,只需
专注于NIDS本身功能的实现即可。
libnids支持Linux、Solaris和*BSD系统平台,目前最新版本为1.13。
二、IP分片数据包
为了使libnids能接收所有的IP数据包(包括分片包、畸形包等),程序员需要定义如
下的回调函数:
voidip_frag_func(structip*a_packet)
在调用nids_init()函数初始化后,使用nids的函数进行注册:
nids_register_ip_frag(ip_frag_func);
这样回调函数ip_frag_func会在适当的时候由libnids调用,参数a_packet指针将指向接
收到的数据报。
类似地,如果仅接收目标主机会接受的数据包(如非碎片包、重组包或头部校验正确
的数据包等),需要定义如下回调函数:
voidip_func(structip*a_packet)
然后注册:
nids_register_ip(ip_func);
三、TCP数据流重组
要接收TCP流在交换的数据,必须定义如下回调函数:
voidtcp_callback(structtcp_stream*ns,void**param)
tcp_stream结构提供了一个TCP连接的所有信息。例如,它包含了客户端与服务器端的
half_stream结构。下文会对该结构的字段进行解释。
tcp_stream结构有一个名为nids_state的字段。此字段的数值将决定tcp_callback的
操作。
(a)ns->nids_state==NIDS_JUST_EST时,ns表示一个刚刚建立的连接。
tcp_callback可以据此决定是否对该连接的后续数据进行检查。如
需要检查,tcp_callback回调函数将通知libnids它希望接收哪些
数据(如到客户端的数据、到服务器端的数据、到客户端的紧急数
据或到服务器端的紧急数据等),然后返回。
(b)ns->nids_state==NIDS_DATA时,表示ns连接接收到新的数据。
half_stream结构中的缓冲区用于存放这些数据。
(c)nids_state字段为其它数值(NIDS_CLOSE、NIDS_RESET、
NIDS_TIMEOUT)时,表示该连接已经关闭了。tcp_callback函数应
释放相关资源。
四、一个简单的实例
下面的源代码是一个非常简单的程序,它将libnids捕获的所有TCP连接交换的数据输
出显示到标准输出设备上。
-----------------------BEGININGOFCODE--------------------------------
#include\"nids.h\"
#include
#include
externchar*inet_ntoa(unsignedlong);
//tuple4结构包含了TCP连接两端的IP地址和端口,以下函数将它们转换为字符串
//格式,如10.0.0.1,1024,10.0.0.2,23
char*
adres(structtuple4addr)
{
staticcharbuf;
strcpy(buf,inet_ntoa(addr.saddr));
sprintf(buf+strlen(buf),\",%i,\",addr.source);
strcat(buf,inet_ntoa(addr.daddr));
sprintf(buf+strlen(buf),\",%i\",addr.dest);
returnbuf;
}
void
tcp_callback(structtcp_stream*a_tcp,void**this_time_not_needed)
{
charbuf;
strcpy(buf,adres(a_tcp->addr));//weputconnparamsintobuf
if(a_tcp->nids_state==NIDS_JUST_EST)
{
//a_tcp所定义的连接已经建立。此处可视程序需要添加额外
//的判断处理。如if(a_tcp->addr.dest!=23)return;表
//示不处理目标端口为23的数据包。
//本例需要处理(显示)所有数据包,故:
a_tcp->client.collect++;//需要处理客户端接收的数据
a_tcp->server.collect++;//和服务器端接收的数据
a_tcp->server.collect_urg++;//需要处理服务器端接收的紧急数据
#ifdefWE_WANT_URGENT_DATA_RECEIVED_BY_A_CLIENT
a_tcp->client.collect_urg++;//需要处理客户端接收的紧急数据
//(打开编译选项才有效)
#endif
fprintf(stderr,\"%sestablished\\n\",buf);
return;
}
if(a_tcp->nids_state==NIDS_CLOSE)
{
//TCP连接正常关闭
fprintf(stderr,\"%sclosing\\n\",buf);
return;
}
if(a_tcp->nids_state==NIDS_RESET)
{
//TCP连接因RST数据包而关闭
fprintf(stderr,\"%sreset\\n\",buf);
return;
}
if(a_tcp->nids_state==NIDS_DATA)
{
//接收到新数据,下面判断决定是否显示
structhalf_stream*hlf;
if(a_tcp->server.count_new_urg)
{
//服务器端接收的紧急数据
strcat(buf,\"(urgent->)\");
buf=0;
buf=a_tcp->server.urgdata;
write(1,buf,strlen(buf));
return;
}
#ifdefWE_WANT_URGENT_DATA_RECEIVED_BY_A_CLIENT
if(a_tcp->client.count_new_urg)
{
//客户端接收的紧急数据
strcat(buf,\"(urgent->)\");
buf=0;
buf=a_tcp->server.urgdata;
write(1,buf,strlen(buf));
return;
}
#endif
if(a_tcp->client.count_new)
{
//客户端接收的数据
hlf=&a_tcp->client;//准备显示客户端接收的数据
strcat(buf,\"(<-)\");//指示数据流方向
}
else
{
hlf=&a_tcp->server;//准备显示服务器端接收的数据
strcat(buf,\"(->)\");//指示数据流方向
}
fprintf(stderr,\"%s\",buf);//首先输出显示连接双方的IP地址、端口
//和数据流方向
write(2,hlf->data,hlf->count_new);//输出显示接收到的新数据
}
return;
}
int
main()
{
//此处可自定义libnids的全局变量,如:
//nids_params.n_hosts=256;
if(!nids_init())
{
fprintf(stderr,\"%s\\n\",nids_errbuf);
exit(1);
}
nids_register_tcp(tcp_callback);
nids_run();
//NOTREACHED
return0;
}
---------------------------ENDOFCODE------------------------------------
五、libnids的数据结构及接口函数
libnids库的所有数据结构及接口函数都在\"nids.h\"头文件中声明。
structtuple4//TCP连接参数
{
unsignedshortsource,dest;//客户端和服务器端的端口号
unsignedlongsaddr,daddr;//客户端和服务器端的IP地址
};
structhalf_stream//TCP连接一端的数据结构
{
charstate;//套接字状态(如TCP_ESTABLISHED)
charcollect;//如果大于0,则保存其数据到缓冲区中,否则忽略
charcollect_urg;//如果大于0,则保存紧急数据,否则忽略
char*data;//正常数据的缓冲区
unsignedcharurgdata;//紧急数据缓冲区
intcount;//自从连接建立以来保存到\"data\"缓冲区的数据字节
//数总和
intoffset;//保存到\"data\"缓冲区的首字节数据偏移量
intcount_new;//最近一次接收到的数据字节数;如果为0,则无数
//到达
charcount_new_urg;//如果非0,表示有新的紧急数据到达
...//libnids库使用的辅助字段
};
structtcp_stream
{
structtuple4addr;//TCP连接参数(saddr,daddr,sport,dport)
charnids_state;//TCP连接的逻辑状态
structhalf_streamclient,server;//描述客户端与服务器端的数据结构
...//libnids库使用的辅助字段
};
在上面的实例程序中,回调函数tcp_callback输出显示hlf->data缓冲区中的数据到
标准输出设备上。这些数据在tcp_callback函数返回后,由libnids自动释放这些数据所
占用的内存空间。同时,hlf->offset字段将增加被丢弃数据的字节数,而新接收到的数
据则存放到\"data\"缓冲区的起始处。
如果在其它应用中不进行如上例的操作(例如,数据处理过程至少需要N个字节的输入
数据,而libnids只接收到的数据字节数count_new前调用如下函数:
voidnids_discard(structtcp_stream*a_tcp,intnum_bytes)
此时,当回调函数tcp_callback返回后linids将\"data\"缓冲区的前num_bytes字节数据,
同时计算调整offset字段的数值,并将剩余数据移动到缓冲区的起始处。
如果始终不调用nids_discard()函数(如上面实例),hlf->data缓冲区中将包含
hlf->count_new字节数据。通常情况下,在hlf->data缓冲区中的数据字节数等于
hlf->count-hlf->offset。
有了nids_discard()函数,程序员就不必拷贝接收到的数据到另外的缓冲区中,
hlf->data缓冲区将总是尽可能保存足够的数据。然后,有时会有保留数据包特定数据的
需要。例如,我们希望能监测到针对wu-ftpd服务器的\"CWD\"溢出攻击,就需要跟踪检查
ftp客户端发送的\"CWD\"命令。此时就需要tcp_callback回调函数具有第二个参数了。此参
数是某TCP连接私有数据的指针。处理过程如下:
void
tcp_callback_2(structtcp_stream*a_tcp,structconn_param**ptr)
{
if(a_tcp->nids_state==NIDS_JUST_EST)
{
structconn_param*a_conn;
iftheconnectionisuninteresting,return;
a_conn=mallocofsomedatastructure
initofa_conn
*ptr=a_conn//thisvaluewillbepassedtotcp_callback_2infuture
//calls
increasesomeof\"collect\"fields
return;
}
if(a_tcp->nids_state==NIDS_DATA)
{
structconn_param*current_conn_param=*ptr;
usingcurrent_conn_paramandthenewlyreceiveddatafromthenet
wesearchforattacksignatures,possiblymodyfying
current_conn_param
return;
}
...
}
nids_register_tcp和nids_register_ip*函数可被任意次调用。在同一个TCP连接中
使用两种不同的回调函数是允许的。
libnids库定义了一个全局变量结构nids_params,其声明如下:
structnids_prm
{
intn_tcp_streams;//存放tcp_stream结构的hash表大小。
//缺省值:1024
intn_hosts;//存放IP分片信息的hash表大小
//缺省值:256
char*device;//libnids监听的接口设备名
//缺省值==NULL,即由pcap_lookupdev函数确定
intsk_buff_size;//(Linux内核)sk_buff结构大小
//缺省值:168
intdev_addon;//sk_buff为网络接口保留的字节数
//如果dev_addon==-1,则由nids_init函数确定
//缺省值:-1
void(*syslog)();//日志函数指针
intsyslog_level;//如果nids_params.syslog==nids_syslog,则此字段值
//将确定日志等级loglevel
//缺省值:LOG_ALERT
intscan_num_hosts;//存放端口扫描信息的hash表大小。
//如果为0,则关闭端口扫描监测功能。
//缺省值:256
intscan_num_ports;//来自同一IP地址所扫描的TCP端口数上限
//缺省值:10
intscan_delay;//在两次端口扫描中的间隔时间上限(毫秒)
//缺省值:3000
void(*no_mem)();//内存不足时被调用,此时应终止当前进程
int(*ip_filter)(structip*);//当接收到一个IP数据包时调用。如返回值
//非零,则处理该数据包,否则忽略。
//缺省为(nids_ip_filter)且总返回1
char*pcap_filter;//传递给pcap过滤器的字符串。
//缺省值:NULL
}nids_params;
nids_params的syslog字段缺省时指向nids_syslog函数,声明如下:
voidnids_syslog(inttype,interrnum,structip*iph,void*data);
nids_params.syslog函数用于记录异常情况,如端口扫描企图,无效TCP头标志等。
该字段应指向自定义的日志处理函数。nids_syslog()仅作为一个例子。nids_syslog()函
数向系统守护服务syslogd发送日志消息。
使用nids_run有一个缺陷:应用程序将完全由数据包驱动(运行)。有时需要在没有数
据包到达时也能处理一些任务,则作为nids_run()函数的替代,程序员可使用如下函数:
intnids_next()
此函数将调用pcap_next()函数(而不是pcap_loop()函数)。(详细资料请参阅《网络安全
工具开发函数库介绍之二——libpcap》。)nids_next()函数成功时返回1,出错时返回
0,且nids_errbuf缓冲区存放相应错误消息。
典型地,当使用nids_next()函数时,应用程序调用I/O复用函数select()阻塞,监听
套接字fd在“读”描述字集合fd_set中设置。该套接字可通过如下函数获得:
intnids_getfd()
成功时返回一个文件描述字,出错时返回-1,且nids_errbuf缓冲区存放相应错误消息。
---[]----------------------------------
1、nids_next()函数的应用
============================cuthere============================
/*
Thisisanexamplehowonecanusenids_getfd()andnids_next()functions.
Youcanreplaceprintall.c\'sfunctionmainwiththisfile.
*/
#include
#include
#include
int
main()
{
//herewecanalterlibnidsparams,forinstance:
//nids_params.n_hosts=256;
intfd;
inttime=0;
fd_setrset;
structtimevaltv;
if(!nids_init())
{
fprintf(stderr,\"%s\\n\",nids_errbuf);
exit(1);
}
nids_register_tcp(tcp_callback);
fd=nids_getfd();
for(;;)
{
tv.tv_sec=1;
tv.tv_usec=0;
FD_ZERO(&rset);
FD_SET(fd,&rset);
//addanyotherfdweneedtotakecareof
if(select(fd+1,&rset,0,0,&tv))
{
if(FD_ISSET(fd,&rset)//needtotestitifthereareother
//fdinrset
if(!nids_next())break;
}
else
fprintf(stderr,\"%i\",time++);
}
return0;
}
============================cuthere============================
2、Simplesniffer
============================cuthere============================
/*
Copyright(c)1999RafalWojtczuk.Allrights
reserved.
SeethefileCOPYINGforlicensedetails.
*/
#include
#include
#include
#include
#include
#include
#include
#include\"nids.h\"
#defineLOG_MAX100
#defineSZLACZEK\"\\n--------------------------------------------------\\n\"
#defineint_ntoa(x)inet_ntoa(*((structin_addr*)&x))
char*
adres(structtuple4addr)
{
staticcharbuf;
strcpy(buf,int_ntoa(addr.saddr));
sprintf(buf+strlen(buf),\",%i,\",addr.source);
strcat(buf,int_ntoa(addr.daddr));
sprintf(buf+strlen(buf),\",%i:\",addr.dest);
returnbuf;
}
intlogfd;
void
do_log(char*adres_txt,char*data,intile)
{
write(logfd,adres_txt,strlen(adres_txt));
write(logfd,data,ile);
write(logfd,SZLACZEK,strlen(SZLACZEK));
}
void
sniff_callback(structtcp_stream*a_tcp,void**this_time_not_needed)
{
intdest;
if(a_tcp->nids_state==NIDS_JUST_EST)
{
dest=a_tcp->addr.dest;
if(dest==21||dest==23||dest==110||dest==143||dest==
513)
a_tcp->server.collect++;
return;
}
if(a_tcp->nids_state!=NIDS_DATA)
{
//seemsthestreamisclosing,logasmuchaspossible
do_log(adres(a_tcp->addr),a_tcp->server.data,
a_tcp->server.count-a_tcp->server.offset);
return;
}
if(a_tcp->server.count-a_tcp->server.offset
{
//wehaven\'tgotenoughdatayet;keepallofit
nids_discard(a_tcp,0);
return;
}
//enoughdata
do_log(adres(a_tcp->addr),a_tcp->server.data,LOG_MAX);
//Nowproceduresniff_callbackdoesn\'twanttoseethisstreamanymore.
//So,wedecreaseallthe\"collect\"fieldswehavepreviouslyincreased.
//Iftherewereothercallbacksfollowinga_tcpstream,theywouldstill
//receivedata
a_tcp->server.collect--;
}
int
main()
{
logfd=open(\"./logfile\",O_WRONLY|O_CREAT|O_TRUNC,0600);
if(logfd<0)
{
perror(\"opening./logfile:\");
exit(1);
}
if(!nids_init())
{
fprintf(stderr,\"%s\\n\",nids_errbuf);
exit(1);
}
nids_register_tcp(sniff_callback);
nids_run();
return0;
}
============================cuthere============================
3、Wu-FTPdoverflowattackdetector
============================cuthere============================
/*
Copyright(c)1999RafalWojtczuk.Allrightsreserved.
SeethefileCOPYINGforlicensedetails.
*/
/*
Thiscodeattemptstodetectattackagainstimapd(AUTHENTICATEhole)and
wuftpd(creationofdeepdirectory).Thiscodeistoilustrateuseoflibnids;
inordertoimprovereadability,somesimplificationsweremade,whichenables
anattackertobypassthiscode(note,thebelowroutinesshouldbeimproved,
notlibnids)
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include\"nids.h\"
#defineint_ntoa(x)inet_ntoa(*((structin_addr*)&x))
char*
adres(structtuple4addr)
{
staticcharbuf;
strcpy(buf,int_ntoa(addr.saddr));
sprintf(buf+strlen(buf),\",%i,\",addr.source);
strcat(buf,int_ntoa(addr.daddr));
sprintf(buf+strlen(buf),\",%i\",addr.dest);
returnbuf;
}
/*
ifwefindapatternAUTHENTICATE{an_int}indatastreamsenttoanimap
server,wherean_int>1024,itmeansanbufferoverflowattempt.Wekillthe
connection.
*/
#definePATTERN\"AUTHENTICATE{\"
#definePATLENstrlen(PATTERN)
void
detect_imap(structtcp_stream*a_tcp)
{
charnumbuf;
inti,j,datalen,numberlen;
structhalf_stream*hlf;
if(a_tcp->nids_state==NIDS_JUST_EST)
{
if(a_tcp->addr.dest==143)
{
a_tcp->server.collect++;
return;
}
else
return;
}
if(a_tcp->nids_state!=NIDS_DATA)
return;
hlf=&a_tcp->server;
datalen=hlf->count-hlf->offset;
if(datalen
{
//wehavetoosmallamountofdatatoworkon.Keepalldatainbuffer.
nids_discard(a_tcp,0);
return;
}
for(i=0;i<=datalen-PATLEN;i++)
if(!memcmp(PATTERN,hlf->data+i,PATLEN))//searchingforapattern
break;
if(i>datalen-PATLEN)
{
//retainPATLENbytesinbuffer
nids_discard(a_tcp,datalen-PATLEN);
return;
}
for(j=i+PATLEN;j
if(*(hlf->data+j)==\'}\')
break;
if(j>datalen)
{
if(datalen>20)
{
//numbertoolong,perhapsweshouldlogit,too
}
return;
}
numberlen=j-i-PATLEN;
memcpy(numbuf,hlf->data+i+PATLEN,numberlen);//numbufcontains
//AUTHargument
numbuf=0;
if(atoi(numbuf)>1024)
{
//notifyadmin
syslog(nids_params.syslog_level,
\"Imapdexploitattempt,connection%s\\n\",adres(a_tcp->addr));
//killtheconnection
nids_killtcp(a_tcp);
}
nids_discard(a_tcp,datalen-PATLEN);
return;
}
//auxiliarystructure,neededtokeepcurrentdirofftpddaemon
structsupp
{
char*currdir;
intlast_newline;
};
//thebelowfunctionadds\"elem\"stringto\"path\"string,takingcareof
//\"..\"andmultiple\'/\'.Iftheresultingpathislongerthan768,
//returnvalueis1,otherwise0
int
add_to_path(char*path,char*elem,intlen)
{
intplen;
char*ptr;
if(len>768)
return1;
if(len==2&&elem==\'.\'&&elem==\'.\')
{
ptr=rindex(path,\'/\');
if(ptr!=path)
*ptr=0;
}
elseif(len>0)
{
plen=strlen(path);
if(plen+len+1>768)
return1;
if(plen==1)
{
strncpy(path+1,elem,len);
path=0;
}
else
{
path=\'/\';
strncpy(path+plen+1,elem,len);
path=0;
}
}
return0;
}
void
do_detect_ftp(structtcp_stream*a_tcp,structsupp**param_ptr)
{
structsupp*p=*param_ptr;
intindex=p->last_newline+1;
char*buf=a_tcp->server.data;
intoffset=a_tcp->server.offset;
intn_bytes=a_tcp->server.count-offset;
intpath_index,pi2,index2,remcaret;
for(;;)
{
index2=index;
while(index2-offset
index2++;
if(index2-offset>=n_bytes)
break;
if(!strncasecmp(buf+index-offset,\"cwd\",4))
{
path_index=index+4;
if(buf==\'/\')
{
strcpy(p->currdir,\"/\");
path_index++;
}
for(;;)
{
pi2=path_index;
while(buf!=\'\\n\'&&buf!=\'/\')
pi2++;
if(buf==\'\\n\'&&buf==\'\\r\')
remcaret=1;
elseremcaret=0;
if(add_to_path(p->currdir,buf+path_index-offset,pi2-
path_index-remcaret))
{
//notifyadmin
syslog(nids_params.syslog_level,
\"Ftpdexploitattempt,connection%s\\n\",adres(a_tcp->addr));
nids_killtcp(a_tcp);
return;
}
if(buf==\'\\n\')
break;
path_index=pi2+1;
}
}
index=index2+1;
}
p->last_newline=index-1;
nids_discard(a_tcp,index-offset);
}
void
detect_ftpd(structtcp_stream*a_tcp,structsupp**param)
{
if(a_tcp->nids_state==NIDS_JUST_EST)
{
if(a_tcp->addr.dest==21)
{
structsupp*one_for_conn;
a_tcp->server.collect++;
one_for_conn=(structsupp*)malloc(sizeof(structsupp));
one_for_conn->currdir=malloc(1024);
strcpy(one_for_conn->currdir,\"/\");
one_for_conn->last_newline=0;
*param=one_for_conn;
}
return;
}
if(a_tcp->nids_state!=NIDS_DATA)
{
free((*param)->currdir);
free(*param);
return;
}
do_detect_ftp(a_tcp,param);
}
int
main()
{
if(!nids_init())
{
fprintf(stderr,\"%s\\n\",nids_errbuf);
exit(1);
}
nids_register_tcp(detect_imap);
nids_register_tcp(detect_ftpd);
nids_run();
return0;
}
原文出处:http://blog.ccidnet.com/blog-htm-do-showone-uid-36931-itemid-138338-type-blog.html