快速代码审计(java)

1、配置信息

首先看pom.xml,了解到使用了哪个依赖库以及版本,从而可以确定是否存在漏洞。
图中Shiro<=1.2.4版本,存在shiro550反序列化漏洞,
image
application.yml
该配置文件可能存在数据库或其他组件的连接信息,如数据库连接信息。
image

漏洞关键字:
Fastjson <=1.2.83 
Jackson <=2.9.2 
POI < 3.11 DOS XXE
Shiro <= 1.24 
Spring 5.0.x < 5.0.6 1
Spring 4.3.x < 4.3.7

2、配置不当

swagger接口文档泄露

下图的就是将com.sky.controller.admin包下的所有接口扫描成swagger接口调试文档。
image
这就是访问swagger调试文档访问地址。
image
image
在项目审计中,swagger接口文档是不应该被用户访问的,接口文档可直接就是存在漏洞问题。

搜索关键字:
doc.html
swagger
addResourceHandlers
Docket

springboot-actuator接口未授权

这个配置确实是将所有 Actuator 端点都暴露出来,包括了 /actuator/* 下的所有端点。这意味着所有的监控和管理端点都会对外公开,包括健康检查、信息显示、配置信息、metrics 等。某些端点可能包含敏感信息,比如 /actuator/env 端点可能会暴露应用程序的环境变量。
image

搜索关键字:
management.endpoints.web.exposure.include=*
endpoints.env.enabled=true
endpoints.enabled = true
management
actuator

未授权访问

过滤器

该方法判断了请求url是否包含了/login.html或者register.html,如果包含就放行。
所以我们可以http://127.0.0.1/login.html/../admin/test的方法绕过过滤。
image

关键字:
doFilter
Filter

拦截器

如果路径的开头是以/admin开头并且Session中的loginUser属性为 null,就会判断是否登录。利用:构造结构路径为/;/admin或//admin后访问(不影响解析),即可绕过登录限制。
image

关键字:
Interceptor
addinterceptor

shiro

在shiro过滤器中对所有路径配置了anon匿名拦截器,即不需要认证

关键字:
anon
authc
shiro
点击查看代码示例
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

    // 自定义 Realm(需实现认证和授权逻辑)
    @Bean
    public CustomRealm customRealm() {
        return new CustomRealm();
    }

    // 安全管理器
    @Bean
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(customRealm());
        return securityManager;
    }

    // Shiro 过滤器配置
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean() {
        ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
        filterFactoryBean.setSecurityManager(securityManager());

        // 设置登录页和未授权跳转页
        filterFactoryBean.setLoginUrl("/login");      // 认证失败跳转的URL
        filterFactoryBean.setUnauthorizedUrl("/403"); // 权限不足跳转的URL

        // 配置过滤器链(顺序敏感!)
        Map<String, String> filterChainMap = new LinkedHashMap<>();
        
        // 允许匿名访问的路径(anon)
        filterChainMap.put("/login", "anon");       // 登录页
        filterChainMap.put("/static/**", "anon");   // 静态资源
        filterChainMap.put("/public/**", "anon");   // 公共接口

        // 需要认证的路径(authc)
        filterChainMap.put("/user/**", "authc");    // 用户相关接口
        filterChainMap.put("/admin/**", "authc");   // 管理员接口

        // 其他路径默认需要认证(谨慎使用)
        filterChainMap.put("/**", "authc");         // 所有未匹配路径需认证

        filterFactoryBean.setFilterChainDefinitionMap(filterChainMap);
        return filterFactoryBean;
    }
}

错误1:所有路径配置为 anon

// 错误配置:所有路径允许匿名访问(无认证)
filterChainMap.put("/**", "anon");
//风险:攻击者可直接访问敏感接口(如 /admin/delete)。

错误2:路径匹配顺序错误

filterChainMap.put("/**", "authc");    // 匹配所有路径
filterChainMap.put("/login", "anon"); // 此配置不会生效(因顺序在后)

SQL注入

现在大部分项目都是基于mybatis操作数据库,不使用预编译的情况就可能会导致sql注入漏洞。

简单介绍一下预编译与拼接:

占位符:#{},预编译指的是在执行 SQL 语句之前,先将 SQL 语句中的占位符(如 ?)替换为占位符对应的实际值,然后将这个已经编译好的 SQL 语句发送给数据库执行。

拼接符:${},可以用来替换 SQL 语句中的任何部分,包括表名、列名、条件等等。在执行 SQL 语句之前,MyBatis 会将 ${} 中的内容替换为相应的参数值,然后将得到的 SQL 语句发送给数据库执行。

mybatis中有些地方不能使用预编译的,这种场景下就容易出现sql注入漏洞:

动态 SQL 中的表名、列名:如果在动态 SQL 中使用 ${} 来表示表名、列名等标识符,因为这些标识符是在 SQL 解析阶段确定的,无法使用预编译参数来替换。
动态 SQL 中的 SQL 语句片段:例如在 <sql> 或 <selectKey> 等元素中使用 ${},这些片段是在 SQL 解析阶段确定的,也无法使用预编译参数来替换。
动态 SQL 中的 ORDER BY 字段:如果在 ORDER BY 子句中使用 ${} 来表示排序字段,因为排序字段是在 SQL 解析阶段确定的,同样无法使用预编译参数来替换。
LIKE 操作中的模糊查询字符串:如果在 LIKE 操作中使用 ${} 来表示模糊查询的字符串,因为这个字符串是直接拼接到 SQL 语句中的,不会被预编译。

漏洞点1:
如下:模糊查询处无法直接使用预编译,直接使用预编译会报错。

点击查看代码
错误示例(直接拼接模糊查询字符串)

<!-- LIKE 模糊查询(直接拼接参数) -->
<select id="searchUsers" resultType="User">
    SELECT * FROM users
    WHERE name LIKE '%${keyword}%'
</select>
风险:若 keyword 参数为 ' OR 1=1 --,最终 SQL 会变为 LIKE '%' OR 1=1 --%',绕过条件限制。

//修复方案(使用 #{} + CONCAT)

<!-- 正确使用预编译 -->
<select id="searchUsers" resultType="User">
    SELECT * FROM users
    WHERE name LIKE CONCAT('%', #{keyword}, '%')
</select>

或 Java 层预处理:

// 在 Java 层添加通配符
String keyword = "%" + userInput + "%";
Map<String, Object> params = new HashMap<>();
params.put("keyword", keyword);
sqlSession.selectList("searchUsers", params);
例如: 根据此处的sql语句,跟进查看哪个函数调用了该sql;

image

继续跟进:
image
发现了是page调用了list,而且name可控,继续跟进是哪个函数调用了page。
image

发现了是controller层的page调用了,访问的接口为emps,即http://127.0.0.1/emps,而且name参数可控。
image

漏洞点2
order by后是无法使用预编译的,这种地方也容易存在sql注入。
image

通过上面说的方法,一步一步跟,查看是那个访问接口调用了该sql语句(此处省略)此处asc参数为漏洞点,输入asc=asc,id,(asc=asc,sql列名),回显正常。
image

输入asc=asc,xxx,(asc=asc,不存在的sql列名),无回显数据。
image

SSRF

现在大部分java代码中的ssrf漏洞都不支持伪协议,基本只能进行内网探测,危害也相对较低。
如下:
image
这段代码只支持http请求,无法进行伪协议。

关键字:
HttpClient
HttpClients
HttpURLConnection
openConnection
支持伪协议函数:
openConnectionURL
ConnectionopenStream

文件操作类型漏洞

文件操作类型漏洞包括:文件上传,文件下载,文件读取,文件删除等。漏洞示例:文件名file可控而且没有对后缀进行过滤,存在文件上传漏洞,文件操作类型漏洞在白盒中还是挺多的,大多都是文件上传目录穿越。
image

image

关键字:
new FileOutputStream
download
upload
File.createTempFile
transferTo
new FileInputStream
IOUtils.readFully
IOUtils.write
FileReader
fs.open
file.exists()
file.delete()

XXE

xxe漏洞现在已经不多了,遇到的次数也很少,一般出现在支持xml文件导入或者csv,xslx文件导入(POI组件)的地方。漏洞示例:这段代码读取xml文件,但没有明确禁用外部实体解析,所以存在xxe漏洞。
image

修复方法:

SAXReader reader = new SAXReader();// 这是优先选择. 如果不允许DTDs (doctypes) ,几乎可以阻止所有的XML实体攻击
setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);// 如果不能完全禁用DTDs,最少采取以下措施,必须两项同时存在
setFeature("http://xml.org/sax/features/external-general-entities", false);// 防止外部实体
POCsetFeature("http://xml.org/sax/features/external-parameter-entities", false);// 防止参数实体POC
关键字:
SAXReader
SAXBuilder
XMLReaderFactory.createXMLReader()	
DocumentBuilderFactory
XPathExpression
DocumentHelper.parseText
TransformerFactory
Unmarshaller
StringReader
组件:POI < 3.11 DOS XXE

RCE

存在可以执行命令或者代码的函数就可能存在RCE漏洞。

漏洞案例:

在该接口中将接口传参未做过滤直接传递到继承了FelEngineImpl类的工具类中执行并返回结果,可以通过传入如导致代码注入从而执行任意命令
image

image
image

关键字:
ProcessBuilder
exec
system()
command
Runtime.getRuntime().exec()
Process
UNIXProcess
ProcessImpl
ProcessBuilder.start()
GroovyShell.evaluate()
eval
classLoader
$$BCEL$$
ServiceLoader
ToolProvider.getSystemJavaCompiler()
getSystemClassLoader
JavaFileObject
JdbcRowSetImpl
TemplatesImpl
TransformerFactoryImpl
resolveClass
loadClass
javax.el.ELProcessor

逻辑缺陷

逻辑缺陷一般出在判断条件处,例如esle if,动态sql中的if判断。若开发写的if判断条件有逻辑问题,就会出现漏洞。

漏洞案例:

这段动态sql语句中的if判断条件,判断id是否为空,不为空就删除指定id的数据。但是如果用户输入的id参数为空,这会导致生成一个类似于 delete from dish where id 的 SQL 查询语句。在这种情况下,没有指定具体的条件来限制删除操作,因此这个删除语句会删除整个表中的数据,而不管 id 参数是否为空

image

posted @ 2025-05-14 15:03  猫鳍  阅读(40)  评论(0)    收藏  举报