如何成为一个牛逼的脚本小子日记之0x001-JAVA 代码审计 Top half (2023829-202392)
字数 1299 2025-08-10 13:48:25
Java代码审计全面指南:从基础到高级漏洞分析
1. SQL注入漏洞审计
1.1 经典SQL注入
漏洞成因:
- 直接拼接用户输入到SQL语句中
- 使用Statement而非PreparedStatement
典型代码示例:
String sql_command = "select * from db_name where id = " + req.getParamenter("id");
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(sql_command);
1.2 预编译使用不当
错误示例:
String sql_command = "select * from db_name where id = " + req.getParamenter("id");
PreparedStatement pstt = con.prepareStatement(sql_command);
ResultSet rs = pstt.executeQuery();
1.3 框架使用不当
MyBatis注入:
<select id="getUsername" resultType="com.sqltest.bean.user">
select * from user where name = ${name} <!-- 注入点 -->
</select>
Hibernate HQL注入:
List user = session.createQuery("from user where name= '" + req.getParament("insert") + "'", User.class).getResultList();
1.4 审计方法
- 跟踪关键字:
sql,sql_command,sql_query - 寻找SQL拼接入口点
- 回溯构造链:
con.prepareStatement,req.getParamenter,st.executeQuery,pstt.executeQuery
2. 命令注入漏洞审计
2.1 基本命令注入
String Cmd = req.getParament("cmd");
Process process = Runtime.getRuntime().exec(Cmd);
2.2 Runtime.exec的陷阱
Runtime.exec使用StringTokenizer对空白字符截取可能导致注入失效:
// 输入:ping 127.0.0.1&whoami
String[1] = "ping"
String[2] = "127.0.0.1&whoami" // 注入失败
绕过方法:
使用多个空格:
// 输入:ping 127.0.0.1 & whoami
String[1] = "ping"
String[2] = "127.0.0.1"
String[3] = "&"
String[4] = "whoami" // 注入成功
3. 表达式注入漏洞
3.1 EL表达式注入
JSP示例:
<%@page contentType="text/html;charset=UTF-8" language="Java" %>
<html>
<center><h3>name is : ${param.name} </h3></center>
</html>
3.2 Spring SpEL注入
@RequestMapping("/test")
@ResponseBody
public String test(String input) {
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(input);
return expression.getValue().toString();
}
利用方式:
http://127.0.0.1:8080/test?input=new%20java.lang.ProcessBuilder(%22/Applications/Calculator.app/Contents/MacOS/Calculator%22).start()
T()运算符利用:
#{T(java.lang.Runtime).getRuntime().exec('calc')}
4. SSTI (服务器端模板注入)
4.1 FreeMarker模板注入
重点关注类:
freemarker.template.utility.Execute
版本限制:
- 2.3.17+版本提供了三种
TemplateClassResolver:UNRESTRICTED_RESOLVER: 可获取任何类SAFER_RESOLVER: 限制三个危险类ALLOWS_NOTHING_RESOLVER: 不能解析任何类
5. XXE (XML外部实体注入)
5.1 常见漏洞点
javax.xml.parsers.DocumentBuilder
javax.xml.parsers.DocumentBuildFactory
org.xml.sax.EntityResolver
org.dom4j.*
javax.xml.parsers.SAXParser
javax.xml.parsers.SAXParserFactory
TransformerFactory
SAXReader
DocumentHelper
SAXBuilder
SAXParserFactory
XMLReaderFactory
XMLInputFactory
SchemaFactory
DocumentBuilderFactoryImpl
SAXTransformerFactory
DocumentBuilderFactoryImpl
XMLReader
Xerces: DOMParser, DOMParserImpl, SAXParser, XMLParser
5.2 DTD示例
内部DTD:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE scores [
<!ELEMENT scores (student*) >
<!ELEMENT student (name, course, score)>
<!ATTLIST student id CDATA #REQUIRED>
<!ELEMENT name (#PCDATA)>
<!ELEMENT course (#PCDATA)>
<!ELEMENT score (#PCDATA)>
]>
外部DTD:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE scores SYSTEM "scores.dtd">
6. 敏感信息泄露
6.1 典型示例
public static void show(boolean bAjax, HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
PMInterface pm = null;
StringBuffer sb = new StringBuffer();
for (int i = 0; i < alPM.size(); i++) {
pm = alPM.get(i);
sb.append(pm.PM());
sb.append("\r\n");
}
String str = sb.toString();
response.getOutputStream().write(str.getBytes(SysConts.New_InCharSet));
}
7. CSRF漏洞
7.1 Referer检查不严
public class RefererInterceptor extends HandlerInterceptorAdapter {
private Boolean check = true;
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse resp,
Object handler) throws Exception {
if(!check) return true;
String referer = request.getHeader("Referer");
if((referer != null) && (referer.trim().startsWith("www.example.com"))) {
chain.doFilter(request, response);
} else {
request.getRequestDispatcher("index.jsp").forward(request,response);
}
}
}
7.2 Token可重用
String sToken = generateToken();
String pToken = req.getPrameter("csrf-token");
if(sToken != null && pToken != null && sToken.equals(pToken)) {
chain.doFilter(request,response);
} else {
request.getRequestDispatcher("index.jsp").forward(request,response);
}
8. SSRF漏洞
8.1 敏感函数
HttpClient.execute()
HttpClient.executeMethod()
HttpURLConnection.connect()
HttpURLConnection.getInputStream()
URL.openStream()
HttpServerRequest()
BasicHttpEntityEnclosingRequest()
DefaultBHttpClientConnection()
BasicHttpRequest()
9. 文件操作漏洞
9.1 文件包含
静态包含:
<%@include file="test.jsp"%>
动态包含:
<jsp:include page="<%=file%>"></jsp:include>
<jsp:include page="<%=file%>"/>
JSTL包含:
<c:import url="<%=url%>"></c:import>
9.2 文件上传
关注函数:
File.lastIndexOf()
indexOf()
FileUpload
getRealPath()
getServletPath()
getPathInfo()
getContentType()
equalsIgnoreCase()
FileUtils
MultipartFile
MultipartRequest
EntityUpload
HandleServlet
FileLoadServlet
FileOutputStream
getInputStream()
DiskFileItemFactory
9.3 任意文件读取/下载
审计重点:FileInputStream反溯构造链
10. 失效的访问控制
10.1 横向/纵向越权
审计要点:
- HTTP传参构造链
- pom.xml对传入数据的处理
- 用户身份校验缺失
审计方法论总结
- 输入源追踪:从用户输入点开始,跟踪数据流
- 危险函数识别:识别各漏洞类型的敏感函数
- 上下文分析:结合业务逻辑判断漏洞可利用性
- 框架特性理解:掌握各框架的安全机制和绕过方法
- 组合漏洞利用:考虑多个漏洞串联利用的可能性
后续研究方向
- Java反序列化漏洞深入分析
- CC/CB链审计方法
- WebLogic、Fastjson等特定组件反序列化
- WAF绕过技术
- 实战审计案例分析
本指南涵盖了Java代码审计中的主要漏洞类型,从基础注入到高级表达式注入、XXE等,提供了详细的漏洞成因、示例代码和审计方法。实际审计中需要结合具体业务场景和代码实现进行深入分析。