setup stdio for payloads

This commit is contained in:
John Törnblom committed 2024-02-12 22:12:27 +01:00
1 parent 897a79e53c
commit 4add2df892
6 files changed
+179 -17

No files matched your search

+1 -1
View File
@@ -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)) {
+148 -3
View File
@@ -28,6 +28,7 @@ along with this program; see the file COPYING. If not, see
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/sysctl.h>
#include <sys/un.h>
#include <sys/user.h>
#include <sys/wait.h>
@@ -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;
}
+2 -2
View File
@@ -19,6 +19,6 @@ along with this program; see the file COPYING. If not, see
#include <unistd.h>
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);
+18
View File
@@ -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");
+3
View File
@@ -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);
+7 -11
View File
@@ -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);