基于代码级别的渗透测试实践
2016-05-08梁娟
梁 娟
(武汉交通职业学院, 武汉 430065)
渗透测试,是为了证明网络防御按照预期计划正常运行而提供的一种机制。渗透测试(penetration test)并没有一个标准的定义,国外一些安全组织达成共识的通用说法是:通过模拟恶意黑客的攻击方法,来评估计算机网络系统安全的一种评估方法。[1]这个过程包括对系统的任何弱点、技术缺陷或漏洞的主动分析,这个分析是从一个攻击者可能存在的位置来进行的,并且从这个位置有条件主动利用安全漏洞。广义上来说覆盖范围较广,可以使用各种端口、漏洞扫描工具扫描系统漏洞,同时可以开展Fuzzing测试、DOS攻击测试系统抗攻击能力,[2]也可以针对产品代码做白盒分析测试,从白盒的角度发现漏洞,分析出系统可能存在的问题,并通过黑盒的方式进行漏洞利用。本文主要从白盒的角度,通过代码走读的方式,讲述如何对系统进行渗透测试。
容易被程序员忽略,且被黑客利用的主要安全问题包括:[3]内存管理问题、字符串操作安全问题、格式化输出安全问题以及一些高危函数可能引起的问题。下面从这几个方面分析如何对代码进行渗透测试,发现代码中隐藏的安全问题。
一、内存管理安全问题
(一)实例1:内存未初始化
有些函数如malloc分配出来的内存是没有初始化的,可以使用memset进行清零,或者使用calloc进行内存分配,calloc分配的内存是清零的。当然,如果后面需要对申请的内存进行全部复制,就不要清零了,但要确保内存被引用前是被初始化的。此外,分配内存初始化,可以消除之前可能存放在内存中的敏感信息,避免信息的泄露。
比如下面的代码示例:
函数X_UINT32 X_PIC_Sendmsg中pcSendStr申请的内存未初始化,如果传入的uiLength<X_MSG_MAX_BUF,有部分内存没有被赋值,缓存内容作为消息发送出去,有可能造成攻击或消息泄露。
(二)实例2:动态申请内存未释放
在某些函数中动态申请了内存,但后续没有对申请的内存进行释放,[4]导致内存泄露,系统出现工作一段时间后异常的问题。
比如下面的代码示例,每次启动组播丢包诊断功能,动态申请内存,但停止诊断后,没有及时释放内存,导致反复进行组播丢包诊断功能,内存泄露,工作一段时间后,系统异常。
(三)实例3:内存拷贝长度超过目的内存大小
在下面的代码示例中,函数X_WEB_MatchUser InfoByMD5,acCookie的长度为 512,acPWD 的长度为128字节,在做cookie解析时,没有对uiWordLen进行判断,构造报文使cookie的长度为512字节,会导致acPWD内存溢出。
(四)总结:内存管理安全问题渗透测试方法
第一,关注复杂程度较高的重点模块,有针对性地进行渗透测试。
第二,注意内存分配的代码,查看是否存在内存管理安全:包括引用未初始化的内存、访问已经释放的内存、重复释放内存、释放非动态申请的内存、动态申请内存未释放、对指定申请内存大小的整数值未进行合法性校验、拷贝内存长度超过目的内存分配长度等。[5]
第三,查出疑似问题后,查看输入来源是否可以外部控制,按照代码实现功能构造黑盒测试方法,达到攻击目的。
第四,也可以使用大范围进行搜索排查,比如搜索malloc等动态内存分配函数以及内存拷贝的代码(memcpy关键字),一个个排查是否存在内存管理安全问题。
二、字符串操作安全问题
(一)实例1:拷贝字符串长度超过目的缓存大小
函数strncpy(char*dest,const char*src,int n),把src所指向的字符串中以src地址开始的前n个字节复制到dest所指的数组中,并返回dest。如果没有对dest与src长度进行限制,导致src字符串长度大于dest字符串长度时,会出现栈溢出情况,系统异常。比如下面的示例:入参dnsurl是一个512字节长度的char数组(X_CHAR8 dnsurl[512]={0};),进行字符串拷贝的时候,没有判断长度是否小于目的字符串(目的char数组长度为128字节),当构造特殊的 DNS 报文,第一个“:”到第一个“/”长度在131~512字节之间时,会导致栈溢出,系统异常。
(二)总结:字符串操作安全问题渗透测试方法
第一,关注字符串拷贝的代码(strncpy关键字),特别注意第三个参数为变量的地方,考虑第三个参数是否可能超过目的缓冲区大小。对于strcpy函数,关注src字符串长度是否大于dest字符串长度。
第二,查出疑似问题后,查看输入来源是否可以外部控制,按照代码实现功能构造黑盒测试方法,达到攻击目的。
三、格式化处理函数输出安全问题
(一)格式化函数参数未进行格式化处理
snprintf()函数第三个参数直接引入外部输入,没有对外部输入参数进行格式化处理,导致格式化字符串攻击。
比如下面的示例:
X_UAM_BuildGetDownloadStatusResponseMsg函数中X_OSS_Snprintf函数第三个参数直接引入外部输入,没有对外部输入参数进行格式化处理,pcTemp来源于外部AP的回应消息,遇到特殊的AP回应消息比如(%s%s%s%s%s%s%s%s%s%s%s%s%s),可以造成格式化字符串攻击导致栈击穿。
(二)总结:格式化处理函数输出问题渗透测试方法
第一,关注格式化处理函数的代码(snprintf),特别注意第三个参数直接为外部输入参数的地方,查看是否存在未格式化处理直接引用的情况。
第二,查出疑似问题后,查看输入来源是否可以外部控制,按照代码实现功能构造黑盒测试方法,达到攻击目的。
四、高危函数
strcpy()、sprintf()、strcat()这些函数存在安全隐患,[6]由于src字符串可能小于dst字符串,程序员在写作的时候很容易遗漏长度的判断,易被攻击造成系统安全问题,在使用时需谨慎。另外,可以通过使用其对应的安全版函数来替换:strncpy()、snprintf()、strncat(),避免出现安全问题。
参考文献:
[1]王晓聪,张冉,黄赪东.渗透测试技术浅析[J].计算机科学,2012(S1):43-45.
[2]王雷,陈归,金茂忠.基于约束分析与模型检测的代码安全漏洞检测方法研究[J].计算机研究与发展,2011(9):14-17.
[3]谢志锋.基于木马的网络渗透测试的研究[D].太原:太原理工大学,2013.
[4]梁业裕,徐坦,宁建创,杨明.代码审计工作在整个安全保障体系中的重要价值[J].计算机安全,2013(12):27-30.
[5]李天博.基于B/S架构的网络渗透技术研究与开发[D].北京:北京邮电大学,2014.
[6]李俊.白盒代码安全审计方法浅析[J].牡丹江大学学报,2014(10):21-24.