本文介绍了如何通过IDA Python脚本来实现对栈溢出漏洞的检测,并以ascii_easy一道PWN基础题为例来实战。原文
介绍
IDAPython 是一个用于复杂逆向工程任务的强大的自动化工具。尽管有很多文章介绍了用IDAPython来简化基本的逆向任务,但很少有提及使用IDAPython来审计二进制漏洞的方法。 因为这不是一个新的方法(Halvar Flake在2001年做过关于IDA脚本自动分析漏洞的研究),但令人惊讶的是,这个话题没有被更多的说明。这可能是因为在现代操作系统上想要利用漏洞日渐复杂困难。然而,这对于自动化部分的漏洞研究还是有价值的。
在这篇文章中,我们将介绍使用基本的IDAPython来检测程序中出现的能导致栈溢出问题的地方。在这篇文章中,我会用自动化探测方法实战pwnable.kr 中的ascii_easy二进制题目。尽管这个二进制文件小到我们可以手动整个去分析它,它仍然是一个很好的学习案例以便我们使用相同的IDAPython技术取分析更大更复杂的二进制文件。
开始
在我们写任何IDAPython脚本前,我们先要决定我们想让我们的脚本做什么。 这里,我们选择了简单漏洞中的一个栈溢出漏洞,其可由strcpy
函数导致将用户可以控制的字符串拷贝到栈缓存区中。既然我们知道了我们要寻找什么,我们可以开始考虑如何取自动化寻找这种漏洞。
我们分为两步:
定位可能导致栈溢出的函数(这里我们选取strcpy
函数)
分析这些函数的调用来决定这个这个调用我们是否感兴趣(即是否可能导致漏洞)
定位函数调用
为了寻找任何调用strcpy
的地方,我们需要首先定位strcpy
这个函数本身。 使用IDAPython API很容易做到这一点。使用如下的代码片段来打印二进制文件中所有的函数名:
for functionAddr in Functions():
print(GetFunctionName(functionAddr))
(注:可以在ida底部的python命令控制窗口中输入命令) 我们可以看到,所有的函数名都被输出了。
然后,我们要添加过滤取寻找我们感兴趣的strcpy
函数。简单的字符串比较我们就能达到效果。但因为我们常常需要处理一些函数名相似但仍有区别的情况(例如_strcpy
,这取决于导入函数的命名),我们最好检查子字符串。
在前面的基础上,我们有下面的代码
for functionAddr in Functions():
if “strcpy” in GetFunctionName(functionAddr):
print hex(functionAddr)
既然我们获得了我们感兴趣的函数,我们需要获取所有调用它的地方。这需要很多步骤。 首先我们要获取strcpy
交叉引用的地方,然后我们要检查这其中的每个地方是否真正调用了strcpy
函数。总结一下就有下面的代码:
for functionAddr in Functions():
# Check each function to look for strcpy
if "strcpy" in GetFunctionName(functionAddr):
xrefs = CodeRefsTo(functionAddr, False)
# Iterate over each cross-reference
for xref in xrefs:
# Check to see if this cross-reference is a function call
if GetMnem(xref).lower() == "call":
print hex(xref)
对ascii_easy二进制文件运行此脚本后我们得到如下结果:
即我们找到了0x451b2c目标地址。
分析函数调用
现在,通过上面的代码,我们知道了如何获取所有程序中调用strcpy
的地方。而ascii_easy恰好就只有这一个调用strcpy
的地方(也恰好可利用),很多程序有很多调用strcpy
的地方(很多都不可被利用),因此我们需要一些方法取分析对strcpy
的调用来根据可利用的可能性进行排序。
一个缓存区溢出漏洞的常见特点是它们往往涉及栈上的缓冲区。尽管在堆上或者别的地方的缓存区溢出也是有可能的,栈溢出是一个更简单的利用方式。
[招生]科锐逆向工程师培训(2025年3月11日实地,远程教学同时开班, 第52期)!
最后于 2019-8-30 12:27
被微笑明天编辑
,原因: 修复图片