
本书是奇安信认证网络安全工程师培训教材之一,目的是为网络安全行业培养合格的人才。网络安全人才的培养是一项艰巨的任务,其中代码审计人才更是“稀缺资源”。本书分为4章。第1章代码审计基础,内容包括基础Java开发环境搭建、代码审计环境搭建。第2章常见漏洞审计,介绍了多种常见漏洞的成因以及审计和修复的技巧。第3章常见的框架漏洞,介绍了Java开发中经常使用的一些框架的典型漏洞,如Spring、Struts2等的命令执行漏洞。第4章代码审计实战,通过对真实环境下的Java应用程序进行审计,向读者详细介绍了Java代码审计的技巧与方法。本书可供软件开发工程师、网络运维人员、渗透测试工程师、网络安全工程师,以及想要从事网络安全工作的人员阅读。
前言 随着互联网的高速发展,各类新型Web攻击层出不穷。NIST(美国国家标准与技术研究院)的研究表明,在软件开发生命周期中,在软件发布以后进行修复的代价是在软件设计和编码阶段即进行修复所花代价的30倍,所以在软件系统发布后才发现系统缺陷,然后再去进行修复,这样的代价是很大的。如何在软件系统发布前找到Web应用系统存在的隐藏漏洞已成为众多企业普遍面临的问题。代码审计便是在攻击发生前通过审查源代码的方式,找到系统中的隐藏漏洞。这十分考验代码审计人员对漏洞原理的掌握以及对开发语言的熟悉程度。 伴随Java语言的发展,现在越来越多的程序采用Java语言进行编写。传统的代码审计人员往往对PHP代码审计很熟练,Java开发人员也并不了解所有常见的漏洞,因此写一本有关Java代码审计的书籍便变得尤为重要。 对于渗透测试人员来说,掌握代码审计应是一项基本技能,只有懂得了漏洞的原理以及产生的过程,才能够根据具体漏洞环境的变化写出符合实际需求的攻击代码进行渗透。对于代码审计人员,只有充分挖掘当前代码中可能存在的安全问题,才能使开发人员了解其开发的应用系统可能会面临的威胁,并正确修复程序缺陷。在网络安全竞赛中有一个常见考点:由源代码泄露产生的代码审计。这在实际攻防渗透中也很常见,即由于系统配置或管理员的错误操作而导致系统的源代码泄露。除了源代码泄露,在实战中另外一个场景是目标站点使用了某套开源系统,这时我们除了查找此开源系统已公开的相关漏洞,还有一个十分有效的攻击手法是对此开源系统进行代码审计,以发现未知的漏洞,通过未知漏洞进行攻击。 代码审计需要通过阅读源代码的方式找到隐藏的安全问题,因此代码审计对渗透测试人员的编程能力有一定的要求,而最基础的要求是能够读懂代码逻辑、读懂代码的功能。高中时期我的数学老师曾说过的一句话使我印象深刻—他说:学习是一通百通的,当你学好数学后你就能学好物理、学好化学或是其他的任何一门课程,因为学习的方法是一样的。这句话同样适用于编程语言的学习,大家在校时或多或少都学过C、Python等编程语言,只需将这种编程思想套用到Java语言的学习中即可快速学会它。因此本书更加关注的是怎么写源代码会产生漏洞,这个漏洞为什么会产生,这个函数为什么是不安全的;而不是关注要实现这个功能我们应该怎么写源代码。对于代码审计的常规手法,一般可分为以下三种。 (1)通读源代码:这种审计手法往往能够发现隐藏较深的安全问题,一般从程序的入口函数开始读。但其缺点也十分明显,需要通读整个源代码的逻辑,因此十分耗费时间。 (2)关键函数回溯:这种方法比第一种方法效率大大提升,但是很难发现隐藏极深的安全问题。对于关键函数回溯法,首先需定位到敏感函数以及参数,随后同步回溯参数的赋值过程,判断是否可控以及是否经过过滤等。 (3)追踪功能点:这种方法需要审计人员有一定的渗透测试基础,根据自己的经验判断可能存在问题的路由或功能点,并针对该功能点进行通读。例如,文件上传漏洞可直接通过定位上传函数来发现。 对于一个专业的代码审计人员,审计流程可以分为以下四个步骤。 (1)前期准备阶段:通过由测试人员提供、GitHub、Gitee、CSDN、SVN、源代码泄露漏洞等各类途径获取程序源代码,并搭建相关环境。对于审计环境的准备,我们将在后面的章节做详细介绍。 (2)代码审计阶段:可以先通过奇安信代码卫士、Fortify等自动审计工具对源代码进行扫描,并根据程序提示有目的地进行测试。当扫描工具测试不全或是无可用的扫描工具时,可以根据常见关键字对程序进行全局搜索并定位可能存在问题的程序段。当然,也可以完全从入口函数开始通读所有的源代码。 (3)POC编写阶段:当通过代码审计找到安全问题后,要做的便是根据审计结果以及触发方式编写可行的概念性验证(POC)脚本,通过POC脚本来进一步确定问题以及会造成的影响。 (4)报告编写阶段:根据前面发现的安全问题以及概念性验证(POC)脚本的验证结果,编写整体的代码审计报告,以方便他人查阅。 编著者 2021年7月
第1章 代码审计基础 (1) 1.1 Java Web环境搭建 (1) 1.1.1 Java EE介绍 (1) 1.1.2 Java EE环境搭建 (1) 1.2 Java Web动态调试 (18) 1.2.1 Eclipse动态调试 (19) 1.2.2 IDEA动态调试程序 (21) 第2章 常见漏洞审计 (32) 2.1 SQL注入漏洞 (32) 2.1.1 SQL注入漏洞简介 (32) 2.1.2 执行SQL语句的几种方式 (33) 2.1.3 常见Java SQL注入 (38) 2.1.4 常规注入代码审计 (46) 2.1.5 二次注入代码审计 (48) 2.1.6 SQL注入漏洞修复 (51) 2.2 任意文件上传漏洞 (53) 2.2.1 常见文件上传方式 (53) 2.2.2 文件上传漏洞审计 (56) 2.2.3 文件上传漏洞修复 (59) 2.3 XSS漏洞 (61) 2.3.1 XSS常见触发位置 (61) 2.3.2 反射型XSS (65) 2.3.3 存储型XSS (66) 2.3.4 XSS漏洞修复 (70) 2.4 目录穿越漏洞 (73) 2.4.1 目录穿越漏洞简介 (73) 2.4.2 目录穿越漏洞审计 (74) 2.4.3 目录穿越漏洞修复 (75) 2.5 URL跳转漏洞 (76) 2.5.1 URL重定向 (77) 2.5.2 URL跳转漏洞审计 (78) 2.5.3 URL跳转漏洞修复 (79) 2.6 命令执行漏洞 (80) 2.6.1 命令执行漏洞简介 (80) 2.6.2 ProcessBuilder命令执行漏洞 (80) 2.6.3 Runtime exec命令执行漏洞 (83) 2.6.4 命令执行漏洞修复 (90) 2.7 XXE漏洞 (90) 2.7.1 XML的常见接口 (91) 2.7.2 XXE漏洞审计 (94) 2.7.3 XXE漏洞修复 (96) 2.8 SSRF漏洞 (97) 2.8.1 SSRF漏洞简介 (97) 2.8.2 SSRF漏洞常见接口 (98) 2.8.3 SSRF漏洞审计 (101) 2.8.4 SSRF漏洞修复 (103) 2.9 SpEL表达式注入漏洞 (105) 2.9.1 SpEL介绍 (105) 2.9.2 SpEL漏洞 (106) 2.9.3 SpEL漏洞审计 (107) 2.9.4 SpEL漏洞修复 (109) 2.10 Java反序列化漏洞 (109) 2.10.1 Java序列化与反序列化 (110) 2.10.2 Java反序列化漏洞审计 (113) 2.10.3 Java反序列化漏洞修复 (116) 2.11 SSTI模板注入漏洞 (118) 2.11.1 Velocity模板引擎介绍 (119) 2.11.2 SSTI漏洞审计 (120) 2.11.3 SSTI漏洞修复 (121) 2.12 整数溢出漏洞 (122) 2.12.1 整数溢出漏洞介绍 (122) 2.12.2 整数溢出漏洞修复 (122) 2.13 硬编码密码漏洞 (123) 2.14 不安全的随机数生成器 (124) 第3章 常见的框架漏洞 (127) 3.1 Spring框架 (127) 3.1.1 Spring介绍 (127) 3.1.2 第一个Spring MVC项目 (128) 3.1.3 CVE-2018-1260 Spring Security OAuth2 RCE (139) 3.1.4 CVE-2018-1273 Spring Data Commons RCE (144) 3.1.5 CVE-2017-8046 Spring Data Rest RCE (149) 3.2 Struts2 框架 (156) 3.2.1 Struts2介绍 (156) 3.2.2 第一个Struts2项目 (157) 3.2.3 OGNL表达式介绍 (166) 3.2.4 S2-045远程代码执行漏洞 (170) 3.2.5 S2-048远程代码执行漏洞 (179) 3.2.6 S2-057远程代码执行漏洞 (183) 第4章 代码审计实战 (190) 4.1 OFCMS审计案例 (190) 4.1.1 SQL注入漏洞 (194) 4.1.2 目录遍历漏洞 (196) 4.1.3 任意文件上传漏洞 (199) 4.1.4 模板注入漏洞 (204) 4.1.5 储存型XSS漏洞 (205) 4.1.6 CSRF漏洞 (207) 4.2 MCMS审计案例 (209) 4.2.1 任意文件上传漏洞 (212) 4.2.2 任意文件解压 (217)