原 po 如下 只是在 pray77 师傅的基础上做了一点意义不大的补充和学习 学习到了新的 rop 链构造方式
GitHub - pray77/SCTF2023_kernelpwn: SCTF 2023 kernel pwn
# 逆向
这里的代码只能看汇编 作者估计是直接用汇编写的
1 | .text:0000000000000010 seven_ioctl proc near ; DATA XREF: .data:00000000000003F8↓o |
cmd = 0x5555 的时候 有一次 aar 的机会
cmd = 0x6000 的时候 清零所有寄存器 然后栈迁移
1 | .text:000000000000005C loc_5C: ; CODE XREF: seven_ioctl+3B↑j |
一次 aar 和一次栈迁移 要实现提权 如果不学这个手法我是想不到的(aar 首先你要泄漏 kdma 才能读到 kbase 不然 rop 都布置不了)
# ret2hbp
[[ret2hbp]]
pray77 师傅提出的硬件断点 rop
关于 cpu_entry_area 6.2 之前没加入随机化
1 | fffffe0000000000 | -2 TB | fffffe7fffffffff | 0.5 TB | cpu_entry_area mapping |
1 | tools/perf/util/machine.c |
1 | noinstr struct cpu_entry_area *get_cpu_entry_area(int cpu) |
其中 CPU_ENTRY_AREA_PER_CPU 为 0xfffffe0000000000 + PAGE_SIZE
对着汇编很容易看出来 CPU_ENTRY_AREA_SIZE 是 0x35000
1 | pwndbg> x/10i get_cpu_entry_area |
cpu_entry_area 中的异常栈就是用户可以布置的 rop 位置 之后找个环境深入研究一下
cpu_entry_area
contains all the data and code needed to allow the CPU to hand control over to the kernel. When KPTI is enabled, only that part of the kernel is mapped when user-space is running.
1 | pwndbg> x/20gx 0xfffffe0000000000 + 4 |
如果我们实现了 aar 是可以在不泄露 kdma 的情况下获得 kbase 的
# hbp
amd64 上 dr0-7 (debugreg) 寄存器用于硬件断点
intel manual 17 page 18.2.4 节详细叙述了 dr7 他用于管理其他硬件断点
-
L0-L3 当前任务硬件断点 enable flag 在任务切换之后会抹去
-
G0-G3 全局任务硬件断点 enable flag 任务切换的时候不会抹去
Linux 上无论线程还是进程都是以 task_struct 进行描述 所以这里 L/G 应该是线程与进程的区别 -
LE and GE 不支持 amd64 不用管
-
R/W0 through R/W3 设置断点条件
- DE 激活情况下
- 00 — Break on instruction execution only.
- 01 — Break on data writes only.
- 10 — Break on I/O reads or writes.
- 11 — Break on data reads or writes but not instruction fetches.
- 无脑 11 就行
-
LEN
- 00 — 1-byte length.
- 01 — 2-byte length.
- 10 — Undefined (or 8 byte length, see note below).
- 11 — 4-byte length.
所以我如果 想触发一个硬件断点 只需要设置 dr [0] 为 bp_addr
然后设置 dr [7] 的 G0 为 1 (单线程无所谓 G0/L0) 然后 R/W0 为 11 LEN 为 11
简单来说就是 0x00 0f 04 02
# ptrace
通过 ptrace 可以 poke peek tracee 的 user 结构体 比如修改 dr 寄存器可以达到硬件断点的效果
# exp
1 |
|