这几天一直在跟着团队的进度做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
字节。
下面来看道例题: