79265907

Date: 2024-12-09 17:32:28
Score: 1.5
Natty:
Report link

I am able to get the DUT to respond to the fabricated packet.

It appears the checksums were computed badly. I updated the check sum for the TCP computation, since I learned that the TCP needs to have a "pseudo IP" header to make the computation. It's explained here: Calculation of TCP Checksum

I also restructured the code to build it from the inside out (TCP-> IP-> Ethernet) and the DUT responds to the SYN.

I also disabled "Checksum offload" on the Linux PC to be sure, and to allow me to see and verify the checksums.

So the result: it puts me back to my first reported challenge trying to fabricate a test for RFC5961:

The problem is that after the ACK to the SYN, Linux is sending a RST on it's own. I learned that is because the socket has nothing listening or connected. I don't know how to get around that, since it's closing before my test even has a chance to issue a "revcfrom()"

WireShark Screen Shot of the RST packet

For anyone who is interested, here is the updated code for "main.cpp". It's not meant to be robust or defensive, just to test fabricating a packet from the Ethernet level.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>

#include <netinet/in.h>
#include <netinet/ip.h>       // struct ip and IP_MAXPACKET (which is 65535)
#include <netinet/in.h>       // IPPROTO_RAW, IPPROTO_IP, IPPROTO_TCP, INET_ADDRSTRLEN
#define __FAVOR_BSD           // Use BSD format of tcp header
#include <netinet/tcp.h>      // struct tcphdr
#include <arpa/inet.h>        // inet_pton() and inet_ntop()

#include <errno.h>
#include "Packet.h"

int BuildEthernetHdr(unsigned char **buffer, uint8_t *src_ip, uint8_t *dst_ip);
int BuildIPHdr(unsigned char **buffer, const char *src_ip, const char *dst_ip);
int BuildTCPHdr(unsigned char **buffer, const char *, const char *);

uint16_t checksum (uint8_t *addr, int len);

unsigned char buffer[2048];
int main() {
    int tcplen, iplen, maclen, len;
    unsigned char *eth, *tcp, *ip, *pkt;
    CPacket packet;

    uint8_t     srcMac[6];
    uint8_t     dstMac[6];

    tcplen = BuildTCPHdr(&tcp, "192.168.1.211","192.168.1.94");

    iplen = BuildIPHdr(&ip, "192.168.1.211","192.168.1.94");
    //  Know your MAC addresses... 
    memcpy(srcMac, "\x60\xa4\x4c\x63\x4d\x9e", 6);
    memcpy(dstMac, "\xa4\x9b\x13\x00\xfe\x0e", 6);

    maclen = BuildEthernetHdr(&eth,srcMac, dstMac);

    packet.Initialize();

    pkt = buffer;

    memcpy(pkt,eth, maclen);
    pkt += maclen;
    memcpy(pkt,ip, iplen);
    pkt += iplen;
    memcpy(pkt,tcp, tcplen);
    pkt += tcplen;

    len = pkt - buffer;

    packet.SendMessage(buffer, len);
    free(tcp);
    free(ip);
    free(eth);
    packet.Cleanup();
    return EXIT_SUCCESS;
}

#define IP4_HDRLEN      20
#define TCP_HDRLEN      20
#define ETH_HDRLEN      14

int BuildEthernetHdr(uint8_t **buffer, uint8_t *src_mac, uint8_t *dst_mac) {
    ETHERHDR * ethhdr;
    ethhdr = (ETHERHDR * )malloc(sizeof(ETHERHDR));

    memcpy(ethhdr->srcMac, src_mac,6);
    memcpy(ethhdr->dstMac, dst_mac,6);
    ethhdr->etherType = htons(0x0800);

    *buffer = (uint8_t*) ethhdr;

    return sizeof(ETHERHDR);
}

