Browse Source

fully functional video/webm replacement, fixed bug in upstream header decryption

cecylia 5 years ago
parent
commit
3dfaa4500e

+ 1 - 0
relay_station/flow.c

@@ -186,6 +186,7 @@ flow *add_flow(struct packet_info *info) {
     new_flow->httpstate = PARSE_HEADER;
     new_flow->webmstate = 0;
     new_flow->remaining_element = 0;
+    new_flow->element_header = 0;
     new_flow->replace_response = 0;
 
     new_flow->ecdh = NULL;

+ 5 - 2
relay_station/flow.h

@@ -164,11 +164,14 @@ typedef struct flow_st {
     //for downstream processing
     uint32_t remaining_record_len;
     uint8_t httpstate;
-    uint8_t webmstate;
-    uint64_t remaining_element;
     uint32_t remaining_response_len;
     uint8_t replace_response;
 
+    //webm state machine
+    uint8_t webmstate;
+    uint64_t remaining_element;
+    uint32_t element_header;
+
     uint8_t *outbox;
     int32_t outbox_len;
     int32_t outbox_offset;

+ 15 - 11
relay_station/relay.c

@@ -93,7 +93,6 @@ typedef struct stream_table_st {
 
 static int process_downstream(flow *f, int32_t offset, struct packet_info *info);
 static int read_header(flow *f, struct packet_info *info);
-static int fill_with_downstream(flow *f, uint8_t *data, int32_t length);
 static void *proxy_covert_site(void *data);
 
 /** Called when a TLS application record is received for a
@@ -243,7 +242,7 @@ static int read_header(flow *f, struct packet_info *info){
                 last->next = new_block;
             }
 
-            f->upstream_remaining = record_length - new_block->len;
+            f->upstream_remaining = record_length + RECORD_HEADER_LEN - new_block->len;
             return 0;
         }
     }
@@ -270,7 +269,9 @@ static int read_header(flow *f, struct packet_info *info){
     }
 
     DEBUG_MSG(DEBUG_UP, "Upstream data: (%x:%d > %x:%d )\n",info->ip_hdr->src.s_addr,ntohs(info->tcp_hdr->src_port), info->ip_hdr->dst.s_addr, ntohs(info->tcp_hdr->dst_port));
-    DEBUG_MSG(DEBUG_UP, "%s\n", decrypted_data+EVP_GCM_TLS_EXPLICIT_IV_LEN);
+    DEBUG_MSG(DEBUG_UP, "Data for flow %p:\n%s\n", f, decrypted_data+EVP_GCM_TLS_EXPLICIT_IV_LEN);
+    DEBUG_MSG(DEBUG_UP, "Bytes for flow %p (%d bytes):\n", f, decrypted_len);
+    DEBUG_BYTES(DEBUG_UP, (decrypted_data + EVP_GCM_TLS_EXPLICIT_IV_LEN), decrypted_len);
 
     /* search through decrypted data for x-ignore */
     char *header_ptr = strstr((const char *) decrypted_data+EVP_GCM_TLS_EXPLICIT_IV_LEN, "X-Slitheen");
@@ -1015,8 +1016,8 @@ static int process_downstream(flow *f, int32_t offset, struct packet_info *info)
                         len_ptr = strstr((const char *) p, "Content-Type: video/webm");
                         if(len_ptr != NULL){
                             printf("Found webm resource!\n");
-                            f->replace_response = 1;
-                            f->webmstate = BEGIN_ELEMENT;
+                            f->replace_response = 0;
+                            f->webmstate = WEBM_HEADER;
                             //memcpy(len_ptr + 14, "sli/theenv", 10);
 
                             char *c = len_ptr + 14+10;
@@ -1028,8 +1029,8 @@ static int process_downstream(flow *f, int32_t offset, struct packet_info *info)
                             len_ptr = strstr((const char *) p, "Content-Type: hfjdkahfk"); //audio/webm");
                             if(len_ptr != NULL){
                                 printf("Found webm resource!\n");
-                                f->replace_response = 1;
-                                f->webmstate = BEGIN_ELEMENT;
+                                f->replace_response = 0;
+                                f->webmstate = WEBM_HEADER;
                                 //memcpy(len_ptr + 14, "sli/theena", 10);
 
                                 char *c = len_ptr + 14+10;
@@ -1127,7 +1128,10 @@ static int process_downstream(flow *f, int32_t offset, struct packet_info *info)
                     //check if content is replaceable
                     if(f->remaining_response_len > remaining_record_len){
                         if (f->webmstate) {
-                            //parse_webm(f, p, remaining_record_len);
+                            parse_webm(f, p, remaining_record_len);
+                            if(f->remaining_response_len - remaining_record_len == 0){
+                                fprintf(stderr, "quitting\n");
+                            }
                         }
 
                         if(f->replace_response){
@@ -1143,7 +1147,7 @@ static int process_downstream(flow *f, int32_t offset, struct packet_info *info)
                         remaining_record_len = 0;
                     } else {
                         if (f->webmstate) {
-                            //parse_webm(f, p, f->remaining_response_len);
+                            parse_webm(f, p, f->remaining_response_len);
                         }
 
                         if(f->replace_response){
@@ -1248,7 +1252,7 @@ static int process_downstream(flow *f, int32_t offset, struct packet_info *info)
             }
         }
 
-        if(changed && f->replace_response){
+        if(changed && (f->replace_response || f->webmstate)){
             DEBUG_MSG(DEBUG_DOWN, "Resource is now:\n");
             DEBUG_BYTES(DEBUG_DOWN, (record_ptr + EVP_GCM_TLS_EXPLICIT_IV_LEN), n);
             DEBUG_MSG(DEBUG_DOWN, "Text:\n%s\n", record_ptr+EVP_GCM_TLS_EXPLICIT_IV_LEN);
@@ -1354,7 +1358,7 @@ static int process_downstream(flow *f, int32_t offset, struct packet_info *info)
  *  	length: The length of the downstream data required
  *
  */
-static int fill_with_downstream(flow *f, uint8_t *data, int32_t length){
+int fill_with_downstream(flow *f, uint8_t *data, int32_t length){
 
     uint8_t *p = data;
     int32_t remaining = length;

+ 1 - 0
relay_station/relay.h

@@ -54,6 +54,7 @@ extern client_table *clients;
 int replace_packet(flow *f, struct packet_info *info);
 uint16_t tcp_checksum(struct packet_info *info);
 
+int fill_with_downstream(flow *f, uint8_t *data, int32_t length);
 #define BEGIN_HEADER 0x10
 #define PARSE_HEADER 0x20
 #define MID_CONTENT 0x30

+ 3 - 3
relay_station/tests/Makefile

@@ -7,13 +7,13 @@ all: $(TARGETS)
 
 test_util.o: test_util.h
 
-check_tagged: check_tagged.c test_util.o ../flow.c ../crypto.o ../relay.o ../cryptothread.o ../ptwist168.o ../packet.o ../util.o ../flow.h ../crypto.h ../relay.h ../cryptothread.h ../ptwist.h ../packet.h ../util.h
+check_tagged: check_tagged.c test_util.o ../flow.c ../crypto.o ../relay.o ../cryptothread.o ../ptwist168.o ../packet.o ../util.o ../webm.o ../flow.h ../crypto.h ../relay.h ../cryptothread.h ../ptwist.h ../packet.h ../util.h ../webm.h
 	gcc -g -ggdb -o $@ $^ -L/usr/local/lib -I/usr/local/include -lssl -lcrypto -ldl -lpthread -lpcap -lcheck_pic -lrt -lm -lsubunit
 
-check_handshake: check_handshake.c test_util.o ../flow.c ../crypto.o ../relay.o ../cryptothread.o ../ptwist168.o ../packet.o ../util.o ../flow.h ../crypto.h ../relay.h ../cryptothread.h ../ptwist.h ../packet.h ../util.h
+check_handshake: check_handshake.c test_util.o ../flow.c ../crypto.o ../relay.o ../cryptothread.o ../ptwist168.o ../packet.o ../util.o ../webm.o ../flow.h ../crypto.h ../relay.h ../cryptothread.h ../ptwist.h ../packet.h ../util.h ../webm.h
 	gcc -g -ggdb -o $@ $^ -L/usr/local/lib -I/usr/local/include -lssl -lcrypto -ldl -lpthread -lpcap -lcheck_pic -lrt -lm -lsubunit
 
-test_partial_aes: test_partial_aes.c test_util.o ../flow.c ../crypto.o ../relay.o ../cryptothread.o ../ptwist168.o ../packet.o ../util.o ../flow.h ../crypto.h ../relay.h ../cryptothread.h ../ptwist.h ../packet.h ../util.h
+test_partial_aes: test_partial_aes.c test_util.o ../flow.c ../crypto.o ../relay.o ../cryptothread.o ../ptwist168.o ../packet.o ../util.o ../webm.o ../flow.h ../crypto.h ../relay.h ../cryptothread.h ../ptwist.h ../packet.h ../util.h ../webm.h
 	gcc -g -ggdb -o $@ $^ -L/usr/local/lib -I/usr/local/include -lssl -lcrypto -ldl -lpthread -lpcap -lcheck_pic -lrt -lm -lsubunit
 
 test_webm: test_webm.c test_util.o ../flow.o ../crypto.o ../relay.o ../cryptothread.o ../ptwist168.o ../packet.o ../util.o ../flow.h ../crypto.h ../relay.h ../cryptothread.h ../ptwist.h ../packet.h ../util.h

+ 8 - 14
relay_station/tests/test_webm.c

@@ -59,7 +59,7 @@ START_TEST(webm_parser) {
     flow *f = smalloc(sizeof(flow));
 
     //we only need to set the webmstate and remaining_element fields of the flow
-    f->webmstate = BEGIN_ELEMENT;
+    f->webmstate = WEBM_HEADER;
     f->remaining_element = 0;
 
     uint8_t *data;
@@ -87,7 +87,7 @@ START_TEST(webm_parser) {
 
     ck_assert_int_eq(f->remaining_element, 0);
 
-    ck_assert_int_eq(f->webmstate, BEGIN_ELEMENT);
+    ck_assert_int_eq(f->webmstate, WEBM_HEADER);
 
     p+= 28;
     file_len -= 28;
@@ -95,13 +95,13 @@ START_TEST(webm_parser) {
     //Now parse segment header
     parse_webm(f, p, 16);
 
-    ck_assert_int_eq(f->webmstate, MID_ELEMENT);
+    //ck_assert_int_eq(f->webmstate, MID_ELEMENT);
 
     p+= 16;
     file_len -= 16;
 
     parse_webm(f, p, 185);
-    ck_assert_int_eq(f->webmstate, BEGIN_ELEMENT);
+    ck_assert_int_eq(f->webmstate, WEBM_HEADER);
 
     //Detect cluster element ID
     p += 185;
@@ -113,19 +113,13 @@ START_TEST(webm_parser) {
     ck_assert_int_eq(p[3], 0x75);
 
     //Parse into media element
-    parse_webm(f, p, 8);
-
-    //make sure it was changed to slitheen ID
-    ck_assert_int_eq(p[0], 0x16);
-    ck_assert_int_eq(p[1], 0x73);
-    ck_assert_int_eq(p[2], 0x6c);
-    ck_assert_int_eq(p[3], 0x69);
+    //parse_webm(f, p, 8);
 
-    ck_assert_int_eq(f->webmstate, MEDIA);
+    //ck_assert_int_eq(f->webmstate, MEDIA);
 
     //parse to end of file
-    p += 8;
-    file_len -= 8;
+    //p += 8;
+    //file_len -= 8;
 
     parse_webm(f, p, file_len);
 

+ 64 - 58
relay_station/webm.c

@@ -34,6 +34,7 @@
 
 #include "webm.h"
 #include "flow.h"
+#include "relay.h"
 
 static uint64_t variable_length(uint8_t *p, uint8_t *int_length);
 static uint32_t variable_header(uint8_t *p, uint8_t *int_length);
@@ -55,97 +56,102 @@ int32_t parse_webm(flow *f, uint8_t *ptr, uint32_t len) {
 
     while (remaining_len){
         switch (f->webmstate){
-            case BEGIN_ELEMENT:
+            uint8_t header_len, int_len;
+            case WEBM_HEADER:
                 if(remaining_len < 8){
+                    //TODO:right now this assumes we'll have the header + size
+                    // but later we should make it work with just the header
+                    // also the size should be 8 bytes max
                     //this will be difficult to parse
-                    //TODO: make this easier to deal with
                     printf("PARSE FAIL: too little len remaining\n");
                     return 1;
                 }
 
-                //The only elements we care about are:
-                //  the segment header (0x18538067), and
-                //  the cluster header (0x1f43b675).
-
                 //Parse header:
-                uint8_t header_len;
-                uint32_t header = variable_header(p, &header_len);
-
-                printf("Received header: %x\n", header);
-
-                if (header == 0x18538067) {
-                    // do nothing. Move on to parsing sub-element
-
-                } else if (header == 0x1f43b675) {
-                    f->webmstate = MEDIA;
-
-                    //replace with slitheen header
-                    p[0] = 0x16; //'SYN'
-                    p[1] = 0x73; //'s'
-                    p[2] = 0x6c; //'l'
-                    p[3] = 0x69; //'i'
+                f->element_header = variable_header(p, &header_len);
 
-                    printf("Replaced cluster with slitheen segment!\n");
+                printf("Received header: %x\n", f->element_header);
 
-                } else {
-                    //we want to skip this element
-                    f->webmstate = MID_ELEMENT;
+                if(f->element_header == 0xa3){
+                    //we want to replace this block
+                    printf("Replaced simple block!\n");
+                    p[0] = 0xef;
                 }
 
                 p += header_len;
                 remaining_len -= header_len;
 
                 //parse length of header
-                uint8_t int_len;
-                uint64_t element_len = variable_length(p, &int_len);
+                f->remaining_element = variable_length(p, &int_len);
 
                 p += int_len;
                 remaining_len -= int_len;
 
-                printf("element length: %lu\n", element_len);
+                printf("element length: %lu\n", f->remaining_element);
 
-                f->remaining_element = element_len;
+                f->webmstate = PARSE_ELEMENT;
 
                 break;
-            case MID_ELEMENT:
-                //The initial sequence of bytes contains everything up to the media
-                //segments
+            case PARSE_ELEMENT:
 
-                if(f->remaining_element <= remaining_len){
-                    //we have the entire element in this packet
+                switch(f->element_header) {
 
-                    p += f->remaining_element;
-                    remaining_len -= f->remaining_element;
+                    case  0x18538067: //segment
+                    case 0x1f43b675: //cluster
+                    // do nothing. Move on to parsing sub-element
+                    f->webmstate = WEBM_HEADER;
 
-                    f->remaining_element = 0;
-                    f->webmstate = BEGIN_ELEMENT;
-                } else {
-                    //still have more of this element to process
+                    break;
+                    case 0xa3: //simple block
 
-                    p += remaining_len;
-                    f->remaining_element -= remaining_len;
-                    remaining_len = 0;
-                }
+                    f->webmstate = BLOCK_HEADER;
+
+                    break;
+                    default:
+                    //we want to skip this element
+                    f->webmstate = MID_ELEMENT;
+                    break;
 
+                }
                 break;
-            case MEDIA:
-                //We're replacing all of this element
+            case MID_ELEMENT: {
 
-                if(f->remaining_element <= remaining_len){
-                    //we have the entire element in this packet
+                uint32_t parse_len = (f->remaining_element <= remaining_len) ?
+                    f->remaining_element : remaining_len;
 
-                    p += f->remaining_element;
-                    remaining_len -= f->remaining_element;
+                if (f->element_header == 0xa3) {
+                    //replace content
+                    printf("Replaceable data (%d bytes):\n", parse_len);
+                    for(int i=0; i< parse_len; i++){
+                        printf("%02x ", p[i]);
+                    }
+                    printf("\n");
 
-                    f->remaining_element = 0;
-                    f->webmstate = BEGIN_ELEMENT;
-                } else {
-                    //still have more of this element to process
+                    fill_with_downstream(f, p, parse_len);
+                }
+
+                p += parse_len;
+                remaining_len -= parse_len;
+                f->remaining_element -= parse_len;
 
-                    p += remaining_len;
-                    f->remaining_element -= remaining_len;
-                    remaining_len = 0;
+                if (f->remaining_element == 0) {
+                    f->webmstate = WEBM_HEADER;
                 }
+                break;
+            }
+            case BLOCK_HEADER:
+                //TODO: expand to handle lacing, non-simple blocks
+                if(remaining_len < 4){
+                    //TODO: fix this somehow
+                    printf("PARSE FAIL: too little len remaining\n");
+                    return 1;
+                }
+
+                p += 4;
+                f->remaining_element -= 4;
+                remaining_len -= 4;
+
+                f->webmstate = MID_ELEMENT;
 
                 break;
         }

+ 4 - 3
relay_station/webm.h

@@ -33,9 +33,10 @@ int32_t parse_webm(flow *f, uint8_t *ptr, uint32_t len);
 
 /* WebM states */
 
-#define BEGIN_ELEMENT 0x01
-#define MID_ELEMENT 0x02
-#define MEDIA 0x03
+#define WEBM_HEADER 0x01
+#define PARSE_ELEMENT 0x02
+#define MID_ELEMENT 0x03
+#define BLOCK_HEADER 0x04
 
 #endif /* WEBM_H */