0%

scanf_attacker?

一切都源于某个中午的突发奇想~

想法

众所周知,在较低的libc版本(2.34之前)下进行orw利用一般是把__free_hook劫持为setcontext进行栈迁移(现在还需要跳板gadget完成rdxrdi的转变),堆的各项布局对于我这个想寄就寄的菜鸟来说真是心力憔悴。

转念一想free(buf)中的buf是人为可控的,free也可以由__free_hook被劫持为某个函数。刚好当时国赛出题出的就是有关格式化字符串printfscanf的漏洞利用,就有了这样的想法——free(buf)===>scanf(buf),其中buf堆块中存放着%n$s来对准rbp链在函数返回地址处直接构造orw

scanf格式化字符串漏洞

利用scanf(%n$s)可以对偏移为n的栈上指针指向处进行任意长度的输入。常见利用手法有:

  1. 栈上若残留IO指针可进行IO_ATTACK泄露libc
  2. 利用rbp链构造rop,直接避开了rbp链前的canary

试验

于是兴致勃勃地跑去用上次刚复盘过的题目进行试验:

下图为已劫持__free_hookscanf,正在尝试执行scanf('%8$s')操作(8为rbp链的偏移):

送些垃圾数据过去,看一下栈的变化:

可以看到我们成功利用rbp链将main函数栈的返回地址给覆盖为了anzaanza,加上scanf也不会被\x00截断,所以直接构造orw并非难事。

分析

优点

  1. 省去了对堆块的布局操作以及寻找rdxrdi转变的gadget,简化为只需要爆破出固定偏移即可。

  2. 上次复盘时感觉setcontextorw链需要在一个较大的堆块中进行布局,如果所给堆块较小的话,大概会提高利用的复杂程度(第一次利用setcontext解题,经验不足,可能是拙见)。而scanf可输入不限长,对参数堆块buf的大小也不做限制。

  3. 如果题目允许,则可不断申请、释放?相当于无限次格式化字符串漏洞(不论劫持为scanf还是printf),可以在栈上构造想要的地址,然后对其指向处进行修改等操作?

缺点

  1. 试验过程中我们知道,在delete功能函数中利用scanf格式化漏洞利用只能修改到其父函数main函数的返回地址,而许多题目都是直接exit退出了,不给main函数返回的机会。
  2. 会被\x0a截断,对rop链有要求。
  3. 大概更适用于orw,毕竟不开沙箱的话直接构造system('/bin/sh')就好。

其他

scanf(buf)system(buf)都是控制函数和其第一个参数,而后者被sandbox之后,前者还有用武之地(除非orw白名单)。不知能否配合io_file之类的利用手法,以及搭配起来是否比原解法更方便。