TCP steganography is not something fundamentally new, for example, John Torakis implemented quite interesting things on Python in 2016, it 's a pity that not all of them are publicly available. It was not fundamentally new at the time of writing the articles by Thorakis. Here is a post on Habré of 2009, describing the idea and, for example, the Covert_TCP program of the far (and maybe not very much) 1996, written in pure C and implementing quite subtle settings.
If Covert TCP proposes to transfer one byte of payload in a TCP packet, Torakis used from 2 to 6 bytes per packet and suggested the idea of creating a protocol in the protocol. But even in this way it is difficult to transfer large amounts of data.
Here the system of one-time messages can come to the rescue. Indeed, why not combine the two approaches, since they were invented before us?
So, the characters are machine 1 (sender) and machine 2 (recipient). It is required to automate the following actions:
Let's start from the middle - with the introduction of the payload.
The packet into which we will inject (secret but not encrypted) bits consists of an IP header and a TCP header.
IPv4 header.
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 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
RFC 791 contains the following:
Identification: 16 bits An identifying value assigned by the sender to aid in assembling the fragments of a datagram.
The ID field is needed to collect ordered data fragments. Those. in the case of a single packet, this field is not used. So for our purposes, you can already use 2 bytes. It was established experimentally that the zero field ID is automatically filled with random values, probably this is also written somewhere.
Consider the TCP header.
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 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The Sequence Number field of the first connection packet is not fixed, because otherwise attackers might have known it ( RCF 793 ). And this is another 4 bytes.
Disclaimer: Yes, global variables are ugly and ayayay, but for small test programs, it seems to me acceptable.
The code in this section will be pure C and is oriented to linux systems, since they require fewer non-obvious steps to make the programs work (and no winpcap). All programs using raw sockets should be run from under the root.
Thanks to binarytides.com for parsed examples with sending packages , as well as a ready-made sniffer .
#include<stdio.h> //for printf #include<string.h> //memset #include<sys/socket.h> //for socket ofcourse #include<stdlib.h> //for exit(0); #include<errno.h> //For errno - the error number #include<netinet/tcp.h> //Provides declarations for tcp header #include<netinet/ip.h> //Provides declarations for ip header #include <unistd.h> // 96 (12 ) -, - struct pseudo_header { u_int32_t source_address; u_int32_t dest_address; u_int8_t placeholder; u_int8_t protocol; u_int16_t tcp_length; }; // - unsigned short csum(unsigned short *ptr,int nbytes) { register long sum; unsigned short oddbyte; register short answer; sum=0; while(nbytes>1) { sum+=*ptr++; nbytes-=2; } if(nbytes==1) { oddbyte=0; *((u_char*)&oddbyte)=*(u_char*)ptr; sum+=oddbyte; } sum = (sum>>16)+(sum & 0xffff); sum = sum + (sum>>16); answer=(short)~sum; return(answer); } int main (int argc, char* argv[]) { srand(time(NULL)); if (argc < 3) { puts("Enter source and destination ip"); return 1; } while (1) { puts("Enter payload:"); char payload[1024]; // fgets(payload, 1024, stdin); // int length = strlen(payload); // - if (length > 0 && payload[strlen (payload) - 1] == '\n') payload[strlen (payload) - 1] = '\0'; // if (!length) break; // int n = (length + 5)/6; int i; for (i = 0; i < n; ++i) { // usleep(10000); // RAW int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP); if(s == -1) { // // , - perror("Failed to create socket"); exit(1); } // char datagram[4096] , source_ip[32] , *pseudogram; // memset (datagram, 0, 4096); // IP struct iphdr *iph = (struct iphdr *) datagram; //TCP struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct iphdr)); struct sockaddr_in sin; struct pseudo_header psh; //some address resolution strcpy(source_ip , argv[1]); sin.sin_family = AF_INET; sin.sin_port = htons(80); sin.sin_addr.s_addr = inet_addr (argv[2]); // IP // 5 iph->ihl = 5; // IPv3 iph->version = 4; // iph->tos = 0; // iph->tot_len = sizeof (struct iphdr) + sizeof (struct tcphdr); // iph->id = (6*i < length ? payload[6*i] << 8 : 0) + (6*i + 1 < length ? payload[6*i + 1] : 0); // id == 0, , // , , // if (iph->id == 0) iph->id = 1; // => iph->frag_off = 0; // TTL iph->ttl = 64; // TCP iph->protocol = IPPROTO_TCP; // - iph->check = 0; // IP iph->saddr = inet_addr ( source_ip ); // IP iph->daddr = sin.sin_addr.s_addr; // IP iph->check = csum ((unsigned short *) datagram, iph->tot_len); // TCP // tcph->source = htons (20); // tcph->dest = htons (rand() % 10000); // "" tcph->ack_seq = 0; // tcph->seq = 0; int j; for (j = 0; j < 4; ++j) tcph->seq += (6*i + 2 + j < length ? payload[6*i + 2 + j] : 0) << 8*j; // tcph->doff = 5; // SYN tcph->fin=0; tcph->syn=1; tcph->rst=0; tcph->psh=0; tcph->ack=0; tcph->urg=0; // tcph->window = htons (5840); // - - tcph->check = 0; // "" tcph->urg_ptr = 0; // psh.source_address = inet_addr( source_ip ); psh.dest_address = sin.sin_addr.s_addr; psh.placeholder = 0; psh.protocol = IPPROTO_TCP; psh.tcp_length = 0; int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr); pseudogram = (char*)malloc(psize); memcpy(pseudogram , (char*) &psh , sizeof (struct pseudo_header)); memcpy(pseudogram + sizeof(struct pseudo_header) , tcph, sizeof(struct tcphdr)); tcph->check = csum( (unsigned short*) pseudogram , psize); free(pseudogram); //IP_HDRINCL , int one = 1; const int *val = &one; if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0) { perror("Error setting IP_HDRINCL"); exit(0); } // if (sendto (s, datagram, iph->tot_len , 0, (struct sockaddr *) &sin, sizeof (sin)) < 0) { perror("sendto failed"); } // else { // printf ("Packet sent. \"" ); for (j = 0; j < 6; ++j) if (6*i + j < length) printf("%c", payload[6*i + j]); puts("\""); } } } return 0; }
For convenience of verification, we will transmit messages entered from the keyboard.
// fgets(payload, 1024, stdin); // int length = strlen(payload);
There are 6 bytes in total, so the number of required packets is equal to the length divided by 6 and rounded down.
// int n = (length + 5)/6;
Further actions are performed n times.
Creating a TCP packet in raw mode.
int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);
Creating the necessary variables, filling in the fields.
// char datagram[4096] , source_ip[32] , *pseudogram; // memset (datagram, 0, 4096); // IP struct iphdr *iph = (struct iphdr *) datagram; //TCP struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct iphdr));
Implementation of the first part of the payload (2 bytes in the ID field).
iph->id = (6*i < length ? payload[6*i] << 8 : 0) + (6*i + 1 < length ? payload[6*i + 1] : 0);
Implementation of the second part of the payload (4 bytes in the Sequence Number field).
tcph->seq = 0; int j; for (j = 0; j < 4; ++j) tcph->seq += (6*i + 2 + j < length ? payload[6*i + 2 + j] : 0) << 8*j;
Sending a packet and outputting its payload.
if (sendto (s, datagram, iph->tot_len , 0, (struct sockaddr *) &sin, sizeof (sin)) < 0) { perror("sendto failed"); } // else { // printf ("Packet sent. \"" ); for (j = 0; j < 6; ++j) if (6*i + j < length) printf("%c", payload[6*i + j]); puts("\""); }
#include<stdio.h> //For standard things #include<stdlib.h> //malloc #include<string.h> //memset #include<netinet/ip_icmp.h> //Provides declarations for icmp header #include<netinet/udp.h> //Provides declarations for udp header #include<netinet/tcp.h> //Provides declarations for tcp header #include<netinet/ip.h> //Provides declarations for ip header #include<sys/socket.h> #include<arpa/inet.h> void processPacket(unsigned char*); void handleMessage(unsigned char*); int sock_raw; // char global_buffer[1024]; // int global_n = 0; char * src_addr, *dst_addr; int main(int argc, char* argv[]) { if (argc < 3) { puts("Enter source and destination ip"); return 1; } src_addr = argv[1]; dst_addr = argv[2]; int saddr_size , data_size; struct sockaddr saddr; unsigned char *buffer = (unsigned char *)malloc(65536); //Its Big! puts("Starting..."); // "" , sock_raw = socket(AF_INET , SOCK_RAW , IPPROTO_TCP); if(sock_raw < 0) { printf("Socket Error\n"); return 1; } while(1) { saddr_size = sizeof saddr; // data_size = recvfrom(sock_raw , buffer , 65536 , 0 , &saddr , &saddr_size); if(data_size <0 ) { printf("Recvfrom error , failed to get packets\n"); return 1; } // processPacket(buffer); } close(sock_raw); printf("Finished"); return 0; } void processPacket(unsigned char* buffer) { // IP struct iphdr *iph = (struct iphdr*)buffer; // TCP if (iph->protocol == IPPROTO_TCP) { // handleMessage(buffer); } } void handleMessage(unsigned char *Buffer) { int i; struct iphdr *iph = (struct iphdr *)Buffer; struct tcphdr *tcph = (struct tcphdr *) (Buffer + sizeof (struct iphdr)); struct sockaddr_in source,dest; // memset(&source, 0, sizeof(source)); source.sin_addr.s_addr = iph->saddr; memset(&dest, 0, sizeof(dest)); dest.sin_addr.s_addr = iph->daddr; // if (source.sin_addr.s_addr == inet_addr(src_addr) && dest.sin_addr.s_addr == inet_addr(dst_addr)) { // setvbuf (stdout, NULL, _IONBF, 0); // char payload[6]; // payload[0] = iph->id >> 8; payload[1] = iph->id & ((1 << 8) - 1); // for (i = 0; i < 4; ++i) { payload[i + 2] = (tcph->seq >> i*8) & ((1 << 8 ) - 1); } // for (i = 0; i < 6; ++i) { global_buffer[global_n++] = payload[i]; } // for (i = 0; i < 6; ++i) { // if (payload[i]) printf("%c", payload[i]); else { // 0 => // puts(""); // global_n = 0; // break; } } } }
In order not to load the code with unnecessary variable transfers, the message and its length will be controlled in global variables. At the current stage, it is not necessary to record a message, but why not take care of its storage in advance.
// char global_buffer[1024]; // int global_n = 0;
Create a raw socket for listening and get packets in an infinite loop, followed by a call to the packet processing function.
sock_raw = socket(AF_INET , SOCK_RAW , IPPROTO_TCP); // ... while(1) { // ... // recvfrom(sock_raw , buffer , 65536 , 0 , &saddr , &saddr_size); //... // processPacket(buffer); }
After checking that the TCP packet was received, and it is from the desired address, we extract both parts of the payload.
// ... char payload[6]; // payload[0] = iph->id >> 8; payload[1] = iph->id & ((1 << 8) - 1); // for (i = 0; i < 4; ++i) payload[i + 2] = (tcph->seq >> i*8) & ((1 << 8 ) - 1); // ...
(Recipient on the left, sender on the right)
The load is perfectly visible when analyzing a packet, for example, in Wireshark. So it would be nice to introduce encryption, but for Proof Of Consept we will not do this.
So, until now, we have repeated the success of Torakis from his first article , but using C, not Python. It's time for discrepancies.
I would like to transfer large data arrays in TCP packets, but this is inconvenient, since the steganographic data transfer rate is rather small. However, no one bothers to leave a message in a specified place, and this place can be either a site created specifically for today's experiment, or one of the existing ones .
Here things are somewhat more complicated than last time, because you have to supplement ready-made applications by loading pages via https and parsing them. Since we use a specific site, "parsing" will be simplified to find the right line in the page code and extract the code from there for reference by known adjacent characters.
First you need the curl library. By default, it sends the received web page to the console, so you need to make a buffer into which we want to write the source code of the page and the callback function corresponding to the curl API that produces the same record.
char html_buffer[65530]; size_t writeCallback(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; memcpy(html_buffer, contents, realsize); return realsize; }
#include<stdio.h> //for printf #include<string.h> //memset #include<sys/socket.h> //for socket ofcourse #include<stdlib.h> //for exit(0); #include<errno.h> //For errno - the error number #include<netinet/tcp.h> //Provides declarations for tcp header #include<netinet/ip.h> //Provides declarations for ip header #include <unistd.h> #include <curl/curl.h> // 96 (12 ) -, - struct pseudo_header { u_int32_t source_address; u_int32_t dest_address; u_int8_t placeholder; u_int8_t protocol; u_int16_t tcp_length; }; unsigned short csum(unsigned short *ptr,int nbytes); size_t writeCallback(void *contents, size_t size, size_t nmemb, void *userp); char * findMessage(); const char post_parameter[] = "message%5Bbody%5D="; char html_buffer[65530]; int main (int argc, char* argv[]) { srand(time(NULL)); if (argc < 3) { puts("Enter source and destination ip"); return 1; } while (1) { puts("Enter payload:"); // , POST- char post[65530]; memset(post, 0, sizeof(post)); memcpy(post, post_parameter, sizeof(post_parameter)*sizeof(char)); // fgets(post + sizeof(post_parameter) - 1, sizeof(post) - sizeof(post_parameter), stdin); // - post[strlen (post) - 1] = '\0'; puts(post); // curl CURL *curl; CURLcode res; // xurl curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if(curl) { // curl_easy_setopt(curl, CURLOPT_URL, "https://tmwsd.ws/messages"); // "test" curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post); // curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); // curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback); // res = curl_easy_perform(curl); // /* Check for errors */ if(res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); /* always cleanup */ curl_easy_cleanup(curl); } curl_global_cleanup(); char *link = findMessage(); puts("Link:"); puts(link); // int length = strlen(link); // - // if (!length) break; // int n = (length + 5)/6; int i; for (i = 0; i < n; ++i) { // usleep(10000); // RAW // AF_INTER == PF_INER - IP v4 int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP); if(s == -1) { // // , - perror("Failed to create socket"); exit(1); } // char datagram[4096] , source_ip[32] , *pseudogram; // memset (datagram, 0, 4096); // IP struct iphdr *iph = (struct iphdr *) datagram; //TCP struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct iphdr)); struct sockaddr_in sin; struct pseudo_header psh; //some address resolution strcpy(source_ip , argv[1]); sin.sin_family = AF_INET; sin.sin_port = htons(80); sin.sin_addr.s_addr = inet_addr (argv[2]); // IP // 5 iph->ihl = 5; // IPv3 iph->version = 4; // iph->tos = 0; // iph->tot_len = sizeof (struct iphdr) + sizeof (struct tcphdr); // iph->id = (6*i < length ? link[6*i] << 8 : 0) + (6*i + 1 < length ? link[6*i + 1] : 0); // id == 0, // , , // if (iph->id == 0) iph->id = 1; // => iph->frag_off = 0; // TTL iph->ttl = 64; // TCP iph->protocol = IPPROTO_TCP; // - iph->check = 0; // IP iph->saddr = inet_addr ( source_ip ); // IP iph->daddr = sin.sin_addr.s_addr; // IP iph->check = csum ((unsigned short *) datagram, iph->tot_len); // TCP // tcph->source = htons (20); // tcph->dest = htons (rand() % 10000); // "" tcph->ack_seq = 0; // tcph->seq = 0; int j; for (j = 0; j < 4; ++j) tcph->seq += (6*i + 2 + j < length ? link[6*i + 2 + j] : 0) << 8*j; // tcph->doff = 5; // SYN tcph->fin=0; tcph->syn=1; tcph->rst=0; tcph->psh=0; tcph->ack=0; tcph->urg=0; // tcph->window = htons (5840); // - - tcph->check = 0; // "" tcph->urg_ptr = 0; // psh.source_address = inet_addr( source_ip ); psh.dest_address = sin.sin_addr.s_addr; psh.placeholder = 0; psh.protocol = IPPROTO_TCP; psh.tcp_length = 0; int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr); pseudogram = (char*)malloc(psize); memcpy(pseudogram , (char*) &psh , sizeof (struct pseudo_header)); memcpy(pseudogram + sizeof(struct pseudo_header) , tcph, sizeof(struct tcphdr)); tcph->check = csum( (unsigned short*) pseudogram , psize); free(pseudogram); //IP_HDRINCL , int one = 1; const int *val = &one; if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0) { perror("Error setting IP_HDRINCL"); exit(0); } // if (sendto (s, datagram, iph->tot_len , 0, (struct sockaddr *) &sin, sizeof (sin)) < 0) { perror("sendto failed"); } // else { // printf ("Packet sent. \"" ); for (j = 0; j < 6; ++j) if (6*i + j < length) printf("%c", link[6*i + j]); puts("\""); } } free(link); } return 0; } // - unsigned short csum(unsigned short *ptr,int nbytes) { register long sum; unsigned short oddbyte; register short answer; sum=0; while(nbytes>1) { sum+=*ptr++; nbytes-=2; } if(nbytes==1) { oddbyte=0; *((u_char*)&oddbyte)=*(u_char*)ptr; sum+=oddbyte; } sum = (sum>>16)+(sum & 0xffff); sum = sum + (sum>>16); answer=(short)~sum; return(answer); } size_t writeCallback(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; memcpy(html_buffer, contents, realsize); return realsize; } char * findMessage() { // 75- size_t i, j = 0; for (i = 0; i < 74; ++i) { while (html_buffer[j++] != '\n'); } while (html_buffer[j++] != 'w'); int first, last; first = j+2; while (html_buffer[++j] != '<'); last = j; char * link = malloc(sizeof(char)*(last - first + 1)); memset(link, 0, last - first + 1); memcpy(link, html_buffer + first, last - first); return link; }
To create a message, you need to send to https://tmwsd.ws/messages (or any other of their domain names) a POST request with at least the message[body]
variable specified, which will be our message. As a result, the site will redirect to the page containing the one-link link.
An example of a page with a link.
We see the left message "test" and a warning that the message will be deleted.
If you try your luck again and follow the same link, you will not be able to see the message.
From the whole page, we are only interested in the address, i.e. in this case, https://⌫.ws/4Gn30zLh
, and since the domain name is agreed in advance; only the 4Gn30zLh
set is 4Gn30zLh
. In the source code of the page, it lies on line 75 in this form:
<span id="message_url_366056">https://⌫.ws/4Gn30zLh</span>
And the number 366056 is not fixed. So, you can first go to the 75th line, then go to the 'w' symbol, and starting from the offset from it by 2 to the right to the next angle bracket, get the message
char * findLink() { // 74 size_t i, j = 0; for (i = 0; i < 74; ++i) { while (html_buffer[j++] != '\n'); } while (html_buffer[j++] != 'w'); int first, last; first = j+2; while (html_buffer[++j] != '<'); last = j; char * msg = malloc(sizeof(char)*(last-first)); for (i = first; i < last; ++i) msg[i - first] = html_buffer[i]; return msg; }
The author does not understand the web What if you try to break the algorithm by sending the <
character? Nothing will happen, in the page source it will be in the form of html code <
.
// curl CURL *curl; CURLcode res; // curl curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if(curl) { // curl_easy_setopt(curl, CURLOPT_URL, "https://tmwsd.ws/messages"); // "test" curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "message%5Bbody%5D=test"); // curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); // curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); // res = curl_easy_perform(curl);
After parsing we get the work address.
It will be necessary to transmit it in TCP packets.
To begin with, we will assign a variable to the constant part of the POST request.
const char post_parameter[] = "message%5Bbody%5D=";
The constant part is copied to the array containing the POST request, and then the message is read with offset.
char post[65530]; memset(post, 0, sizeof(post)); memcpy(post, post_parameter, sizeof(post_parameter)*sizeof(char)); // fgets(post + sizeof(post_parameter) - 1, sizeof(post) - sizeof(post_parameter), stdin);
Next, the already known manipulations with curl and TCP packets are performed.
As a result, we can send any message using two packets.
We check the message on the link.
It remains to learn how to receive messages!
We are able to extract the load, we are able to load the html, and the message is on the 31st line.
All the nuances of a similar implementation were dismantled. In order not to read the same thing once again, I suggest that those wishing to familiarize themselves with the code, and the rest go to the "check connection".
#include<stdio.h> //for printf #include<string.h> //memset #include<sys/socket.h> //for socket ofcourse #include<stdlib.h> //for exit(0); #include<errno.h> //For errno - the error number #include<netinet/tcp.h> //Provides declarations for tcp header #include<netinet/ip.h> //Provides declarations for ip header #include <unistd.h> #include <curl/curl.h> // 96 (12 ) -, - struct pseudo_header { u_int32_t source_address; u_int32_t dest_address; u_int8_t placeholder; u_int8_t protocol; u_int16_t tcp_length; }; unsigned short csum(unsigned short *ptr,int nbytes); size_t writeCallback(void *contents, size_t size, size_t nmemb, void *userp); char * findMessage(); const char post_parameter[] = "message%5Bbody%5D="; char html_buffer[65530]; int main (int argc, char* argv[]) { srand(time(NULL)); if (argc < 3) { puts("Enter source and destination ip"); return 1; } while (1) { puts("Enter payload:"); // , POST- char post[65530]; memset(post, 0, sizeof(post)); memcpy(post, post_parameter, sizeof(post_parameter)*sizeof(char)); // fgets(post + sizeof(post_parameter) - 1, sizeof(post) - sizeof(post_parameter), stdin); // - post[strlen (post) - 1] = '\0'; puts(post); // curl CURL *curl; CURLcode res; // xurl curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if(curl) { // curl_easy_setopt(curl, CURLOPT_URL, "https://tmwsd.ws/messages"); // "test" curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post); // curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); // curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback); // res = curl_easy_perform(curl); // /* Check for errors */ if(res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); /* always cleanup */ curl_easy_cleanup(curl); } curl_global_cleanup(); char *link = findMessage(); puts("Link:"); puts(link); // int length = strlen(link); // - // if (!length) break; // int n = (length + 5)/6; int i; for (i = 0; i < n; ++i) { // usleep(10000); // RAW // AF_INTER == PF_INER - IP v4 int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP); if(s == -1) { // // , - perror("Failed to create socket"); exit(1); } // char datagram[4096] , source_ip[32] , *pseudogram; // memset (datagram, 0, 4096); // IP struct iphdr *iph = (struct iphdr *) datagram; //TCP struct tcphdr *tcph = (struct tcphdr *) (datagram + sizeof (struct iphdr)); struct sockaddr_in sin; struct pseudo_header psh; //some address resolution strcpy(source_ip , argv[1]); sin.sin_family = AF_INET; sin.sin_port = htons(80); sin.sin_addr.s_addr = inet_addr (argv[2]); // IP // 5 iph->ihl = 5; // IPv3 iph->version = 4; // iph->tos = 0; // iph->tot_len = sizeof (struct iphdr) + sizeof (struct tcphdr); // iph->id = (6*i < length ? link[6*i] << 8 : 0) + (6*i + 1 < length ? link[6*i + 1] : 0); // id == 0, // , , // if (iph->id == 0) iph->id = 1; // => iph->frag_off = 0; // TTL iph->ttl = 64; // TCP iph->protocol = IPPROTO_TCP; // - iph->check = 0; // IP iph->saddr = inet_addr ( source_ip ); // IP iph->daddr = sin.sin_addr.s_addr; // IP iph->check = csum ((unsigned short *) datagram, iph->tot_len); // TCP // tcph->source = htons (20); // tcph->dest = htons (rand() % 10000); // "" tcph->ack_seq = 0; // tcph->seq = 0; int j; for (j = 0; j < 4; ++j) tcph->seq += (6*i + 2 + j < length ? link[6*i + 2 + j] : 0) << 8*j; // tcph->doff = 5; // SYN tcph->fin=0; tcph->syn=1; tcph->rst=0; tcph->psh=0; tcph->ack=0; tcph->urg=0; // tcph->window = htons (5840); // - - tcph->check = 0; // "" tcph->urg_ptr = 0; // psh.source_address = inet_addr( source_ip ); psh.dest_address = sin.sin_addr.s_addr; psh.placeholder = 0; psh.protocol = IPPROTO_TCP; psh.tcp_length = 0; int psize = sizeof(struct pseudo_header) + sizeof(struct tcphdr); pseudogram = (char*)malloc(psize); memcpy(pseudogram , (char*) &psh , sizeof (struct pseudo_header)); memcpy(pseudogram + sizeof(struct pseudo_header) , tcph, sizeof(struct tcphdr)); tcph->check = csum( (unsigned short*) pseudogram , psize); free(pseudogram); //IP_HDRINCL , int one = 1; const int *val = &one; if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0) { perror("Error setting IP_HDRINCL"); exit(0); } // if (sendto (s, datagram, iph->tot_len , 0, (struct sockaddr *) &sin, sizeof (sin)) < 0) { perror("sendto failed"); } // else { // printf ("Packet sent. \"" ); for (j = 0; j < 6; ++j) if (6*i + j < length) printf("%c", link[6*i + j]); puts("\""); } } free(link); } return 0; } // - unsigned short csum(unsigned short *ptr,int nbytes) { register long sum; unsigned short oddbyte; register short answer; sum=0; while(nbytes>1) { sum+=*ptr++; nbytes-=2; } if(nbytes==1) { oddbyte=0; *((u_char*)&oddbyte)=*(u_char*)ptr; sum+=oddbyte; } sum = (sum>>16)+(sum & 0xffff); sum = sum + (sum>>16); answer=(short)~sum; return(answer); } size_t writeCallback(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; memcpy(html_buffer, contents, realsize); return realsize; } char * findMessage() { // 75- size_t i, j = 0; for (i = 0; i < 74; ++i) { while (html_buffer[j++] != '\n'); } while (html_buffer[j++] != 'w'); int first, last; first = j+2; while (html_buffer[++j] != '<'); last = j; char * link = malloc(sizeof(char)*(last - first + 1)); memset(link, 0, last - first + 1); memcpy(link, html_buffer + first, last - first); return link; }
, , , , .
Source: https://habr.com/ru/post/332962/
All Articles