赞
踩
PXN简介
PXN全称 Privileged Execute-Never,是一种内核安全特性,用来阻止内核直接执行用户空间的代码,能够极大地提升漏洞利用的难度。
根据kernelsec网站的描述,armv8及以上版本的PXN特性由硬件支持,各平台和架构的PXN特性见下图:
(表格内容来自Linux Kernel Security Subsystem)
结合对linux源码(内核版本5.10.41)的分析可以发现,PXN和UXN机制均通过寄存器中的一个位进行控制,具体实现如下:
- arch/arm64/include/asm/pgtable-hwdef.h
- /*
- * Level 3 descriptor (PTE).
- */
- #define PTE_PXN (_AT(pteval_t, 1) << 53) /* Privileged XN */
- #define PTE_UXN (_AT(pteval_t, 1) << 54) /* User XN */
因为PXN特性取决于硬件平台是否支持,所以即使我们看到代码中有对应的实现,并不代表这个功能在系统上是有效的,因此需要进一步构造测试案例来验证。
构造测试案例
编写内核模块,在内核模块中创建proc文件系统,通过proc_write接口向内核空间传递用户空间的代码地址,然后尝试在内核空间中直接执行来自用户空间的代码。
kernel模块主要逻辑实现如下:
- static ssize_t mywrite(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos)
- {
- char buf[MAX_LENGTH];
- typedef void (*MY_FUNC_P)(void);
-
- printk(KERN_INFO "********************* dump stack **********************\n");
- dump_stack();
-
- ((MY_FUNC_P)ubuf)();
- return count;
- }
用户空间主要逻辑实现如下:
- void
- payload(void)
- {
- if (getuid() == 0) {
- printf("[+] PXN is gone, how dare you!\n");
- execl("/bin/sh", "sh", NULL);
- } else {
- warnx("this will never be execute.");
- }
-
- _exit(0);
- }
-
- extern uint32_t shellCode[];
-
- asm
- (
- " .text\n"
- " .align 2\n"
- " .globl shellCode\n\t"
- "shellCode:\n\t"
-
- "bl #payload\n\t"
- );
-
-
- void
- trigger_vuln(int fd, int canary)
- {
-
- #define MAX_PAYLOAD (MAX + 4 * 4 )
-
- char buf[MAX_PAYLOAD];
-
- memset(buf, 0, sizeof(buf));
-
- void * pc = buf ;
-
- *(void **)pc = (void *) shellCode;
-
- write(fd, buf, sizeof(buf) );
-
- printf("[+] write done, %d bytes\n", sizeof(buf));
- }
通过执行测试案例,我们的预期结果是kernel在执行用户空间代码时抛出异常提示,但如果用户空间的测试程序执行之后输出"[+] PXN is gone, how dare you!\n",则表示PXN没有生效。
测试结果
安装内核模块:
- vcu-sxxx:/home# insmod lkm_pxn.ko
- vcu-sxxx:/home# [ 49.457010] hello...
执行用户空间程序:
- vcu-sxxxxx:/home# chmod +x uspace
- vcu-sxxxxx:/home# ./uspace
- [ 61.084617] ********************* dump stack **********************
- [ 61.084642] CPU: 3 PID: 1474 Comm: uspace Tainted: G O 5.10.41-rt42+g5c4c385db992 #1
- [ 61.084658] Hardware name: ARM vcu-sxxxxx(DT)
- [ 61.084663] Call trace:
- [ 61.084665] dump_backtrace+0x0/0x180
- [ 61.084686] show_stack+0x18/0x70
- [ 61.084695] dump_stack+0xd0/0x12c
- [ 61.084707] mywrite+0x2c/0xd8 [lkm_pxn]
- [ 61.084720] proc_reg_write+0xa8/0xec
- [ 61.084731] vfs_write+0xf0/0x2b0
- [ 61.084743] ksys_write+0x58/0xe0
- [ 61.084751] __arm64_sys_write+0x20/0x30
- [ 61.084760] el0_svc_common.constprop.0+0x78/0x1a0
- [ 61.084772] do_el0_svc+0x24/0x90
- [ 61.084780] el0_svc+0x14/0x20
- [ 61.084790] el0_sync_handler+0x1a4/0x1b0
- [ 61.084797] el0_sync+0x180/0x1c0
- [ 61.084810] Unable to handle kernel execution of user memory at virtual address 0000007fd808ce58
- [ 61.165015] Mem abort info:
- [ 61.165014] printk: console [ttyLF0]: printing thread stopped
- [ 61.167933] ESR = 0x8600000f
- [ 61.176923] EC = 0x21: IABT (current EL), IL = 32 bits
- [ 61.182402] SET = 0, FnV = 0
- [ 61.185549] EA = 0, S1PTW = 0
- [ 61.188788] user pgtable: 4k pages, 39-bit VAs, pgdp=000000009709d000
- [ 61.195406] [0000007fd808ce58] pgd=000000008c39b003, p4d=000000008c39b003, pud=000000008c39b003, pmd=0000000081f30003, pte=00e8000086663f43
- [ 61.208308] Internal error: Oops: 8600000f [#1] PREEMPT_RT SMP
- [ 61.214289] Modules linked in: lkm_pxn(O) pfeng(O)
- [ 61.219205] CPU: 3 PID: 1474 Comm: uspace Tainted: G O 5.10.41-rt42+g5c4c385db992 #1
- [ 61.228482] Hardware name: ARM XXXXX (DT)
- [ 61.233300] pstate: 40000005 (nZcv daif -PAN -UAO -TCO BTYPE=--)
- [ 61.239457] pc : 0x7fd808ce58
- [ 61.242501] lr : mywrite+0xb4/0xd8 [lkm_pxn]
- [ 61.246882] sp : ffffffc01235b980
- [ 61.250275] x29: ffffffc01235b980 x28: ffffff8001d29a80
- [ 61.255721] x27: 0000000000000000 x26: 0000000000000000
- [ 61.261165] x25: 0000000000000000 x24: 0000000000000000
- [ 61.266609] x23: 0000000000000000 x22: ffffffc01235be38
- [ 61.272052] x21: 0000007fd808ce58 x20: 0000007fd808ce58
- [ 61.277497] x19: 0000000000000050 x18: 00000000fffffffa
- [ 61.282941] x17: 0000000000000000 x16: 0000000000000000
- [ 61.288385] x15: 0000000000000020 x14: 4141414141414141
- [ 61.293828] x13: 4141414141414141 x12: 4141414141414141
- [ 61.299272] x11: 4141414141414141 x10: 4141414141414141
- [ 61.304715] x9 : 4141414141414141 x8 : 4141414141414141
- [ 61.310160] x7 : 4141414141414141 x6 : ffffffc01235b9f0
- [ 61.315603] x5 : ffffffc01235b9f0 x4 : 0000000000000008
- [ 61.321048] x3 : 858d0cd041414141 x2 : 0000000000000000
- [ 61.326493] x1 : 0000007fd808cea8 x0 : 0000000000000000
- [ 61.331938] Call trace:
- [ 61.334442] 0x7fd808ce58
- [ 61.337127] proc_reg_write+0xa8/0xec
- [ 61.340886] vfs_write+0xf0/0x2b0
- [ 61.344289] ksys_write+0x58/0xe0
- [ 61.347688] __arm64_sys_write+0x20/0x30
- [ 61.351709] el0_svc_common.constprop.0+0x78/0x1a0
- [ 61.356623] do_el0_svc+0x24/0x90
- [ 61.360020] el0_svc+0x14/0x20
- [ 61.363154] el0_sync_handler+0x1a4/0x1b0
- [ 61.367262] el0_sync+0x180/0x1c0
- [ 61.370667] Code: 00000000 00000000 000000ac 00000000 (41414141)
- [ 61.376915] ---[ end trace 0000000000000002 ]---
- Segmentation fault
从日志“Unable to handle kernel execution of user memory at virtual address”可以确认,内核PXN机制阻止了此次用户空间代码的执行。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。