# 总述
本文讲解了 shellcode 的简单编写。
学习编写 shellcode,学习利用 shellcode 执行任务
# shellcode
shellcode 是一段特别的代码,在很小的空间内执行任务。一般是一段机械码,用来执行获得 shell 的代码。
shellcode 可以看作是 rop 攻击的衍生,只是它是专门用来获得 shell 的一段特别的汇编代码,执行它去获得 shell。
Shellcode 编写方式基本有 3 种:
- 直接编写十六进制操作码(不现实)。
- 采用像 C 这样的高级语言编写程序,编译后,进行反汇编以获取汇编指令和十六进制操作码。
- 编译汇编程序,将该程序汇编,然后从二进制中提取十六进制操作码。
# 编写
注意事项:
- 系统调用问题:shellcode 只有几十个字节,不能靠应用头文件,导入符号表,调用系统函数,这样的话字节数不能满足条件。需要利用系统最核心的调用机制绕开系统调用。
- 坏字符问题,shellcode 如果放在栈堆上面就要避免出现截断的 \x00 这样的字节,这种叫做坏字符 bad character,(\x00=null \x0a = 回车换行 \xff = 换页 \x0d = 回车)
# 找系统调用号
64 位和 32 位的系统调用号是不一样的。
linux 和 windows 的系统调用号也不一样。
# 查看函数原型
使用 man 命令可以查看首页册来查看函数原型,找到对应的需要的参数和值。
1 | man [选项] [章节] 名称 |
-
选项:常用选项有
-k
(搜索包含指定关键字的手册页)、-f
(显示指定名称的手册页章节信息)等。 -
章节
:手册页被分为多个章节,不同章节包含不同类型的内容,常见章节如下:
- 1:用户命令(如
ls
、cp
等)。 - 2:系统调用(如
open
、read
等)。 - 3:库函数(如
printf
、malloc
等)。 - 5:文件格式和约定(如
/etc/passwd
文件格式)。 - 8:系统管理命令(如
ifconfig
、mount
等)。
- 1:用户命令(如
-
名称:要查看手册页的命令、函数或文件的名称。
# 编写 shellcode
- 安照函数原型设置对应参数。
- 利用 syscall 调用对应函数。
C 语言编写
返回本地 shell 的例子为:
1 |
|
汇编编写
1 | section .text |
# 提取 shellcode
1 | objdump -M intel -D file_path | grep '[0-9a-f]:' | grep -v 'file' | cut -f2 -d: | cut -f1-7 -d' ' | tr -s ' ' | tr '\t' ' ' | sed 's/ $//g' | sed 's/ /\\\x/g' | paste -d '' -s |
1 | 创建一个名为 shellcode.asm 的文件,将上述汇编代码复制到该文件中 |
# 消除 bad character
然后要删去 bad character。
可以通过查看别人写的 shellcode 来看看有没有对应的改写方法。
针对这种的 mov eax,0x1
,可以使用对寄存器的一部分赋值实现,比如: mov al,0x1
还可以通过 xor rax,rax
先把 rax 置为 0,然后 add rax,0x1
实现
# 使用 shellcode
shellcode 本质就是一段汇编指令,要执行它,就必须把它放在可执行的区域,如 bss,如没有开启 NX 的栈上面,然后把程序执行流控制到 shellcode 开始的地方,接下来执行 shellcode
# 例子
得到 shellcode:
1 | #char *const argv[]={"/bin/sh",NULL}; |
exp:写入 buf(可执行区域)内,然后去到对应的位置。
1 | #可以指定架构然shellcode更加准确 |
# 注意事项
leave:
leave 的作用相当于 MOV SP,BP;POP BP。
因为 leave 指令会释放栈空间,因此我们不能使用目标地址后面的 24 字节。
目标地址后的 8 个字节也不能存放(这里需要存放返回地址)。故我们的 shellcode 只能 放在目标首地址后的 24+8 后的地址。
例如:溢出垃圾数据 +(可执行目标地址 + 32)+ shellcode
1 | payload = cyclic(0x10+8) + p64(v5 + 24+8) + shellcode |
**mmap: **
buf = mmap (0, 0x400u, 7, 34, 0, 0); :这行代码使用 mmap 函数分配一块内存区域,将其起 始地址保存在变量 buf 中。
此时在 buf 中的 shellcode 仍然可以执行。
输入字符限定:
对于 shellcode 进行字符筛选,我们只能使用有限的字符进行 shellcode 编写
使用 pwntools 生成一个 shellcode,没法直接输出,有乱码,将 shellcode 重定向到一个文件中 切换 到 alpha3 目录中,使用 alpha3 生成 string.printable 。string.printable,就是可见字符 shellcode。
1 | cd alpha3 |
nop sled:
nop sled 是一种可以破解栈随机化的缓冲区溢出攻击方式。
攻击者通过输入字符串注入攻击代码。在实际的攻击代码前注入很长的 nop 指令 (无操作,仅使程 序计数器加一)序列, 只要程序的控制流指向该序列任意一处,程序计数器逐步加一,直到到达攻击代码的存在的地址, 并执行。
将 shellcode 填充为以 nop (0x90) 指令开头进行滑栈。