TCP ステガノグラフィは根本的に新しいものではありません。たとえば、 John Thorakisは2016年にPythonに非常に 興味深い ものを実装しました。それらのすべてがパブリックドメインにあるわけではないのは残念です。 Thorakisによる記事執筆時点では、根本的に新しいものではありませんでした。 これは、純粋なCで書かれ、かなり微調整された、アイデアと、たとえば遠い(または多分そうでない)1996年のCovert_TCPプログラムを説明する2009Habréの投稿です。
コバートTCPがTCPパケットで1バイトのペイロードを転送することを提案した場合、ソラキスはパケットごとに2〜6バイトを使用し、プロトコルにプロトコルを作成するというアイデアを提案しました。 しかし、この方法でも、大量のデータを転送することは困難です。
ここでは、ワンタイムメッセージシステムが助けになります。 実際、2つのアプローチは私たちの前で発明されたので、組み合わせてみませんか?
したがって、キャラクターはマシン1(送信者)とマシン2(受信者)です。 次のアクションを自動化する必要があります。
- ワンタイムURLを使用してリソース上でマシン1メッセージから作成し、リンク(たとえば、 ワンタイムシークレット )を取得します。
- リンクをTCP / IPパケットのペイロードとして渡します。
- マシン2のサイトからメッセージを読み取り、それに対していくつかのアクションを実行します。
ペイロードの導入から始めましょう。
TCP / IPステガノグラフィー
埋め込まれる(暗号化されていないが暗号化された)ビットを埋め込むパケットは、IPヘッダーとTCPヘッダーで構成されます。
IPv4ヘッダー。
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には次が含まれています。
Identification: 16 bits An identifying value assigned by the sender to aid in assembling the fragments of a datagram.
IDフィールドは、順序付けられたデータを収集するために必要です。 すなわち 単一のパッケージの場合、このフィールドは使用されません。 したがって、ここでは2バイトを使用することはすでに可能です。 null IDフィールドにはランダムな値が自動的に入力されることが実験的に確立されました。おそらくこれもどこかに書き込まれます。
TCPヘッダーを考慮してください。
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 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
最初の接続パケットのシーケンス番号フィールドは固定されていません。それ以外の場合、攻撃者に知られているためです( RCF 793 )。 そして、これはさらに4バイトです。
実装
免責事項:はい、グローバル変数はくて賛成ですが、小規模なテストプログラムの場合、受け入れられるようです。
このセクションのコードは純粋なCであり、Linuxシステム向けです。 プログラムを機能させるために、明白でない手順が少なくて済みます(winpcapは不要です)。 rawソケットを使用するすべてのプログラムは、ルート内から実行する必要があります。
パッケージを送信する例と、 既製のスニファー を提供してくれたbinarytides.comに感謝します 。
送信者
#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; }
便宜上、キーボードから入力されたメッセージを送信します。
// fgets(payload, 1024, stdin); // int length = strlen(payload);
合計6バイトであるため、必要なパケット数は、長さを6で割った値に等しく、大きい方に丸められます。
// int n = (length + 5)/6;
さらにアクションがn回実行されます。
rawモードでTCPパケットを作成します。
int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);
必要な変数を作成し、フィールドに入力します。
// 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));
ペイロードの最初の部分の実装(IDフィールドに2バイト)。
iph->id = (6*i < length ? payload[6*i] << 8 : 0) + (6*i + 1 < length ? payload[6*i + 1] : 0);
ペイロードの2番目の部分の実装(シーケンス番号フィールドに4バイト)。
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;
パケットを送信し、ペイロードを出力します。
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; } } } }
変数の余分な転送でコードに負担をかけないように、メッセージとその長さはグローバル変数で制御されます。 現在の段階では、メッセージを録音する必要はありませんが、事前にメッセージを保存することに注意してください。
// char global_buffer[1024]; // int global_n = 0;
パケットをリッスンするための生のソケットを作成し、無限ループでパケットを受信し、その後にパケット処理関数を呼び出します。
sock_raw = socket(AF_INET , SOCK_RAW , IPPROTO_TCP); // ... while(1) { // ... // recvfrom(sock_raw , buffer , 65536 , 0 , &saddr , &saddr_size); //... // processPacket(buffer); }
正しいアドレスから受信したのがTCPパケットであることを確認した後、ペイロードの両方の部分を抽出します。
// ... 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); // ...
作業例
(左側に受信者、右側に送信者)
Wiresharkなどでパッケージを分析すると、負荷がはっきりと見えます。 したがって、暗号化を導入するのは良いことですが、Proof Of Conseptについてはこれを行いません。
したがって、これまでのところ、Thorakisの最初の記事から成功を繰り返しましたが、PythonではなくCを使用しました。 不一致の時が来ました。
ワンタイムメッセージングシステム
TCPパケットで大量のデータを転送したいのですが、ステガノグラフィのデータ転送速度が非常に遅いため、これは不便です。 ただし、合意された場所にメッセージを残そうとする人はいません。そのような場所は、今日の実験用に特別に作成されたサイトでも、 既存のサイトでも構いません。
実装
ここでは、前回よりもやや複雑になっています。これは、https経由でページを読み込んで解析することで完成したアプリケーションを補完する必要があるためです。 なぜなら 特定のサイトを使用する場合、ページコードで目的の行を見つけ、そこから既知の隣接文字を使用してリンクのコードを抽出することにより、「解析」が簡素化されます。
最初にcurlライブラリが必要です。 デフォルトでは、受信したWebページをコンソールに送信するため、ページのソースコードと同じレコードを生成するcurl APIに対応するコールバック関数を書き込むバッファーを作成する必要があります。
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; }
メッセージを作成するには、少なくとも変数message[body]
を含むhttps://tmwsd.ws/messages (またはその他のドメイン名)POSTリクエストを送信する必要があります。これはメッセージになります。 その結果、サイトはワンクリックリンクを含むページにリダイレクトされます。
リンク付きのサンプルページ。
左のメッセージ「test」と、メッセージが削除されるという警告が表示されます。
運をもう一度試して同じリンクをたどると、メッセージは表示されません。
ページ全体から、アドレスにのみ興味があります。 この場合https://⌫.ws/4Gn30zLh
、なぜなら ドメイン名は事前に合意されており、 4Gn30zLh
セットのみが4Gn30zLh
。 ページのソースコードでは、次の形式で75行目にあります。
<span id="message_url_366056">https://⌫.ws/4Gn30zLh</span>
さらに、番号366056は固定されていません。 したがって、最初に75行目に移動し、次に「w」文字に移動し、それから2から右へ次の山括弧に移動して、メッセージを取得できます。
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; }
著者はウェブに精通していない <
文字を送信してアルゴリズムを破ろうとするとどうなりますか? しかし、何も起こりません。ページのソーステキストでは、htmlコードの形式になります<
。
接続確認
// 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);
解析後、勤務先住所を取得します。
TCPパケットで送信する必要があります。
まとめる
まず、変数をPOSTリクエストの定数部分に取りましょう。
const char post_parameter[] = "message%5Bbody%5D=";
定数部分は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);
次に、curlおよびTCPパケットを使用した既知の操作が実行されます。
その結果、2つのパケットを使用して任意のメッセージを送信できます。
リンク上のメッセージを確認してください。
メッセージを受信する方法を学ぶことは残っています!
受取人
ロードを抽出する方法、htmlをロードする方法、そしてメッセージは31行目にあります。
再度収集する
同様の実装のニュアンスはすべて分解されました。 もう一度同じことを読まないために、コードに慣れたいと思う人はお勧めし、残りは「接続の確認」に進みます。
#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; }
, , , , .