DragonFlyBSD Kernel Audit
DF-0871 / craft_benign.py
← back to finding ↓ download raw
#!/usr/bin/env python3
"""Build a BENIGN NTFS image: well-formed $AttrDef with short NUL-terminated
names so the do/while at ntfs_vfsops.c:458-460 stops at j<64 (no overflow).
Used as the negative control for DF-0871 causation.  Reuses craft_img.py's
builder; only swaps in a benign attrdef data stream."""
import sys, struct
sys.path.insert(0, sys.path[0])
import craft_img as C

A_STD = 0x10

def benign_attrdef_records():
    """Two well-formed 160-byte attrdef records (short names) + terminator."""
    out = bytearray()
    for name, atype in [("$STANDARD_INFORMATION", A_STD), ("$FILE_NAME", 0x30)]:
        e = bytearray(C.ATTRDEF_RECSZ)
        for i, ch in enumerate(name):
            struct.pack_into("<H", e, i * 2, ord(ch))
        struct.pack_into("<I", e, 128, atype)   # ad_type
        # trailing fields left zero -> do/while stops at name NUL, j < 64
        out += e
    out += bytearray(C.ATTRDEF_RECSZ)            # all-zero terminator
    return bytes(out)

def build(out_path):
    img = bytearray(C.NCLUSTERS * C.CLU)
    img[0:C.BPS] = C.boot_sector()
    rec0 = C.mft_record(1,1,0, C.resident_attr(C.A_DATA,8,b"\x00"*8)+C.term_attr())
    img[C.MFTCN*C.CLU+0*C.RECSZ:C.MFTCN*C.CLU+1*C.RECSZ] = rec0
    ad = benign_attrdef_records()
    rec4 = C.mft_record(1,1,0, C.resident_attr(C.A_DATA,len(ad),ad)+C.term_attr())
    img[C.MFTCN*C.CLU+4*C.RECSZ:C.MFTCN*C.CLU+5*C.RECSZ] = rec4
    iroot = C.well_formed_index_root()
    rec5 = C.mft_record(1,1,0x0002, C.resident_attr(C.A_INDXROOT,len(iroot),iroot,name="$I30")+C.term_attr())
    img[C.MFTCN*C.CLU+5*C.RECSZ:C.MFTCN*C.CLU+6*C.RECSZ] = rec5
    bmp = b"\xFF"*16
    rec6 = C.mft_record(1,1,0, C.resident_attr(C.A_DATA,len(bmp),bmp)+C.term_attr())
    img[C.MFTCN*C.CLU+6*C.RECSZ:C.MFTCN*C.CLU+7*C.RECSZ] = rec6
    runs = C.runs_encode(C.UPCASE_CN, C.UPCASE_NCLU)
    nr = C.nonresident_data_attr(runs, C.UPCASE_NCLU*C.CLU, C.UPCASE_NCLU*C.CLU)
    rec10 = C.mft_record(1,1,0, nr+C.term_attr())
    img[C.MFTCN*C.CLU+10*C.RECSZ:C.MFTCN*C.CLU+11*C.RECSZ] = rec10
    uo = C.UPCASE_CN*C.CLU
    img[uo:uo+C.UPCASE_NCLU*C.CLU] = C.upcase_table()
    with open(out_path,"wb") as f: f.write(img)
    print(f"[+] wrote benign {out_path} ({len(img)} bytes)")

if __name__ == "__main__":
    build(sys.argv[1] if len(sys.argv)>1 else "ntfs_benign.img")