diff --git a/bi0sctf23/pwn/palindromatic/.config b/bi0sctf23/pwn/palindromatic/.config new file mode 100644 index 0000000..c52c075 --- /dev/null +++ b/bi0sctf23/pwn/palindromatic/.config @@ -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="" \ No newline at end of file diff --git a/bi0sctf23/pwn/palindromatic/bzImage b/bi0sctf23/pwn/palindromatic/bzImage new file mode 100644 index 0000000..034249e Binary files /dev/null and b/bi0sctf23/pwn/palindromatic/bzImage differ diff --git a/bi0sctf23/pwn/palindromatic/palindromatic.ko b/bi0sctf23/pwn/palindromatic/palindromatic.ko new file mode 100644 index 0000000..0647fac Binary files /dev/null and b/bi0sctf23/pwn/palindromatic/palindromatic.ko differ diff --git a/bi0sctf23/pwn/palindromatic/rootfs.ext3 b/bi0sctf23/pwn/palindromatic/rootfs.ext3 new file mode 100644 index 0000000..a9d5037 Binary files /dev/null and b/bi0sctf23/pwn/palindromatic/rootfs.ext3 differ diff --git a/bi0sctf23/pwn/palindromatic/run.sh b/bi0sctf23/pwn/palindromatic/run.sh new file mode 100644 index 0000000..0cc4d59 --- /dev/null +++ b/bi0sctf23/pwn/palindromatic/run.sh @@ -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" diff --git a/bi0sctf23/pwn/palindromatic/src/palindromatic.c b/bi0sctf23/pwn/palindromatic/src/palindromatic.c new file mode 100644 index 0000000..1270b2a --- /dev/null +++ b/bi0sctf23/pwn/palindromatic/src/palindromatic.c @@ -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); \ No newline at end of file diff --git a/bi0sctf23/pwn/palindromatic/src/palindromatic.h b/bi0sctf23/pwn/palindromatic/src/palindromatic.h new file mode 100644 index 0000000..8530c52 --- /dev/null +++ b/bi0sctf23/pwn/palindromatic/src/palindromatic.h @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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, +}; \ No newline at end of file diff --git a/bi0sctf23/pwn/palindromatic/src/palindromatic_util.c b/bi0sctf23/pwn/palindromatic/src/palindromatic_util.c new file mode 100644 index 0000000..4792fb9 --- /dev/null +++ b/bi0sctf23/pwn/palindromatic/src/palindromatic_util.c @@ -0,0 +1,68 @@ +#include "palindromatic.h" + +static void pm_queue_init(queue_t *queue) +{ + queue->front = queue->rear = -1; + for(int i = 0; ireqs[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; +} \ No newline at end of file