概述
一、代码审计
1.1什么是代码审计?
1.2为什么要执行代码审核?
1.3代码审计的好处
二、代码审计流程
2.1代码检查方法
2.2代码检查项目
2.3编码规范
2.4代码检查规范
2.5缺陷检查表
2.6代码审计复查
2.7代码审计结果总结
三、代码审计实操
3.1所用工具
3.2RIPS
3.2.1代码扫描
3.3Seay源代码审计系统
3.3.1代码扫描
3.3.2典型漏洞分析
3.4Fortify
3.4.1代码扫描
3.4.2典型漏洞分析
3.5洞态IAST
3.5.1代码扫描
3.5.2典型漏洞分析
四、总结
从3月初到今天代码审计课程结束了,今天将所有内容进行总结,内容从代码审计基础到代码审计实践完成提高的全面总结。
软件代码审计是对软件解决方案或产品中的源代码的全面分析。它被认为是安全过程中最关键的阶段之一,因为它用于验证代码的成熟度和可维护性,同时确保产品已准备好进行无缝切换。
1. 熟悉当前的项目结构和功能
2. 发现现有和潜在的错误
3. 发现安全漏洞和漏洞
4. 验证当前性能和可扩展性
5. 评估代码可维护性级别以及相关的风险和成本
6. 验证是否符合相关的软件开发标准、指南和最佳实践
1. 实现快速的漏洞扫描和修补
2. 打造更加安全可靠的网络运行环境
(1)桌面检查
这是一种传统的检查方法。程序员检查自己的程序。程序编译完成后,程序员会对源代码进行分析和检查,并补充相关文档,以发现程序中的错误。由于程序员熟悉自己的程序和编程风格,程序员自己进行桌面检查可以节省大量检查时间,但应避免主观的片面性。
(2) 代码审查
由几个程序员和测试人员组成的评审小组通过阅读、讨论和争论对程序进行静态分析的过程。代码评审分为两步:第一步是组长提前向团队成员分发设计规范、控制流程图、程序文本、相关要求和规范,作为评审的依据。在充分阅读这些材料后,团队成员进入审查的第二步,并召开程序审查会议。在会上,程序员首先逐句介绍了程序的逻辑。在这个过程中,程序员或其他团队成员可以提出问题、讨论和审查是否存在错误。实践表明,程序员可以发现许多他们在解释过程中没有发现的错误,而讨论和争议会促进问题的暴露。
应为审查小组的每个成员编制一份常见错误清单,列出过去所有可能的常见错误,供与会者进行比较和检查,以提高审查的有效性。这个常见错误列表也称为检查表。它对程序中可能出现的各种错误进行分类,列出每种类型错误的尽可能多的典型错误,然后将它们放入一个表格中进行重新检查。
(3)走查
它与代码审查基本相同,代码审查分为两个步骤。第一步是将材料分发给走查小组的每个成员,并要求他们在召开会议之前仔细研究程序。会议程序与准则审查不同。参与者不是简单地阅读程序并对照错误清单进行检查,而是“充当”一台计算机,也就是说,首先,测试团队的成员为测试程序准备一批具有代表性的测试用例,并将它们提交给走查团队。在小组会议中穿行,集体扮演计算机的角色,让测试用例沿着程序的逻辑运行,并随时记录程序的轨迹以供分析和讨论。
借助测试用例的媒体功能,人们对程序的逻辑和功能提出了各种各样的问题,并结合问题进行了热烈的讨论和争论,从而发现更多的问题。
代码检查应在编译和动态测试前进行。检查前,应编制需求描述文件、程序设计文件、程序源代码、代码编写标准和代码缺陷检查表。在实际使用中,代码检查可以快速发现缺陷,发现30%到70%的逻辑设计和编码缺陷,代码检查中发现的问题不是症状。然而,代码检查非常耗时,代码检查需要积累知识和经验。
代码检查可以使用测试软件进行自动测试,以提高测试效率和降低劳动强度,也可以使用手动测试来充分发挥人类的逻辑思维能力。
文档和源程序代码 |
一份最新的设计文档 |
程序结构图 |
|
所有的模块源程序代码 |
|
代码体系结构描述 |
|
目录文件 |
|
代码组织 |
|
目录文件组织 |
所有的文件名简单明了,见名知意 |
文件和模块分组清晰 |
|
每个文件只包含一个完整模块的代码 |
|
数据库检查 |
数据库命名使用小写英语字母, 数字和下划线,无其他字符 |
数据库命名采用项目名或产品名称命名 ,长度小于20位 |
|
数据库中的所有表字符集统一 |
|
检查函数 |
函数头清晰地描述了函数的功能 |
函数的名字清晰地定义了它所要做的事情 |
|
参数遵循一个规律的顺序 |
|
所有的参数都是要有用的 |
|
函数参数接口关系清晰明了 |
|
函数所使用的算法要有说明 |
|
数据类型及变量 |
每个数据类型都有其解释 |
每个数据类型都有正确的取值 |
|
每一个变量的命名,都明确的表示代表什么 |
|
检查条件判断语句 |
If/else 使用正确 |
无嵌套的if链 |
|
数字,字符,指针和0/NULL/FLSE 判断明确 |
|
不要有臃肿的判断逻辑 |
|
检查循环体 |
循环体不为空 |
循环之前做好初始化代码 |
|
有明确的多次循环操作,使用For循环 |
|
所有的循环边界是否正确 |
|
检查代码注释 |
有一个简单的说明,用于描述代码的结构 |
每个文件和模块均以给予解释 |
|
程序(模块)检查 |
程序中所有的异常是否处理了 |
程序中是否存在重复的代码 |
|
函数调用关系图 |
|
模块控制流图 |
编码规范是指在编程过程中必须遵循的规则。通常,将详细制定代码的语法规则和语法格式。
如:当响应“content-type”为“html”类型时,外部输入拼接到响应包中,需根据输出位置进行编码处理。编码规则:
场景 |
编码规则 |
输出点在HTML标签之间 |
需要对以下6个特殊字符进行HTML实体编码(&, <, >, ", ',/)。 |
输出点在HTML标签普通属性内(如href、src、style等,on事件除外) |
要对数据进行HTML属性编码。 |
输出点在JS内的数据中 |
需要进行js编码 |
输出点在CSS中(Style属性) |
需要进行CSS编码 |
输出点在URL属性中 |
对这些数据进行URL编码 |
在代码检查中,有必要根据被测试软件的特点选择合适的标准和规则。当使用测试软件进行自动代码检查时,测试工具通常有许多内置的编码规则。在自动测试的基础上,使用桌面检查、代码遍历和代码审查等手动检查方法仔细检查程序结构和逻辑中的缺陷。
如:Java
文件组织规则:由于超过2000行的程序难以阅读,应该尽量避免出现超过2000行的程序。一个Java源文件都包含一个单一的公共类或接口。若私有类和接口与一个公共类相关联,可以将它们和公共类放入同一个源文件。公共类必须是这个文件中的第一个类或接口。
文件组织顺序:
1.文件注释:所有的源文件都应该在开头有一个注释,其中列出文件的版权声明、文件名、功能描述以及创建、修改记录:
2.包和引入语句:在多数Java源文件中,第一个非注释行是包语句。在它之后可以跟导包语句
3.类或接口注释:采用JavaDoc文档注释,在类、接口定义之前应当对其进行注释,包括类、接口的描述、最新修改者、版本号、参考链接等;
4. JavaDoc文档注释:描述Java的类、接口、构造方法、方法、以及字段。每个文档注释都会被置于注释定界符/**...*/之中,一个注释对应一个类、接口或成员。该注释应位于声明之前。文档注释的第一行(/**)不需缩进,随后的文档注释每行都缩进1格(使星号纵向对齐)。
4.类或接口的声明
5.类或接口的实现注释:如果有关类或接口的信息不适合作为“类或接口文档注释”,可以在类或接口的实现注释中给出;
6.类的(静态)变量:首先是类的公共变量,随后是保护变量,再后是包一级别的变量(没有访问修饰符),最后是私有变量;
7.实例变量:首先是公共级别的,随后是保护级别的,再后是包一级别的(没有访问修饰符),最后是私有级别的;
8.构造方法;
9.普通方法:方法应该按功能分组,而不应该按作用域或访问权限进行分组。
在手动代码检查中,代码缺陷检查表是我们使用的测试用例。代码缺陷清单通常包括容易出错的地方和以前工作中遇到的典型错误。
重要性 |
激活 |
级别 |
检测项 |
|
总计 |
||||
命名 |
||||
重要 |
Y |
20 |
命名规则是否与所采用的规范保持一致? |
|
是否遵循了最小长度最多信息原则? |
||||
重要 |
Y |
50 |
has/can/is前缀的函数是否返回布尔型? |
|
注释 |
||||
重要 |
10 |
注释是否较清晰且必要? |
||
重要 |
Y |
10 |
复杂的分支流程是否已经被注释? |
|
10 |
距离较远的是否已经被注释? |
|||
10 |
非通用变量是否全部被注释? |
|||
重要 |
Y |
50 |
函数是否已经有文档注释?(功能、输入、返回及其他可选) |
|
10 |
特殊用法是否被注释? |
|||
声明、空白、缩进 |
每行是否只声明了一个变量?(特别是那些可能出错的类型) |
|||
20 |
变量是否已经在定义的同时初始化? |
|||
重要 |
40 |
类属性是否都执行了初始化? |
||
重要 |
40 |
是否合理地使用了空格使程序更清晰? |
||
20 |
代码行长度是否在要求之内? |
|||
语句/功能分布/规模 |
||||
20 |
包含复合语句的{}是否成对出现并符合规范? |
|||
重要 |
20 |
单行是否只有单个功能?(不要使用;进行多行合并) |
||
Y |
20 |
操作符++和— —操作符的应用是否复合规范? |
缺陷检查表
对前五步进行审计的结果再次进行复查,写出复查报告,确定所有漏洞的正确性,将非代码错误进行打回重新检测,保证代码升级结果的正确性、完整性。
代码审计结束,代表一次代码审计完全结束,需要将完整的代码审计报告进行上交,内容包括:代码漏洞原因、出处、修复方法等,帮助管理人员进行更好的项目决策,同时证明增加安全预算的必要性,并将安全问题传达到高级管理层,进行更好的安全认知,有助于进一步健全安全建设体系,遵循了相关安全策略、符合安全合规的要求。
RIPS |
RIPS是一个用 PHP 编写的源代码分析工具,它使用了静态分析技术,能够自动化地挖掘 PHP 源代码潜在的安全漏洞。渗透测试人员可以直接容易的审阅分析结果,而不用审阅整个程序代码。由于静态源代码分析的限制,漏洞是否真正存在,仍然需要代码审阅者确认。RIPS 能够检测 XSS, SQL 注入, 文件泄露, Header Injection 漏洞等。 |
Seay源代码审计系统 |
这是一款基于C#语言开发的一款针对PHP代码安全性审计的系统,主要运行于Windows系统上。这款软件能够发现SQL注入、代码执行、命令执行、文件包含、文件上传、绕过转义防护、拒绝服务、XSS跨站、信息泄露、任意URL跳转等漏洞。 |
Fortify |
Fortify ,是一个静态的、白盒的软件源代码安全测试工具。它通过内置的五大主要分析引擎:数据流、语义、结构、控制流、配置流等对应用软件的源代码进行静态的分析,分析的过程中与它特有的软件安全漏洞规则集进行全面地匹配、查找,从而将源代码中存在的安全漏洞扫描出来,并给予整理报告。扫描的结果包含详细的安全漏洞信息、安全知识说明、修复意见。 |
洞态IAST |
IAST 相当于 DAST 和 SAST 的组合,是一种相互关联的运行时安全检测技术。 它通过使用部署在 Web 应用程序上的 Agent 来监控运行时发送的流量并分析流量流以实时识别安全漏洞,IAST 提供更高的测试准确性,并详细的标注漏洞在应用程序代码中的确切位置,从而帮助开发人员达到实时修复。 |
官网:RIPS - free PHP security scanner using static code analysis
下载完成后直接解压到www目录,通过访问RIPS进行启动
http://192.168.72.1:80/rips-0.55/
首先介绍工具,最上面的输入行从从左到右,从上到下依次为扫描路径、扫描等级、扫描类型、输出类型、正则表达式搜索
第一步 path/file中输入扫描目录C:\phpStudy\WWW\sqli-labs-master\Less-4,其他都选择默认,点击scan进行扫描
输入扫描目录
扫描结果
扫描结果通过图形化弹窗的界面向我们展示出来,一目了然。
我们看到有一个文件包含漏洞和一个SQL注入漏洞,我们点击SQL注入,可以查看到原因代码。
原因代码
上图显示的是一个命令注入漏洞,提示信息为:Userinput reaches sensitive sink,用户能够输入敏感信息,造成命令注入漏洞。
通过点击最左边红色的按钮,可以生产漏洞利用的弹窗,通过$_GET对ID的值进行获取,从而实现SQL注入攻击。
漏洞利用弹窗
在红色的按钮的左边第一个按钮是数据泄露信息扫描的按钮,我们可以通过该内容,得知我们所泄露的内容是否重要,或者这本就应该是用户应该获取的内容。
数据泄露扫描界面
红色按钮左侧第二个按钮为帮助按钮,其中对各种漏洞的概念、漏洞描述、漏洞示例、补丁等进行了详细描述。
3.2.2典型漏洞分析
SQL注入漏洞分析
通过上面的扫描过程我们已经发现了一个SQL注入 漏洞,这也是一个典型漏洞,我们对它进行典型漏洞分析。
首先我们再了解一下我们可以查看到扫描结果的详细内容,漏洞所在的PHP文件位置,用户输入、统计结果、扫描到的函数
接下来对漏洞所在的文件进行分析。点击files可以查看漏洞所在的文件和关系图。
files界面
点击user input可以看到网站使用函数。
user input界面
在SQL Injection界面中,会直接显示可能存在漏洞的代码,我们从中看到代码没有对输入的ID进行一个过滤,会导致一个SQL注入的实现。
SQL Injection内容界面
点击review code可以定位改端代码在源代码中的位置。(乱码原因:工具版本问题,新版需要付费)
CodeViewer界面
下载连接:阿里云盘分享
下载后直接解压,打开Seay源代码审计系统.exe即可
Seay源代码审计系统.主界面
首先我们打开新建一个项目,本次我们审计的是DWVA系统,所以将DWVA系统的文件导入到审计系统
DWVA代码审计
我们点击自动审计、开始,自动化代码审计就开始了
自动化代码审计
一段时间后,扫描完成,会发现可疑漏洞,本次扫描共发现189个可疑漏洞,我们双击以一个敏感信息泄露漏洞,就可以查看漏洞的代码的位置。
漏洞代码
也可以点击生成报告来生成本次审计报告。
代码审计报告
文件上传漏洞分析
通过上面的扫描过程我们已经发现了一个文件上传 漏洞,这也是一个典型漏洞,我们对它进行典型漏洞分析。
文件上传
首先我们双击进入函数,可以看到此处进行了文件上传,并且没有对获取的文件进行过滤,直接就进行了保存,因此我们可以对其进行一个文件上传测试。
问题代码
我们上传一个文件马,发现直接上传成功了
上传截图
我们直接访问它的上传地址,发现php版本就被直接爆出,确定了漏洞的存在。
漏洞截图
下载链接:Fortify (fortifyapp.com)
下载结束需要破解+汉化
使用PHPStudent搭建DVWA靶场,启动Apache和Mysql,保证靶场可以正常运行,如下图DVWA靶场
DVWA靶场
再次进入Fortify安装目录下bin目录,双击打开auditworkbench.bat进入Fortify,找到Advanced Scan进行代码审计扫描
Fortify界面
选择pikachu的目录进行扫描,如图2.3 DVWA目录
DVWA目录
扫描结果如下图扫描结果,通过扫描结果,得到众多靶场漏洞,本次举例几种比较重要的漏洞进行讲解。
扫描结果
命令注入
从下图我们得知本次扫描有命令注入,如下图命令注入所示
命令注入
通过分析代码审计的结果,得知函数在获取变量后没有进行过滤,就直接进行了命令操作,导致了命令注入漏洞。
打开漏洞原因的php界面,进行漏洞复测,输入ip & dir,检查输出结果含有目录的结果,如下图命令注入漏洞复测结果。
命令注入漏洞复测结果
看到复测结果已得知漏洞存在,因此如何修复漏洞就成了最主要的问题,分析代码,漏洞成因为第 26 行rce_ping.php 的会利用由不可信赖的数据构建的命令来调用 shell_exec()。这种调用会导致程序以攻击者的名义执行恶意命令。所以最好的修复办法就是在输入的内容进行过滤,在代码添加过滤函数,将输入内容控制在只有IP。
SQL注入
从下图我们得知本次扫描有命令注入,如下图SQL注入所示
SQL注入
通过分析代码审计的结果,得知函数在获取变量后没有进行过滤,就直接进行了拼接 SQL 参数。也就是将用于输入的查询参数,直接拼接在 SQL 语句中,导致了SQL 注入漏洞,导致了SQL注入漏洞。
打开漏洞原因的php界面,进行漏洞复测,输入’1 or ‘1’=’1检查输出结果为全部登录的结果,如下图SQL注入漏洞复测结果。
SQL注入漏洞复测结果
看到复测结果已得知漏洞存在,因此如何修复漏洞就成了最主要的问题,分析代码,漏洞成因为第 9 行low.php的调用通过不可信赖的数据源输入构建的 SQL 查询。通过这种调用,攻击者能够修改语句的含义或执行任意 SQL 命令。
所以最好的修复办法就是 采用sql语句预编译和绑定变量,SQL引擎会预先进行语法分析,产生语法树,生成执行计划,也就是说,后面你输入的参数,无论你输入的是什么,都不会影响该sql语句的 语法结构了。
结果输出
为了更好的提交结果,所以软件也存在结果输出的方法,方法如图结果输出
结果输出
选择需要的版本进行输出,本次选择OWASP Top 10 2017进行输出,如下图OWASP Top 10 2017输出
OWASP Top 10 2017输出
输出的报告如下图报告所示,包含所有所需的具体信息。
报告
安装流程:
1. 安装curl,在终端输入:
sudo apt-get update
sudo apt-get install curl
2. 输入命令:curl -sSL https://get.daocloud.io/docker | sh
3. 安装docker-compose
输入命令:sudo apt-get install docker-compose
4. 接着在ubuntu输入以下命令
$ git clone https://github.com/HXSecurity/DongTai.git
$ cd DongTai
$ chmod u+x build_with_docker_compose.sh
$ sudo ./build_with_docker_compose.sh 端口输入81,然后打开网站http://127.0.0.1:81,如下图登录界面所示:
登录界面
首先新建项目,项目名称为test,并且新增一个扫描策略模板,模板将全部漏洞类型都进行选择,进行保存如图All扫描策略模板
All扫描策略模板
接着点击右上角的Add Agent进行某种语言的Agent,本次实验为JAVA语言,因此下载需要JAVA Agent,双击DongTai Java Aget进行下载,如图JAVA Agent下载页面
JAVA Agent下载页面
接下来进入命令行,下载靶场SecExample,命令如下git clone https://github.com/tangxiaofeng7/SecExample.git如图靶场SecExample安装
靶场SecExample安装
接着将第一步下载的JAVA Agent复制到靶场的target文件夹下,如图JAVA Agent复制
JAVA Agent复制
然后在命令行输入apt install openjdk-8-jre-headless # version 8u312-b07-0ubuntu1~20.04下载Java 1.8如图 jdk安装
jdk安装
最后在命令行输入java -javaagent:./dongtai-agent.jar -Dproject.name=test -jar ./secexample-1.0.jar 开始进行代码审计扫描扫描,如图代码审计扫描
代码审计扫描
此时查看项目列表以及显示Agent的数量+1,如图Agent+1
Agent+1
接着我们访问本机的127.0.0.1:8080/home进入Java漏洞演示平台,如图Java演示平台
Java演示平台
选择命令行注入进行测试,输入whoami,点击提交,如图命令行注入
命令行注入
返回洞态IAST,就可以看到以及有了返回结果,如图命令注入记录,从中我们可以看到漏洞的描述、请求包、响应包、修复建议等等
命令注入记录
我们对其他漏洞也进行测试,就可以发现更多漏洞记录,如图验证码记录、XSS漏洞记录、spel表达式注入
验证码记录
XSS漏洞记录
spel表达式注入
最后进行漏洞数据导出,我采用的xml文件导出的结果如图漏洞报告。
漏洞报告
本次代码审计总结算是是对这几周学习的交代,我对代码审计的理解已经深入,代码审计是一个有耐心,细心,恒心的人才能完成这个任务。这次总结的内容虽然不是很多,但通过这个过程认真的学习也让我切实了解到审计重要性,也让我们深刻了解到现实的审计工作过程。通过四次理论作业和四次实验操作,进一步巩固已学根本理论实践内容并加以分析进步,学会将学问使用于实际的办法,有了进一步分析和处理的能力。报告做完,自己也具备了一定的审计实际操作能力。