int BuildIPHdr(uint8_t **buffer, const char *src_ip, const char *dst_ip) {
    struct ip *iphdr;
    int status;
    unsigned int ip_flags[4];
    iphdr = (struct ip*) malloc(sizeof(struct ip));
    memset(iphdr,0,sizeof(struct ip));

    iphdr->ip_hl = IP4_HDRLEN / sizeof (uint32_t);

    // Internet Protocol version (4 bits): IPv4
    iphdr->ip_v = 4;

    // Type of service (8 bits)
    iphdr->ip_tos = 0;

    // Total length of datagram (16 bits): IP header + TCP header
    iphdr->ip_len = htons (IP4_HDRLEN + TCP_HDRLEN);

    // ID sequence number (16 bits): unused, since single datagram
    iphdr->ip_id = htons (0);

    // Flags, and Fragmentation offset (3, 13 bits): 0 since single datagram

    // Zero (1 bit)
    ip_flags[0] = 0;

    // Do not fragment flag (1 bit)
    ip_flags[1] = 1;

    // More fragments following flag (1 bit)
    ip_flags[2] = 0;

    // Fragmentation offset (13 bits)
    ip_flags[3] = 0;

    iphdr->ip_off = htons ((ip_flags[0] << 15)
                          + (ip_flags[1] << 14)
                          + (ip_flags[2] << 13)
                          +  ip_flags[3]);

    // Time-to-Live (8 bits): default to maximum value
    iphdr->ip_ttl = 64;

    // Transport layer protocol (8 bits): 6 for TCP
    iphdr->ip_p = IPPROTO_TCP;

    // Source IPv4 address (32 bits)
    if ((status = inet_pton (AF_INET, src_ip, &(iphdr->ip_src))) != 1) {
      fprintf (stderr, "inet_pton() failed for source address.\nError message: %s", strerror (status));
        exit (EXIT_FAILURE);
      }

      // Destination IPv4 address (32 bits)
      if ((status = inet_pton (AF_INET, dst_ip, &(iphdr->ip_dst))) != 1) {
        fprintf (stderr, "inet_pton() failed for destination address.\nError message: %s", strerror (status));
        exit (EXIT_FAILURE);
      }

      // IPv4 header checksum (16 bits): set to 0 when calculating checksum
      iphdr->ip_sum = 0;
      iphdr->ip_sum = checksum ((uint8_t*) iphdr, IP4_HDRLEN);

      printf("IP Chk %x\n", iphdr->ip_sum);

      *buffer = (uint8_t *)iphdr;
      return sizeof(struct ip);
}


typedef struct {
    uint32_t srcIP[1];
    uint32_t dstIP[1];
    uint8_t res[1];
    uint8_t proto[1];
    uint16_t len[1];
} IP_PSEUDO;

uint8_t * PseudoHeader(uint8_t * packet, uint16_t len, uint32_t dst, uint32_t src) {
    IP_PSEUDO * iphdr;
    memmove(&packet[12], packet, len);
    iphdr = (IP_PSEUDO*)packet;
    iphdr->dstIP[0] = dst;      // 5e = 94
    iphdr->srcIP[0] = src;      // d3 = 211
    iphdr->res[0] = 0;
    iphdr->proto[0] = 6;
    iphdr->len[0] = htons(len);
    return &packet[20];
}

