dreamcat@ubuntu:~/Desktop/wykernel/inctf2021_kqueue$ checksec vmlinux [*] '/home/dreamcat/Desktop/wykernel/inctf2021_kqueue/vmlinux' Arch: amd64-64-little RELRO: No RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0xffffffff81000000) RWX: Has RWX segments
文件系统加载了一个 mod,就是 kqueue
1 2 3 4 5 6 7
dreamcat@ubuntu:~/Desktop/wykernel/inctf2021_kqueue/file_system/root$ checksec --file=kqueue.ko [*] '/home/dreamcat/Desktop/wykernel/inctf2021_kqueue/file_system/root/kqueue.ko' Arch: amd64-64-little RELRO: No RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x0)
switch(cmd){ case CREATE_KQUEUE: result = create_kqueue(request); break; case DELETE_KQUEUE: result = delete_kqueue(request); break; case EDIT_KQUEUE: result = edit_kqueue(request); break; case SAVE: result = save_kqueue_entries(request); break; default: result = INVALID; break; } ret: mutex_unlock(&operations_lock); return result; }
static noinline longcreate_kqueue(request_t request){ long result = INVALID;
if(queueCount > MAX_QUEUES) err("[-] Max queue count reached");
/* You can't ask for 0 queues , how meaningless */ if(request.max_entries<1) err("[-] kqueue entries should be greater than 0");
/* Asking for too much is also not good */ if(request.data_size>MAX_DATA_SIZE) err("[-] kqueue data size exceed");
/* Check if multiplication of 2 64 bit integers results in overflow */ ull space = 0; if(__builtin_umulll_overflow(sizeof(queue_entry),(request.max_entries+1),&space) == true) err("[-] Integer overflow");
/* Size is the size of queue structure + size of entry * request entries */ ull queue_size = 0; if(__builtin_saddll_overflow(sizeof(queue),space,&queue_size) == true) err("[-] Integer overflow");
/* Total size should not exceed a certain limit */ if(queue_size>sizeof(queue) + 0x10000) err("[-] Max kqueue alloc limit reached");
/* All checks done , now call kzalloc */ queue *queue = validate((char *)kmalloc(queue_size,GFP_KERNEL));
/* Main queue can also store data */ queue->data = validate((char *)kmalloc(request.data_size,GFP_KERNEL));
/* Fill the remaining queue structure */ queue->data_size = request.data_size; queue->max_entries = request.max_entries; queue->queue_size = queue_size;
/* Get to the place from where memory has to be handled */ kqueue_entry = (queue_entry *)((uint64_t)(queue + (sizeof(queue)+1)/8));
/* Increment current_entry by size of queue_entry */ current_entry += sizeof(queue_entry)/16;
/* Populate next pointer of the previous entry */ prev_entry->next = current_entry; prev_entry = prev_entry->next; }
/* Find an appropriate slot in kqueues */ uint32_t j = 0; for(j=0;j<MAX_QUEUES;j++){ if(kqueues[j] == NULL) break; }
if(j>MAX_QUEUES) err("[-] No kqueue slot left");
/* Assign the newly created kqueue to the kqueues */ kqueues[j] = queue; queueCount++; result = 0; return result; }
static noinline longdelete_kqueue(request_t request){ /* Check for out of bounds requests */ if(request.queue_idx>MAX_QUEUES) err("[-] Invalid idx");
/* Check for existence of the request kqueue */ queue *queue = kqueues[request.queue_idx]; if(!queue) err("[-] Requested kqueue does not exist"); kfree(queue); memset(queue,0,queue->queue_size); kqueues[request.queue_idx] = NULL; return0; }
static noinline longedit_kqueue(request_t request){ /* Check the idx of the kqueue */ if(request.queue_idx > MAX_QUEUES) err("[-] Invalid kqueue idx");
/* Check if the kqueue exists at that idx */ queue *queue = kqueues[request.queue_idx]; if(!queue) err("[-] kqueue does not exist");
/* Check the idx of the kqueue entry */ if(request.entry_idx > queue->max_entries) err("[-] Invalid kqueue entry_idx");
/* Get to the kqueue entry memory */ queue_entry *kqueue_entry = (queue_entry *)(queue + (sizeof(queue)+1)/8);
/* Check for the existence of the kqueue entry */ exists = false; uint32_t i=1; for(i=1;i<queue->max_entries+1;i++){ /* If kqueue entry found , do the necessary */ if(kqueue_entry && request.data && queue->data_size){ if(kqueue_entry->idx == request.entry_idx){ validate(memcpy(kqueue_entry->data,request.data,queue->data_size)); exists = true; } } kqueue_entry = kqueue_entry->next; }
/* What if the idx is 0, it means we have to update the main kqueue's data */ if(request.entry_idx==0 && kqueue_entry && request.data && queue->data_size){ validate(memcpy(queue->data,request.data,queue->data_size)); return0; }
if(!exists) return NOT_EXISTS; return0; }
/* Now you have the option to safely preserve your precious kqueues */ static noinline longsave_kqueue_entries(request_t request){
/* Check for out of bounds queue_idx requests */ if(request.queue_idx > MAX_QUEUES) err("[-] Invalid kqueue idx");
/* Check if queue is already saved or not */ if(isSaved[request.queue_idx]==true) err("[-] Queue already saved");
switch(cmd){ case CREATE_KQUEUE: result = create_kqueue(request); break; case DELETE_KQUEUE: result = delete_kqueue(request); break; case EDIT_KQUEUE: result = edit_kqueue(request); break; case SAVE: result = save_kqueue_entries(request); break; default: result = INVALID; break; } ret: mutex_unlock(&operations_lock); return result; }
/* Check if multiplication of 2 64 bit integers results in overflow */ ull space = 0; if(__builtin_umulll_overflow(sizeof(queue_entry),(request.max_entries+1),&space) == true) err("[-] Integer overflow"); //Gcc 的内部函数,space= sizeof(queue_entry) * (request.max_entries+1);每一个entry可以理解为一个node /* Size is the size of queue structure + size of entry * request entries */ ull queue_size = 0; if(__builtin_saddll_overflow(sizeof(queue),space,&queue_size) == true) err("[-] Integer overflow"); //Gcc 的内部函数,queue_size = sizeof(queue) + space /* Total size should not exceed a certain limit */ if(queue_size>sizeof(queue) + 0x10000) err("[-] Max kqueue alloc limit reached");
/* All checks done , now call kzalloc */ queue *queue = validate((char *)kmalloc(queue_size,GFP_KERNEL)); //创建队列,queue_size = sizeof(queue_entry) * (request.max_entries+1) + sizeof(queue); /* Main queue can also store data */ queue->data = validate((char *)kmalloc(request.data_size,GFP_KERNEL));
/* Fill the remaining queue structure */ queue->data_size = request.data_size; queue->max_entries = request.max_entries; queue->queue_size = queue_size;
/* Get to the place from where memory has to be handled */ kqueue_entry = (queue_entry *)((uint64_t)(queue + (sizeof(queue)+1)/8));//(&queue+0x18)指向的是第一个节点的位置
static noinline longdelete_kqueue(request_t request){ /* Check for out of bounds requests */ if(request.queue_idx>MAX_QUEUES) err("[-] Invalid idx");
/* Check for existence of the request kqueue */ queue *queue = kqueues[request.queue_idx]; if(!queue) err("[-] Requested kqueue does not exist"); kfree(queue); memset(queue,0,queue->queue_size); kqueues[request.queue_idx] = NULL; return0; }
static noinline longedit_kqueue(request_t request){ /* Check the idx of the kqueue */ if(request.queue_idx > MAX_QUEUES) err("[-] Invalid kqueue idx");
/* Check if the kqueue exists at that idx */ queue *queue = kqueues[request.queue_idx]; if(!queue) err("[-] kqueue does not exist");
/* Check the idx of the kqueue entry */ if(request.entry_idx > queue->max_entries) err("[-] Invalid kqueue entry_idx"); //根据idx进行定位,定位到节点,每个节点不会保留data的大小, /* Get to the kqueue entry memory */ queue_entry *kqueue_entry = (queue_entry *)(queue + (sizeof(queue)+1)/8);//第一个头节点 //进行一个简单的遍历 /* Check for the existence of the kqueue entry */ exists = false; uint32_t i=1; for(i=1;i<queue->max_entries+1;i++){ /* If kqueue entry found , do the necessary */ if(kqueue_entry && request.data && queue->data_size){//节点存在,data指针不为空, if(kqueue_entry->idx == request.entry_idx){ validate(memcpy(kqueue_entry->data,request.data,queue->data_size)); exists = true; } } kqueue_entry = kqueue_entry->next; }
/* What if the idx is 0, it means we have to update the main kqueue's data */ if(request.entry_idx==0 && kqueue_entry && request.data && queue->data_size){ validate(memcpy(queue->data,request.data,queue->data_size));//memcpy返回的是queue->data return0; }