绕canary保护

本文介绍了Canary保护机制的工作原理,通过一个Bugku - Pwn4的实例,展示了如何泄露Canary值并利用其进行栈溢出攻击。在分析过程中,讨论了如何确定缓冲区大小,泄露Canary,以及构造ROP链来绕过保护。文章强调了在64位程序中Canary的特性,并提醒读者栈溢出攻击时需注意的细节。

这几天一直在跟着团队的进度做csapp的实验报告,突然想拿题来练手了才发现自己还是有点菜的。这次的任务是做一道简简单单的带canary保护的一题,做了很长时间问了很多师傅,也算把这个方法搞搞明白了,但是不确定能不能完全说的明白,那么下面就开始吧。

canary保护

canary就是一段简简单单的cookie,它一般在上个函数所保存的ebp之前(即靠近栈顶的那个方向)下面一个图能描述一个带canary保护的栈帧,应该还是比较清楚的。

↑栈顶
buf//函数的缓冲区,一般用于保存局部变量
canary
ebp//上一个函数保存的ebp
eip//返回地址
argument 1
argument 2
argument 3
...
...
↓栈底

如果企图用大量数据覆盖缓冲区并且修改返回地址的数据达到劫持eip的目的那么就会修改canary的值,那么在返回的时候检测到canary的值发生改变后就会直接抛出异常并且停止执行程序。并且每次canary的值都是随机的,普通方法几乎是突破不了的。但是我们可以先想办法泄露canary的值,然后再把canary插入到payload当中,这样的话,就算我溢出了,但是并没有修改canary的值,也就没办法检测到我有没有栈溢出了。在64位的程序当中,canary就是一个七字节的数据带一个\x00字节,并且\x00字节在最低位。

那么回想一下字符串是什么?字符串就是一串连着的字节序,不管它原本在这个地方的定义是什么,我说它是字符串,他就可以是字符串,因为计算机它不管是存什么数据它终归也只是0和1的组成。例如0x61626364它看上去好像是一个int型变量,但是它储存也只是

64 63 62 61

如果我把它看成字符串那也没错,它可以代表字符串dcba,它们存储的数据是一模一样的。但是有一个问题:计算机里基本上都是又很多字节连在一起,那如果后面还有很多数据,怎么样才能只表示字符串dcba呢?那就需要一个特殊字节\x00了,识别字符串会从一个字符指针开始,然后依次增大指针的值,只要指针所指向的地址不是\x00字节,那么它就可以是这个字符串中的一员。那如果我输入一个字符串,溢出了但没完全溢出呢?我们把字符串填充地恰到好处,刚好紧挨着canary,那么在之后如果printf这个字符串的话,就会把canary一起输出出来,我们就获取了canary。但是注意,canary最后一个字节是\x00,不会被接受,因此在获取canary的时候注意末尾加上\x00字节。

下面来看道例题:

Bugku - Pwn4

下载文件照例拖进虚拟机checksec检查一下各种保护

### Canary机制概述 栈金丝雀(Stack Canary)是一种用于检测缓冲区溢出的安全技术。其基本原理是在函数返回地址之前放置一个特定值(称为“金丝雀”),如果该值被修改,则表明发生了缓冲区溢出攻击[^1]。 在网络安全上下文中,绕过Canary保护通常涉及利用某些漏洞来规避这种安全措施。以下是几种常见的方法: 1. **覆盖其他变量而非直接破坏Canary** 攻击者可能通过精心设计输入数据仅覆盖目标内存区域中的非关键部分而不触及实际的Canary值,从而避免触发异常处理程序[^2]。 2. **泄露Canary值后再实施攻击** 如果存在信息泄漏漏洞,比如格式化字符串错误等,可以先读取到当前线程或进程内的Canary具体数值;之后再基于此构建精确控制流劫持所需的payload[^3]。 3. **利用已知固定Canary模式** 某些老旧系统可能存在未随机化的Canary实现方式,在这些情况下可以直接猜测或者枚举出正确的Canary序列号来进行后续操作[^4]。 下面给出一段Python伪代码展示如何尝试获取并应用泄露出来的canary value: ```python import struct def leak_canary(target_process): # 假设这里有一个能够造成信息泄露的功能调用 leaked_data = target_process.send_payload("%x." * 20) # 解析返回的数据找出canary所在canary_value = int(leaked_data.split('.')[CANARY_POSITION], 16) return canary_value def craft_exploit(canary, buffer_size): nop_sled = b"\x90" * (buffer_size - len(shellcode)) shellcode = asm("mov $0xb,%al; mov %esp,%ebx; ...") # 构造shellcode address_to_jump = struct.pack("<I", RETURN_ADDRESS) exploit_payload = ( nop_sled + shellcode + struct.pack("<I", canary) + b"A"*(CANARY_PADDING_SIZE-len(struct.pack("<I", canary))) + address_to_jump ) return exploit_payload ``` 以上仅为理论上的演示,请勿非法测试任何真实环境下的软件和服务!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xi@0ji233

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值