-
-
[原创]栈溢出之plt表利用实例--学习笔记
-
发表于: 2022-3-17 13:27 11002
-
题目在附件
首先我们用checksec查看一下这个题
看到它是一个32位小端序,有canary保护且栈不可执行的这样一个程序。
对它的保护机制大概有个了解后现在我们用32位IDA打开它来看看
打开IDA找到main函数双击按F5查看C代码
前面8行定义变量的掠过,第10行的_readgsdword(0x14u)是用来设置canary保护机制的也不管,第11行似乎有个有意思的函数我们点进去看看。我们进到sub_804862b()函数里
发现也没啥有用的东西,前三行setbuf都是关闭缓冲区操作,第6行mprotect是一个设置内存页保护属性的函数也没啥用,第七行一个alarm函数是设置超时的,超过设置的时间程序就会结束,都没啥用。我们按ESC退回去继续看主函数
第12到16行赋值没啥好看的,第17行输出了buf所在这块栈空间的内容,但12行已经给buf赋值0了,所以这个%s什么也没输出。没啥用,继续看下一行
第18行用read读入一个5个字节长度的数据到buf所在地址里面去,通常看到read、puts这类函数我们就要睁大眼睛了,因为溢出很可能就是在这里。我们算一下这个buf自己的空间有多大。我们根据IDA的提示来给这个程序画一个栈结构
我们能够看到buf本身只有4个字节,而此处的read要读入5个字节,那么显然会把本该属于V2的最末尾一个字节覆盖掉。
我们继续往下捋,第19行的if语句如果进去了的话那么程序就会输出一个buf的地址后exit(0)退出,所以这个if条件也没啥实际意义。直接跳到if之后。
第24行给buf所指向的地址赋值V2,并且我们点击第24行按一下tab键能看到它的汇编语句,这里是用V2的[AL]也就是V2的最后一个字节来给*buf赋值的。而我们刚才分析知道buf的指向,也就是他自己的4个字节我们是可以控制的,并且V2的最后一个字节我们也是可以控制的。所以这里显示是个可利用的点,我们先记下来。
第25行只输出一个东西也没啥用。第26行又向buf所在地读入10个字节,然后调用了puts函数输出&buf的值。
在这道题里,第一个read让我们可以控制5个字节,且可以用第5个字节给前4个字节所指向的地址赋值,第二个read可以让我们给下面的puts函数写入一个参数。
这里我们就想,如果这里不是调用的puts函数而是调用的system函数那就万事大吉了,因为我们可以直接往&buf里写入参数“/bin/sh”就拿到shell了。那么我们怎么做到这一点呢?这里引入一个plt表的知识点。
我们用plt打印一下程序的plt表并且用x/4i+地址查看一下它们的反汇编内容
我们知道在动态链接的程序里,当程序首次调用某个函数时会先调用resolver函数去解析被调函数在内存中的真实地址,而它解析的依据就是图中红框框里的”参数“,在本题中,当参数为0x30时resolver就会解析出system函数的地址填到被调函数的got表里,当参数为0x28时resolver就会解析出puts函数的地址填到被调函数的got表里。所以,如果我们在程序首次执行puts函数前,修改掉puts在plt里的参数,把它改为0x30,那么resolver就会解析出本该system的地址填到puts函数的got表里并执行system。
实操
所以在本题中,我们只需要利用第一个read函数把puts的plt参数改成system的参数0x30,再用第二个read函数读入”/bin/sh“,那么最后看似执行的puts("/bin/sh")就变成了system("/bin/sh")了。
所以首先我们用 x/b+地址 挨着挨着查找到puts的plt的参数(0x28)所在字节的精确地址
我们找到0x28这个参数所在地址为0x80484d7,那么后面就很简单了。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!