From 4add2df8928d5fec040a5c38fc45223f6529e33c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20T=C3=B6rnblom?= Date: Mon, 12 Feb 2024 22:12:27 +0100 Subject: [PATCH] setup stdio for payloads --- bootstrap.c | 2 +- elfldr.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++-- elfldr.h | 4 +- pt.c | 18 +++++++ pt.h | 3 ++ socksrv.c | 18 +++---- 6 files changed, 179 insertions(+), 17 deletions(-) diff --git a/bootstrap.c b/bootstrap.c index 82fc4d5..136cca3 100644 --- a/bootstrap.c +++ b/bootstrap.c @@ -65,7 +65,7 @@ main() { return -1; } - ret = elfldr_exec(pid, socksrv_elf); + ret = elfldr_exec(pid, -1, socksrv_elf); // restore privileges if(kernel_set_proc_rootdir(pid, vnode)) { diff --git a/elfldr.c b/elfldr.c index d7e371a..b66b5af 100644 --- a/elfldr.c +++ b/elfldr.c @@ -28,6 +28,7 @@ along with this program; see the file COPYING. If not, see #include #include #include +#include #include #include @@ -286,6 +287,126 @@ elfldr_load(pid_t pid, uint8_t *elf) { } +/** + * Send a file descriptor to a process that listens on a UNIX domain socket + * with the given socket path. + **/ +static int +elfldr_sendfd(const char *sockpath, int fd) { + struct sockaddr_un addr = {0}; + struct msghdr msg = {0}; + struct cmsghdr *cmsg; + uint8_t buf[24]; + int sockfd; + + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, sockpath); + + memset(&msg, 0, sizeof(msg)); + msg.msg_name = &addr; + msg.msg_namelen = sizeof(struct sockaddr_un); + msg.msg_control = buf; + msg.msg_controllen = sizeof(buf); + + memset(buf, 0, sizeof(buf)); + cmsg = (struct cmsghdr *)buf; + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = 20; + *((int *)&buf[16]) = fd; + + if((sockfd=socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { + perror("[elfldr.elf] socket"); + return -1; + } + + if(sendmsg(sockfd, &msg, 0) < 0) { + perror("[elfldr.elf] sendmsg"); + close(sockfd); + return -1; + } + + return close(sockfd); +} + + +/** + * Pipe stdout of a process with the given pid to a file descriptor, where + * communication is done via a UNIX domain socket of the given socket path. + **/ +static int +elfldr_stdout(pid_t pid, const char *sockpath, int fd) { + struct sockaddr_un addr = {0}; + intptr_t ptbuf; + int sockfd; + + if((ptbuf=pt_mmap(pid, 0, PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)) == -1) { + pt_perror(pid, "[elfldr.elf] pt_mmap"); + return -1; + } + + if((sockfd=pt_socket(pid, AF_UNIX, SOCK_DGRAM, 0)) < 0) { + pt_perror(pid, "[elfldr.elf] pt_socket"); + pt_munmap(pid, ptbuf, PAGE_SIZE); + return -1; + } + + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, sockpath); + mdbg_copyin(pid, &addr, ptbuf, sizeof(addr)); + if(pt_bind(pid, sockfd, ptbuf, sizeof(addr))) { + pt_perror(pid, "[elfldr.elf] pt_bind"); + pt_munmap(pid, ptbuf, PAGE_SIZE); + pt_close(pid, sockfd); + return -1; + } + + if(elfldr_sendfd(sockpath, fd)) { + pt_munmap(pid, ptbuf, PAGE_SIZE); + pt_close(pid, sockfd); + return -1; + } + + intptr_t hdr = ptbuf; + intptr_t iov = ptbuf + 0x100; + intptr_t control = ptbuf + 0x200; + + mdbg_setlong(pid, hdr + __builtin_offsetof(struct msghdr, msg_name), 0); + mdbg_setint(pid, hdr + __builtin_offsetof(struct msghdr, msg_namelen), 0); + mdbg_setlong(pid, hdr + __builtin_offsetof(struct msghdr, msg_iov), iov); + mdbg_setint(pid, hdr + __builtin_offsetof(struct msghdr, msg_iovlen), 1); + mdbg_setlong(pid, hdr + __builtin_offsetof(struct msghdr, msg_control), control); + mdbg_setint(pid, hdr + __builtin_offsetof(struct msghdr, msg_controllen), 24); + if(pt_recvmsg(pid, sockfd, hdr, 0) < 0) { + pt_perror(pid, "[elfldr.elf] pt_recvmsg"); + pt_munmap(pid, ptbuf, PAGE_SIZE); + pt_close(pid, sockfd); + return -1; + } + + if((fd=pt_getint(pid, control+16)) < 0) { + pt_munmap(pid, ptbuf, PAGE_SIZE); + pt_close(pid, sockfd); + return -1; + } + + if(pt_munmap(pid, ptbuf, PAGE_SIZE)) { + pt_perror(pid, "[elfldr.elf] pt_munmap"); + pt_close(pid, sockfd); + pt_close(pid, fd); + } + + if(pt_close(pid, sockfd)) { + pt_perror(pid, "[elfldr.elf] pt_close"); + pt_close(pid, fd); + return -1; + } + + return fd; +} + + /** * Create payload args in the address space of the process with the given pid. **/ @@ -460,7 +581,9 @@ elfldr_set_procname(pid_t pid, const char* name) { * Execute an ELF inside the process with the given pid. **/ int -elfldr_exec(pid_t pid, uint8_t* elf) { +elfldr_exec(pid_t pid, int stdio, uint8_t* elf) { + char path[PATH_MAX]; + if(elfldr_raise_privileges(pid)) { puts("[elfldr.elf] Unable to raise privileges"); kill(pid, SIGKILL); @@ -468,6 +591,26 @@ elfldr_exec(pid_t pid, uint8_t* elf) { return -1; } + if(stdio > 0) { + sprintf(path, "/system_tmp/elfldr.%d.sock", pid); + stdio = elfldr_stdout(pid, path, stdio); + unlink(path); + + if(stdio < 0) { + puts("[elfldr.elf] elfldr_stdout() failed"); + kill(pid, SIGKILL); + pt_detach(pid); + return -1; + } + + pt_close(pid, STDERR_FILENO); + pt_close(pid, STDOUT_FILENO); + + pt_dup2(pid, stdio, STDOUT_FILENO); + pt_dup2(pid, stdio, STDERR_FILENO); + pt_close(pid, stdio); + } + if(elfldr_prepare_exec(pid, elf)) { kill(pid, SIGKILL); pt_detach(pid); @@ -488,7 +631,7 @@ elfldr_exec(pid_t pid, uint8_t* elf) { * Execute an ELF inside a new process. **/ pid_t -elfldr_spawn(uint8_t* elf) { +elfldr_spawn(int stdio, uint8_t* elf) { char* argv[] = {"homebrew", 0}; uint8_t int3instr = 0xcc; struct kevent evt; @@ -556,6 +699,7 @@ elfldr_spawn(uint8_t* elf) { pt_detach(pid); return -1; } + if(mdbg_copyout(pid, brkpoint, &orginstr, sizeof(orginstr))) { perror("[elfldr.elf] mdbg_copyout"); kill(pid, SIGKILL); @@ -591,7 +735,7 @@ elfldr_spawn(uint8_t* elf) { // Execute the ELF elfldr_set_procname(pid, "homebrew"); - if(elfldr_exec(pid, elf)) { + if(elfldr_exec(pid, stdio, elf)) { perror("[elfldr.elf] pt_detach"); kill(pid, SIGKILL); pt_detach(pid); @@ -624,6 +768,7 @@ elfldr_find_pid(const char* name) { if(sysctl(mib, 4, buf, &buf_size, 0, 0)) { perror("[elfldr.elf] sysctl"); + free(buf); return -1; } diff --git a/elfldr.h b/elfldr.h index 4c0b258..a1a6881 100644 --- a/elfldr.h +++ b/elfldr.h @@ -19,6 +19,6 @@ along with this program; see the file COPYING. If not, see #include pid_t elfldr_find_pid(const char* name); -pid_t elfldr_spawn(uint8_t *elf); -int elfldr_exec(pid_t pid, uint8_t* elf); +pid_t elfldr_spawn(int stdio, uint8_t *elf); +int elfldr_exec(pid_t pid, int stdio, uint8_t* elf); diff --git a/pt.c b/pt.c index 5acad5c..a94c6c1 100644 --- a/pt.c +++ b/pt.c @@ -294,6 +294,24 @@ pt_close(pid_t pid, int fd) { } +int +pt_bind(pid_t pid, int sockfd, intptr_t addr, uint32_t addrlen) { + return (int)pt_syscall(pid, SYS_bind, sockfd, addr, addrlen); +} + + +ssize_t +pt_recvmsg(pid_t pid, int fd, intptr_t msg, int flags) { + return (int)pt_syscall(pid, SYS_recvmsg, fd, msg, flags); +} + + +int +pt_dup2(pid_t pid, int oldfd, int newfd) { + return (int)pt_syscall(pid, SYS_dup2, oldfd, newfd); +} + + int pt_pipe(pid_t pid, intptr_t pipefd) { intptr_t faddr = pt_resolve(pid, "-Jp7F+pXxNg"); diff --git a/pt.h b/pt.h index 138c102..099f8f6 100644 --- a/pt.h +++ b/pt.h @@ -45,8 +45,11 @@ int pt_mprotect(pid_t pid, intptr_t addr, size_t len, int prot); int pt_socket(pid_t pid, int domain, int type, int protocol); int pt_setsockopt(pid_t pid, int fd, int level, int optname, intptr_t optval, uint32_t optlen); +int pt_bind(pid_t pid, int sockfd, intptr_t addr, uint32_t addrlen) ; +ssize_t pt_recvmsg(pid_t pid, int fd, intptr_t msg, int flags); int pt_close(pid_t pid, int fd); +int pt_dup2(pid_t pid, int oldfd, int newfd); int pt_pipe(pid_t pid, intptr_t pipefd); void pt_perror(pid_t pid, const char *s); diff --git a/socksrv.c b/socksrv.c index 186bb72..fdabed2 100644 --- a/socksrv.c +++ b/socksrv.c @@ -73,25 +73,20 @@ readsock(int fd) { /** * Process connections in induvidual threads. **/ -static void* -serve_thread(void* args) { - int fd = (int)(long)args; +static void +on_connection(int fd) { uint8_t* elf; if(!(elf=readsock(fd))) { - close(fd); - return 0; + return; } // Check for the ELF magic header if(!memcmp(elf, "\x7f\x45\x4c\x46", 4)) { - elfldr_spawn(elf); + elfldr_spawn(fd, elf); } free(elf); - close(fd); - - return 0; } @@ -106,7 +101,6 @@ serve_elfldr(uint16_t port) { struct ifaddrs *ifaddr; int ifaddr_wait = 1; socklen_t socklen; - pthread_t trd; int connfd; int srvfd; @@ -179,7 +173,9 @@ serve_elfldr(uint16_t port) { perror("[elfldr.elf] accept"); break; } - pthread_create(&trd, NULL, serve_thread, (void*)(long)connfd); + + on_connection(connfd); + close(connfd); } return close(srvfd);