started palindromatic task of bi0sCTF 23

This commit is contained in:
2024-02-24 13:16:43 +01:00
parent 377c2ec6bc
commit 27cce50969
8 changed files with 405 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
CONFIG_SLUB=y
CONFIG_SLAB_FREELIST_RANDOM=y
CONFIG_SLAB_FREELIST_HARDENED=y
CONFIG_SLUB_CPU_PARTIAL=y
CONFIG_RANDOM_KMALLOC_CACHES=y
CONFIG_STATIC_USERMODEHELPER=y
CONFIG_STATIC_USERMODEHELPER_PATH=""

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,12 @@
#!/bin/sh
qemu-system-x86_64 \
-m 64M \
-cpu kvm64,+smep,+smap \
-kernel bzImage \
-drive file=rootfs.ext3,format=raw \
-drive file=exploit,format=raw \
-snapshot \
-nographic \
-monitor /dev/null \
-no-reboot \
-append "root=/dev/sda rw init=/init console=ttyS0 kaslr kpti=1 loglevel=0 oops=panic panic=-1"

View File

@@ -0,0 +1,241 @@
#include "linux/random.h"
#include "palindromatic_util.c"
char *temp_buffer;
unsigned long magic;
queue_t incoming_queue;
queue_t outgoing_queue;
bool sanitized = false;
/*
Copy request from user and add to start of queue
*/
static noinline long pm_add_request(arg_t *arg)
{
long idx = -1;
request_t *req = kmem_cache_zalloc(pm_cache, GFP_KERNEL);
if(!req) goto end;
req->type = RAW;
req->magic = magic;
if(copy_from_user(req->str, arg->buffer, STRING_SZ))
{
kfree(req);
goto end;
}
idx = pm_queue_enqueue(&incoming_queue, req);
end:
return idx;
}
/*
Accept characters only in [A-Z|a-z] and translate to [A-Z]
Only 1 sanitize is allowed
*/
static noinline long pm_sanitize_request(void)
{
long idx = -1;
request_t *req = pm_queue_peek(&incoming_queue);
if(!req) goto end;
if(req->type == SANITIZED) goto end;
memset(temp_buffer, 0x0, STRING_SZ);
int ptr = 0;
for(int i = 0; i < STRING_SZ; i++)
{
if(!req->str[i]) break;
if(req->str[i] > 0x60 && req->str[i] < 0x7b)
temp_buffer[ptr++] = req->str[i]-0x20;
else if(req->str[i] > 0x40 && req->str[i] < 0x5b)
temp_buffer[ptr++] = req->str[i];
else continue;
}
temp_buffer[ptr] = 0;
strcpy(req->sanstr, temp_buffer);
req->type = SANITIZED;
idx = pm_queue_enqueue(&incoming_queue, pm_queue_dequeue(&incoming_queue));
end:
return idx;
}
/*
If request is raw, remove it
else, set it to raw and send it back to start of the queue
*/
static noinline long pm_reset_request(void)
{
request_t *req = pm_queue_dequeue(&incoming_queue);
if(!req) return -1;
if(req->type != RAW)
{
req->type = RAW;
memset(req->sanstr, 0x0, sizeof(req->sanstr));
pm_queue_enqueue(&incoming_queue, req);
}
else
{
kfree(req);
}
return 0;
}
/*
Check if it is a palindrome or not and set type accordingly
Remove from incoming queue and add to outgoing queue
*/
static noinline long pm_process_request(void)
{
long idx = -1;
request_t *req = pm_queue_peek(&incoming_queue);
if(!req) goto end;
if(req->magic != magic) goto end;
int len = req->type==SANITIZED?strlen(req->sanstr):strlen(req->str);
if(!len) goto end;
idx = pm_queue_enqueue(&outgoing_queue, req);
if(idx < 0) goto end;
memset(temp_buffer, 0x0, STRING_SZ);
if(req->type == RAW)
{
for(int i = (len/2)-1; i > -1; i--)
{
if(req->str[i] < 0x41 || req->str[i] > 0x5a) break;
temp_buffer[i] = req->str[i];
}
temp_buffer[len/2] = 0;
if(strcmp(temp_buffer, &req->str[len/2]+len%2)) req->type = NONPALINDROME;
else req->type = PALINDROME;
pm_queue_dequeue(&incoming_queue);
}
if(req->type == SANITIZED)
{
for(int i = (len/2)-1; i > -1; i--) temp_buffer[i] = req->sanstr[i];
temp_buffer[len/2] = 0;
if(strcmp(temp_buffer, &req->sanstr[len/2]+len%2)) req->type = NONPALINDROME;
else req->type = PALINDROME;
pm_queue_dequeue(&incoming_queue);
}
end:
return idx;
}
/*
Get result of first request in outgoing queue
*/
static noinline long pm_reap_request(void)
{
request_t *req = pm_queue_dequeue(&outgoing_queue);
if(!req) return -1;
if(req->magic != magic) return -1;
long ret = req->type==PALINDROME?1:0;
kfree(req);
return ret;
}
/*
Get the available slots in both queues
*/
static noinline long pm_query_capacity(void)
{
long ret = (QUEUE_SZ-pm_queue_count(&outgoing_queue))<<16
| (QUEUE_SZ-pm_queue_count(&incoming_queue));
return ret;
}
static long pm_ioctl(struct file *file, unsigned int cmd, unsigned long uarg)
{
arg_t arg;
long ret = -1;
mutex_lock(&lock);
switch(cmd)
{
case QUEUE:
if(copy_from_user(&arg, (void *)uarg, sizeof(arg_t))) goto end;
ret = pm_add_request(&arg);
break;
case SANITIZE:
if(sanitized) goto end;
sanitized = true;
ret = pm_sanitize_request();
break;
case RESET:
ret = pm_reset_request();
break;
case PROCESS:
ret = pm_process_request();
break;
case REAP:
ret = pm_reap_request();
break;
case QUERY:
ret = pm_query_capacity();
break;
default:
goto end;
}
end:
mutex_unlock(&lock);
return ret;
}
static int __init init_palindromatic(void)
{
if(misc_register(&pm_device) < 0) goto err;
pm_cache = kmem_cache_create("palindromatic", TARGET_SZ, __alignof__(request_t),
SLAB_ACCOUNT | SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NO_MERGE, NULL);
if(!pm_cache) goto err;
temp_buffer = kzalloc(TARGET_SZ, GFP_KERNEL);
if(!temp_buffer) goto err;
get_random_bytes(&magic, sizeof(magic));
pm_queue_init(&incoming_queue);
pm_queue_init(&outgoing_queue);
return 0;
err:
if(pm_cache) kmem_cache_destroy(pm_cache);
printk(KERN_ALERT "[-] Failed to register pipeparty");
return -1;
}
static void __exit exit_palindromatic(void)
{
kfree(temp_buffer);
kmem_cache_destroy(pm_cache);
misc_deregister(&pm_device);
}
module_init(init_palindromatic);
module_exit(exit_palindromatic);

