Yersinia:一款支持多協議的底層攻擊檢測工具
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);
- }
它又調用了 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.....
- }
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; : 上邊函數的參數個數
- };
這就是我們一開始等待的東西,這就是我們的攻擊功能的模塊的核心,在 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.....
- }
- -----------------------------------------------------------------------------------------
注意 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) 函數