Yersinia是一款底层协议攻击入侵检测工具。它能实施针对多种协议的多种攻击。例如夺取生成树的根角色(生成树协议:Spanning Tree Protocol),生成虚拟CDP(Cisco发现协议:Cisco Discovery Protocol)邻居、在一个HSRP(热等待路由协议:Hot Standby Router Protocol)环境中虚拟成一个活动的路由器、制造假DHCP反馈,以及其它底层攻击。
下载链接:http://down.51cto.com/data/155576
支持的协议
* Spanning Tree Protocol (STP) : 生成树协议 : 该协议可应用于环路网络,通过一定的算法实现路径冗余,同时将环路网络修剪成无环路的树型网络,从而避免报文在环路网络中的增生和无限循环
* Cisco Discovery Protocol (CDP) : 思科发现协议 : 基本上是用来获取相邻设备的协议地址以及发现这些设备的平台
* Dynamic Trunking Protocol (DTP) : 动态中继协议 : VLAN 协议组中思科专有协议,主要用于协商两台设备间链路上的中继及中继封装(如 802.1Q)类型
* Dynamic Host Configuration Protocol (DHCP) : 动态主机分配协议 : 它分为两个部份:一个是服务器端,而另一个是客户端。所有的 IP 网络设定数据都由 DHCP 服务器集中管理,并负责处理客户端的 DHCP 要求;而客户端则会使用从服务器分配下来的IP环境数据
* Hot Standby Router Protocol (HSRP) : 热备份路由器协议 : HSRP 的设计目标是支持特定情况下 IP 流量失败转移不会引起混乱、并允许主机使用单路由器,以及即使在实际第一跳路由器使用失败的情形下仍能维护路由器间的连通性
* IEEE 802.1Q
* IEEE 802.1X
* Inter-Switch Link Protocol (ISL) : 交换链路内协议 : 是思科私有协议,主要用于维护交换机和路由器间的通信流量等 VLAN 信息
* VLAN Trunking Protocol (VTP) : vlan干道协议 : VTP通过网络(ISL帧或cisco私有DTP帧)保持VLAN配置统一性。VTP在系统级管理增加,删除,调整的VLAN,自动地将信息向网络中其它的交换机广播
支持的操作系统
* OpenBSD 3.4 ( 注意 : 需要升级 pcap 库 至少到 0.7.2)
* Linux 2.4.x and 2.6.x
* Solaris 5.8 64bits SPARC
* Mac OSX 10.4 Tiger (Intel)
HACKER YERSINIA
1.简介 : 作者将引导我们一步步添加解析VRRP协议的代码到 Yersinia 中
2.注册协议 : 在创建vrrp.c和vrrp.h文件后第一件事就是注册该协议,然后Yersinia就可以用我们提供的协议进行攻击,当然也便于Yersinia提供给我们协议感兴趣的数据
跳到 protocols.c::protocol_register_al() 的函数
void
protocol_register_all(void)
{
{ extern void xstp_register(void); xstp_register(); }
{ extern void cdp_register(void); cdp_register(); }
{ extern void dtp_register(void); dtp_register(); }
{ extern void dhcp_register(void); dhcp_register(); }
{ extern void hsrp_register(void); hsrp_register(); }
{ extern void dot1q_register(void); dot1q_register(); }
{ extern void isl_register(void); isl_register(); }
{ extern void vtp_register(void); vtp_register(); }
{ extern void arp_register(void); arp_register(); }
{ extern void dot1x_register(void); dot1x_register(); }
{ extern void vrrp_register(void); vrrp_register(); }
}
由此推测我们也需要自己的注册函数,在vrrp.c中定义下列函数
void vrrp_register(void)
{
protocol_register(PROTO_VRRP, "VRRP", "Virtual Router Redundancy Protocol",
"vrrp", sizeof(struct vrrp_data), vrrp_init_attribs, NULL,
vrrp_get_printable_packet, vrrp_get_printable_store,
vrrp_load_values, vrrp_attack,
vrrp_update_field,
vrrp_features, vrrp_comm_params, SIZE_ARRAY(vrrp_comm_params),
NULL, 0, NULL, vrrp_init_comms_struct, PROTO_VISIBLE, vrrp_end);
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
它又调用了 protocols.c::protocol_register()函数
int8_t protocol_register(
u_int8_t proto, : 协议标识 我们把它定义到 protocol.h 中 #define PROTO_VRRP 10
const char *name, : 协议字符串名称
const char *desc, : 协议的简单描述
const char *name_comm, : 通俗点的名称
u_int16_t size, : vrrp_data 结构体 的大小
init_attribs_t init, : 初始化协议的回调函数,函数声明:int8_t vrrp_init_attribs(struct term_node *node);
learn_packet_t learn, : 得到数据包时调用该函数,我们需要把数据复制到 vrrp_data 结构中,函数声明:vrrp_learn_packet(struct attacks *attacks, char *iface, u_int8_t *stop, void *data, struct pcap_pkthdr *header, struct pcap_data *pcap_aux);
get_printable_packet_t packet, : 把数据包解释成可读的一个字符串
get_printable_store_t store, :
load_values_t load, : 解析接收到的数据包( 作者不太明白 vrrp_learn_packet()与vrrp_load_values()的区别 )
struct attack *attacks, : 该协议中所有可用的攻击类型
update_field_t update_field, : 看起来这个回调函数是用来在用户输入一个命令行参数(比如源IP或目录MAC...)时更新这个数据包中的某些字段
struct proto_features *features, : 作者也不太明白,在 protcols.h 中定义
struct commands_param *param, : 存放需要提供给用户的命令行及默认值
u_int8_t nparams, : 同上
struct commands_param_extra *extra_parameters, : 置空之
u_int8_t extra_nparams, get_extra_field_t extra, : 置空之
init_commands_struct_t init_commands, :
u_int8_t visible, : 设置为 PROTO_VISIBLE
end_t end) : 翻译资源的回调函数
{
.....code.....
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
3.填充协议 : 注册协议时我们填充了许多回调函数和结构体,现在开始详细填充之
vrrp_data : 该结构体用来存放该协议的头和以太网头
void vrrp_init_attribs(struct term_node *node) : 该回调函数接收一个 term_node 类型的数据,因为该函数是回调函数,所以
应该是被调用的,term_node数据也已经填充好,我们需要取出其中数据去填充 vrrp_data ,比如版本号,源/目的端口号
char **hsrp_get_printable_packet(struct pcap_data *data) : 该回调函数用来把数据包解析成可阅读形式的字符串 data 是捕获
的数据包,我们从这个函数中分配一块内存用来存放字符串#p#
int8_t vrrp_load_values(struct pcap_data *data, void *values) : 该函数每次捕获到数据包时都被调用,data指向数据包,
可以被我们用来填充 vrrp_data , 也就是说我们应该从这解析该协议
struct attack { ... } : 这就是我们模块的核心
struct attack {
int16_t v; : 记录攻击的次数
char *s; : 对该攻击的一些描述
int8_t type; : 是否为 (DOS) 攻击
int8_t single; : 我们是一次发一个还是洪水般发送
void (*attack_th_launch)(void *); : 我们发动攻击的回调函数
const struct attack_param *param; : 上边函数的参数
u_int8_t nparams; : 上边函数的参数个数
};
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
这就是我们一开始等待的东西,这就是我们的攻击功能的模块的核心,在 fot1q.h 中有详细的介绍 :
-----------------------------------------------------------------------------------------
#define DOT1Q_ATTACK_SEND 0
#define DOT1Q_ATTACK_DOUBLE 1
#define DOT1Q_ATTACK_POISON 2
static struct attack dot1q_attack[] = {
{ DOT1Q_ATTACK_SEND, "sending 802.1Q packet", NONDOS, SINGLE, dot1q_th_send, NULL, 0 },
{ DOT1Q_ATTACK_DOUBLE, "sending 802.1Q double enc. packet", NONDOS, SINGLE, dot1q_double_th_send, NULL, 0 },
{ DOT1Q_ATTACK_POISON, "sending 802.1Q arp poisoning", DOS, CONTINOUS, dot1q_th_poison,
dot1q_arp_params, SIZE_ARRAY(dot1q_arp_params) },
{ 0, NULL, 0, 0, NULL, NULL, 0 }
};
void dot1q_th_send(void *);
void dot1q_th_send_exit(struct attacks *);
void dot1q_double_th_send(void *);
void dot1q_double_th_send_exit(struct attacks *);
void dot1q_th_poison(void *);
void dot1q_th_poison_exit(struct attacks *);
-----------------------------------------------------------------------------------------
从上可以看出传递到registration函数的是一个attack结构体数组,xxxxx,下面介绍结构体中的各字段
- v: 好像是每个 attack 的ID : 0,1,2 ...
- s: 一些 attack 的描述
- type: 是否为拒绝服务式的攻击(DOS)
- single: 我们是发送一个数据包(SINGLE) 还是发送洪水数据包(CONTINUOUS)
- attack_th_launch: 我们将要调用的函数,比如在这个函数中完成这次攻击
- param, nparams: 传递给上述函数的参数和参数个数
下面看下 dot1q.c 和 terminal-defs.h 文件
-----------------------------------------------------------------------------------------
struct attacks
{
u_int8_t up; /* active or not */
THREAD attack_th;
THREAD helper_th;
u_int16_t attack; /* attack number */
list_t *used_ints; /* interfaces used */
u_int8_t mac_spoofing;
void *data; /* packet */
void *params; /* Parameters */
u_int8_t nparams; /* How many params */
};
void dot1q_th_send(void *arg)
{
struct attacks *attacks=NULL;
sigset_t mask;
struct dot1q_data *dot1q_data;
attacks = arg;
pthread_mutex_lock(&attacks->attack_th.finished);
pthread_detach(pthread_self());
sigfillset(&mask);
if (pthread_sigmask(SIG_BLOCK, &mask, NULL))
{
thread_error("dot1q_th_send pthread_sigmask()",errno);
dot1q_th_send_exit(attacks);
}
dot1q_data = attacks->data;
dot1q_data->tpi1 = ETHERTYPE_VLAN;
dot1q_data->tpi2 = ETHERTYPE_IP;
dot1q_send_icmp(attacks,0);
dot1q_th_send_exit(attacks);
}
void dot1q_th_send_exit(struct attacks *attacks)
{
if (attacks) attack_th_exit(attacks);
pthread_mutex_unlock(&attacks->attack_th.finished);
pthread_exit(NULL);
}
int8_t dot1q_send_icmp(struct attacks *attacks, u_int8_t double_encap)
{
.....code.....
}
-----------------------------------------------------------------------------------------
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
注意 attacks 结构体和 attack 结构体是完全不一样的,attacks 对象是传递给函数 dot1q_th_send 的,还有参数(arg),每个attack都含很多有用的信息,比如 thread-id(每个attack都在一个单独的线程中) , dot1q_data(数据) ,还有参数及参数的个数等 . 然后我们在 dot1q_th_send() 中创建一个互斥体 , 然后调用 pthread_detach() (与主线程分享) ,然后调用 dot1q_send_icmp(attacks,0) , 然后调用 dot1q_th_send_exit(attacks) 函数