int BuildTCPHdr(uint8_t **buffer, const char * src, const char *dest) {

    struct tcphdr *tcphdr;
    int optsize = 0;
    unsigned int tcp_flags[8];
    unsigned char optbuffer[20];

    tcphdr = (struct tcphdr *) malloc(sizeof(struct tcphdr));
    memset(tcphdr,0,sizeof(struct tcphdr));
    if (false) {
      //  Option     length (with itself)          value
        optbuffer[0] = 2; optbuffer[1] = 4; optbuffer[2] = 5; optbuffer [3] = 0xb4;   //Max Seg Size
        optbuffer[4] = 4; optbuffer[5] = 2;      // SACK permitted
      uint32_t time1 = 0x12345678;  uint32_t time2 = 0x87654321;
      optbuffer[6] = 8; optbuffer[7] = 10;  memcpy(&optbuffer[8], &time1, 4); memcpy(&optbuffer[12], &time2, 4);
      optbuffer[16] = 1; // NoOp
      optbuffer[17] = 3; optbuffer[18] = 3; optbuffer[19] = 7;     // Shift Multiplier
      optsize = 20;
    }
  // Source port number (16 bits)
  tcphdr->th_sport = htons (32500);

  // Destination port number (16 bits)
  tcphdr->th_dport = htons (80);

  // Sequence number (32 bits)
  tcphdr->th_seq = htonl (5);

  // Acknowledgement number (32 bits): 0 in first packet of SYN/ACK process
  tcphdr->th_ack = htonl (0);

  // Reserved (4 bits): should be 0
  tcphdr->th_x2 = 0;

  // Data offset (4 bits): size of TCP header in 32-bit words
  tcphdr->th_off = (TCP_HDRLEN + optsize) / 4;

  // Flags (8 bits)

  // FIN flag (1 bit)
  tcp_flags[0] = 0;

  // SYN flag (1 bit): set to 1
  tcp_flags[1] = 1;

  // RST flag (1 bit)
  tcp_flags[2] = 0;

  // PSH flag (1 bit)
  tcp_flags[3] = 0;

  // ACK flag (1 bit)
  tcp_flags[4] = 0;

  // URG flag (1 bit)
  tcp_flags[5] = 0;

  // ECE flag (1 bit)
  tcp_flags[6] = 0;

  // CWR flag (1 bit)
  tcp_flags[7] = 0;

  tcphdr->th_flags = 0;
  for (int i=0; i<8; i++) {
    tcphdr->th_flags += (tcp_flags[i] << i);
  }

  // Window size (16 bits)
  tcphdr->th_win = htons (8192);

  // Urgent pointer (16 bits): 0 (only valid if URG flag is set)
  tcphdr->th_urp = htons (0);

  // TCP checksum (16 bits)
  uint8_t temp[64];
  memset(temp,0,64);
  uint32_t ip_src, ip_dest;
  inet_pton (AF_INET, src, &ip_src);
  inet_pton (AF_INET, dest, &ip_dest);
  memcpy(temp,tcphdr,sizeof(struct tcphdr));
  
  PseudoHeader(temp,20, ip_src,ip_dest);

  tcphdr->th_sum = checksum(temp, sizeof(struct tcphdr) + 12);
  printf("TCP Chk %x\n", tcphdr->th_sum);
  
  *buffer = (uint8_t*) tcphdr;
  return sizeof(struct tcphdr);

}


// Computing the internet checksum (RFC 1071).
// Note that the internet checksum is not guaranteed to preclude collisions.
uint16_t checksum(uint8_t *addr, int len) {

    int count = len;
    register uint32_t sum = 0;
    uint16_t answer = 0;

    // Sum up 2-byte values until none or only one byte left.
    while (count > 1) {
        printf(" Adding %04x \n", *((unsigned short *)(addr)));
        sum += htons(*((unsigned short *)(addr)));
        addr += 2;
        count -= 2;
    }

    // Add left-over byte, if any.
    if (count > 0) {
        sum += *(uint8_t *)addr;
    }

    // Fold 32-bit sum into 16 bits; we lose information by doing this,
    // increasing the chances of a collision.
    // sum = (lower 16 bits) + (upper 16 bits shifted right 16 bits)
    sum = htonl(sum);
    while (sum >> 16) {
        sum = (sum & 0xffff) + (sum >> 16);
    }

    // Checksum is one's compliment of sum.
    answer = ~sum;

    return (answer);
}
Reasons:
  • RegEx Blacklisted phrase (2): Urgent
  • Long answer (-1):
  • Has code block (-0.5):
  • Self-answer (0.5):
  • Low reputation (0.5):
Posted by: SpacemanScott