View File

@@ -0,0 +1,76 @@
#include <linux/compiler.h>
#include <linux/kobject.h>
#include <asm/page_types.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/gfp.h>
#include <linux/random.h>
#include <linux/gfp_types.h>
#include <linux/slab.h>
#include <linux/list.h>
MODULE_AUTHOR("k1R4");
MODULE_DESCRIPTION("\"palindromatic\" - bi0s CTF 2023");
MODULE_LICENSE("GPL");
enum : unsigned int
{
QUEUE = 0xb10500a,
SANITIZE,
RESET,
PROCESS,
REAP,
QUERY
};
typedef enum ptype : unsigned long
{
RAW = 0x1337,
SANITIZED,
PALINDROME,
NONPALINDROME
} ptype;
#define TARGET_SZ 0x400
#define STRING_SZ ((TARGET_SZ-2*sizeof(unsigned long))/2)
typedef struct request_t
{
ptype type;
unsigned long magic;
char str[STRING_SZ];
char sanstr[STRING_SZ];
} request_t;
typedef struct arg_t
{
char *buffer;
} arg_t;
#define QUEUE_SZ 0x100
typedef struct queue_t
{
int front;
int rear;
request_t *reqs[QUEUE_SZ];
} queue_t;
DEFINE_MUTEX(lock);
struct kmem_cache *pm_cache;
static noinline long pm_ioctl(struct file *file, unsigned int cmd, unsigned long uarg);
static struct file_operations pm_fops = { .unlocked_ioctl = pm_ioctl };
struct miscdevice pm_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "palindromatic",
.fops = &pm_fops,
};

View File

@@ -0,0 +1,68 @@
#include "palindromatic.h"
static void pm_queue_init(queue_t *queue)
{
queue->front = queue->rear = -1;
for(int i = 0; i<QUEUE_SZ; i++) queue->reqs[i] = NULL;
}
static long pm_queue_enqueue(queue_t *queue, request_t *req)
{
if((queue->front == 0 && queue->rear == QUEUE_SZ-1) || (queue->rear+1)%QUEUE_SZ == queue->front) return -1;
else if(queue->front == -1)
{
queue->front = queue->rear = 0;
queue->reqs[queue->rear] = req;
}
else if(queue->rear == QUEUE_SZ-1 && queue->front != 0)
{
queue->rear = 0;
queue->reqs[queue->rear] = req;
}
else
{
queue->rear++;
queue->reqs[queue->rear] = req;
}
return queue->rear;
}
static request_t *pm_queue_dequeue(queue_t *queue)
{
if(queue->front == -1) return NULL;
request_t *req = queue->reqs[queue->front];
queue->reqs[queue->front] = NULL;
if(queue->front == queue->rear) queue->front = queue->rear = -1;
else if(queue->front == QUEUE_SZ-1) queue->front = 0;
else queue->front++;
return req;
}
static request_t *pm_queue_peek(queue_t *queue)
{
if(queue->front == -1) return NULL;
else return queue->reqs[queue->front];
}
static int pm_queue_count(queue_t *queue)
{
if(queue->front == -1)
return 0;
else if(queue->rear >= queue->front)
return queue->rear-queue->front+1;
else
return QUEUE_SZ - queue->front + queue->rear + 1;
}