标题:
MMA CTF 2nd 2016 : greeting-150
原理:
栈溢出,爆破system地址,绕过PIE保护。
做题环境:
ubuntu14 64位
工具:
pwntools、LibcSearcher
步骤:
根据程序逻辑爆破system地址,进而计算出libc_base,进而构造ROP链获得shell。
具体流程:
用checksec查看保护:发现有PIE保护,即地址无关可执行文件。
对于PIE保护的具体细节,PIE原理。简单来说就是开了PIE保护之后,程序会在每次加载时都变换加载基址,从而使位于程序本身的gadget也失效。只能使用相对偏移。攻击手法祥见PIE保护攻击方法。
从IDA里分析程序。
发现该处的无论判断是否成立之前,已经将system
地址写进rbp-110h
处。
接着往下看。
发现当我们输入“1”,进入1、Go选项,发现有个可疑的变量,也在rbp-110h处,有没有可能两个是指向同一个位置呢,那就看是不是进入函数时的rsp是否相等,再用IDA分析
发现两个函数之间没有对rsp进行操作,也就是进入两个函数时的rsp是一样的,所以两个变量是同一个位置,也就是再Go选项的函数里,v5里的脏数据,是system地址,这可不是脏数据,是宝贝!继续看
大致的程序逻辑是,我们先输入level,然后判断level是否大于0,是则将level赋值给v5(v5里面脏数据是system地址),若小于等于0,直接则进入输入"any more?",给v3输入一个数,然后将v5、v3之和赋值给v6,然后判断v6是否大于0,大于则进入level游戏,否则return puts("Coward Coward Coward Coward Coward");
。所以我们给level输一个0,然后v5保持脏数据为system地址,在输入v3为小于负system地址的值,导致v6=v5+v3小于0,进而return puts("Coward Coward Coward Coward Coward");
,以此可以进行爆破出system地址。
由于PIE保护之下,system地址的后12位(3个16进制位)不变,由上面的PIE原理可知,system地址就是0x7ffbf8000***-rand,调试得后12位为0x390,rand是28位数左移12位,也就是会影响0x7f之后的7个16进制位,也就是要爆破这7个16进制位。
上面已经说了,如果v6小于0,就会return puts("Coward Coward Coward Coward Coward");
,当我们输入level=0时,v6=v5+v3,v5=system_addr,v3是我们可控的,所以可以从0x7f0000000390,构造-0x7f*000000390,我们从*处从f->0开始爆破,可知-0x7f*000000390+system_addr=v6,易知当*处的16进制数和system_addr对应的*处的16进制数一样的时候,便进入level,只要system_addr不是0x7f*000000390,就会导致-0x7f*000000390+system_addr<0,依次爆破,可以从高位到低位爆破出system_addr,但是到最后一位时,即0x390的前一个,因为此时中间要爆破的前六16进制数已经确定,要想此时v3+system_addr<0,那么该16进制数只能小真实的system_addr的对应位,所以最后爆破出来的还要再加0x1000。
以上是爆破出system_addr的方法,
整体思路就是这样。
上exp:
from pwn import *
from LibcSearcher import *
#context.log_level='debug'
def hint():
io