Java代码审计之SSRF&&XXE

Java 中支持的协议

Java网络请求支持的协议包括:http,https,file,ftp,mailto,jar,netdoc。

1、HttpClient

HttpClient 是 Apache Jakarta Common 下的子项目,可以用来提供高效的、昀新的、功能丰富的支持HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议昀新的版本和建议。

HttpClient 实现了 HTTP1.0 和 HTTP1.1。也实现了 HTTP 全部的方法,如: GET, POST, PUT, DELETE, HEAD, OPTIONS, TRACE 。

2、HttpAsyncClient

HttpAsyncClient 是一个异步的 HTTP 客户端开发包,基于 HttpCore NIO 和 HttpClient 组件。

HttpAsyncClient 的出现并不是为了替换 HttpClient,而是作为一个补充用于需要大量并发连接,对性能要求非常高的基于 HTTP 的原生数据通信,而且提供了事件驱动的 API。

3、java.net.URLConnection

java.net.URLConnection,是 Java 原生的 HTTP 请求方法。URLConnection 类包含了许多方法可以让你的 URL 在网络上通信。此类的实例既可用于读取URL所引用的资源,也可用于写入URL所引用资源。

4、java.net.HttpURLConnection

HttpURLConnection 继承自 URLConnection。可以向指定网站发起GET或POST请求。

5、java.net.URL

在 java.net 包中定义了 URL 类,该类用来处理有关 URL 的内容。通过使用 URL 对象的 openStream() 方法创建打开指定 URL 链接,以获取输入流资源内容。

6、java.net.Socket

java.net.Socket 是 Java 套接字编程使用的类。提供了两台计算机之间的通信机制。在Java代码审计中,我们可能会遇见使用Socket判断IP与端口连通性的代码。如果IP和端口接受外部输入,那么极有可能存在SSRF漏洞。

7、OkHttp

OKHttp 是一个网络请求框架,OKHttp会为每个客户端创建自己的连接池和线程池。重用连接和线程可以减少延迟并节省内存。OkHttp中请求方式分为同步请求( client.newCall(request).execute())和异步请求( client.newCall(request).enqueue() )两种

8、ImageIO

ImageIO 是Java读写图片操作的一个类。在代码审计中,如果目标使用了 ImageIO.read 读取图片,且读取的图片地址可控的话,可能会存在SSRF漏洞。

9、Hutool

Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅。

在Hutool中,也实现了HTTP客户端,Hutool-http针对JDK的HttpUrlConnection做一层封装,简化了HTTPS请求、文件上传、Cookie记忆等操作,使Http请求变得无比简单。

Hutool-http的核心集中在两个类:

  1. HttpRequest
  2. HttpResponse

10、 Jsoup
Jsoup 是基于 Java 的 HTML 解析器,可以从指定的 URL 中解析 HTML 内容

11、RestTemplate

RestTemplate 是从Spring3.0 开始支持的一个HTTP 请求工具,它提供了常见的REST请求方案的模版,例如GET 请求、POST 请求、PUT 请求等等。从名称上来看,是更针对RESTFUL风格API设计的。但通过他调用普通的HTTP接口也是可以的。

SSRF审计关键字:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
HttpRequest.get
HttpRequest.post
Jsoup.connect
getForObject
RestTemplate
postForObject
httpclient
execute
HttpClients.createDefault
httpasyncclient
HttpAsyncClients.createDefault
java.net.URLConnection
openConnection
java.net.HttpURLConnection
openStream
openConnection
Socket
java.net.Socket
okhttp
OkHttpClient
newCall
ImageIO.read
javax.imageio.ImageIO
HttpRequest.get
jsoup
Jsoup.connect
RestTemplate
org.springframework.web.client.RestTemplate

防御:
重写底层代码(Socket connect)增加IP是否在内网的判断代码,如果是进行报错,可以有效防范

XXE代审

1.XML介绍

XML (Extensible Markup Language) 是一种可扩展的标记语言,用于标记电子文件中的各种元素。它是用来传输和存储数据的一种常用方式(html用来展示的),并且可以被很多不同的应用程序所使用。

XML 的基本概念是标记,它使用标签来描述文档中的元素。每个标签都有一个名称,并且可以包含属性和值。

XML 的一个主要优点是它允许不同的应用程序之间进行数据交换,因为它是一种通用的数据格式。它还可以用于存储数据,并且可以使用 XML 文档来描述数据的结构。

XML 在许多不同的领域都有广泛的应用,包括电子商务、计算机技术、生物学和其他领域。它是一种流行的数据格式,并且被广泛使用。

Java中的XXE支持 sun.net.www.protocol 里面的所有协议:http,https,file,ftp,mailto,jar,netdoc 。

通常可以使用以下协议来发起XXE攻击:

  1. file:允许通过文件系统访问本地文件。
  2. http:允许通过HTTP协议访问远程服务器上的文件。
  3. https:允许通过HTTPS协议访问远程服务器上的文件。
  4. ftp:允许通过FTP协议访问远程服务器上的文件。
1
2
3
4
5
<?xml version="1.0"?>
<!DOCTYPE root [
 <!ENTITY file SYSTEM "file:///etc/passwd">
]>
<root>&file;</root>

2、DTD

DTD(Document Type Definition)是文档类型定义的缩写。它是一种用来定义XML文档结构的文本文件,用于描述XML文档中元素的名称、属性和约束关系。DTD可以帮助浏览器或其他应用程序更好地解析和处理XML文档。

漏洞解析:

1、DOM 解析

DOM的全称是Document Object Model,也即文档对象模型。DOM 解析是将一个 XML 文档转换成一个 DOM 树,并将 DOM 树放在内存中。

使用大致步骤:

  1. 创建一个 DocumentBuilderFactory 对象
  2. 创建一个 DocumentBuilder 对象
  3. 通过 DocumentBuilder 的 parse() 方法加载 XML
  4. 遍历 name 和 value 节点
1
2
3
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse(is);

2、SAX 解析

SAX 的全称是 Simple APIs for XML,也即 XML 简单应用程序接口。与 DOM 不同,SAX 提供的访问模式是一种顺序模式,这是一种快速读写 XML 数据的方式。

使用大致步骤:

  1. 获取 SAXParserFactory 的实例
  2. 获取 SAXParser 实例
  3. 创建一个 handler() 对象
  4. 通过 parser 的 parse() 方法来解析 XML
1
2
3
4
5
6
7
一.
SAXParserHandler handler = new SAXParserHandler(); //解析xml
parser.parse(new InputSource(new StringReader(body)), handler);

二.
SAXReader reader = new SAXReader();
reader.read(new InputSource(new StringReader(body)));

3、JDOM 解析

JDOM 是一个开源项目,它基于树型结构,利用纯 JAVA 的技术对 XML 文档实现解析、生成、序列化以及多种操作。

使用大致步骤:

  1. 创建一个 SAXBuilder 的对象
  2. 通过 saxBuilder 的 build() 方法,将输入流加载到 saxBuilder 中
1
2
3
4
5
6
JDOM 需要在 pom.xml 文件中引入该依赖
<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom</artifactId>
<version>1.1.3</version>
</dependency>
1
2
SAXBuilder builder = new SAXBuilder();
builder.build(new InputSource(new StringReader(body)));

4、DOM4J 解析

Dom4j 是一个易用的、开源的库,用于XML,XPath 和 XSLT。它应用于Java平台,采用了Java集合框架并完全支持 DOM,SAX 和 JAXP。是 Jdom 的升级品

使用大致步骤:

  1. 创建 SAXReader 的对象 reader
  2. 通过 reader 对象的 read() 方法加载 xml 文件
1
2
3
4
5
6
依赖
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6</version>
</dependency>
1
2
SAXReader reader = new SAXReader();
reader.read(new InputSource(new StringReader(body)));

5、Digester 解析

Digester 是 Apache 下一款开源项目。 目前最新版本为 Digester 3.x 。

Digester 是对 SAX 的包装,底层是采用的是 SAX 解析方式

使用大致步骤:

  1. 创建 Digester 对象
  2. 调用 Digester 对象的 parse() 解析 XML
1
2
3
4
5
<dependency>
<groupId>commons-digester</groupId>
<artifactId>commons-digester</artifactId>
<version>2.1</version>
</dependency>
1
2
Digester digester = new Digester();
digester.parse(new StringReader(body));

靶场复现:

xxedemo靶场:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.example.xxedemo;

import org.dom4j.io.SAXReader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.xml.sax.InputSource;

import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.io.StringReader;

/**
* 编号7089
*/
@RestController
public class DOM4JTest {

@RequestMapping("/dom4jdemo/vul")
public String dom4jDemo(HttpServletRequest request) {
try {
//获取输入流
InputStream in = request.getInputStream();
String body = convertStreamToString(in);

SAXReader reader = new SAXReader();
reader.read(new InputSource(new StringReader(body)));
return "DOM4J XXE......";
} catch (Exception e) {
return "EXCEPT ERROR!!!";
}
}
public static String convertStreamToString(java.io.InputStream is) {
java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
}

访问路径:http://127.0.0.1:8886/dom4jdemo/vul

关键字:SAXReader符合DOM4J 解析 并没有会XXE进行防护

抓包:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
GET /dom4jdemo/vul HTTP/1.1
Host: 127.0.0.1:8886
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Upgrade-Insecure-Requests: 1
Sec-Fetch-Mode: navigate
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:139.0) Gecko/20100101 Firefox/139.0
Cookie: JSESSIONID=C6223D7ACFF84109FA5B62818C028CEA; remember-me=YWRtaW46MTc1MDczMTMxNjU2Njo2M2MzM2U1NTc0NDc0NjE2Mjc3NGIwYjVmMzEwNjgwOQ; XSRF-TOKEN=40496df0-4bfb-4b2a-b7d4-50cf6715dc75
Sec-Fetch-Site: none
Priority: u=0, i
Accept-Encoding: gzip, deflate, br, zstd
Sec-Fetch-Dest: document
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

改为POST,修改Content-Type值为:text/xml,并在请求体中加上paylod,可以读取本地文件

1
2
3
4
5
6
7
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY file SYSTEM "file:///D:/abc/demo.txt">
]>
<root>
&file;
</root>

XXE 漏洞审计函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
XMLReaderFactory
createXMLReader
SAXBuilder
SAXReader
SAXParserFactory
newSAXParser
Digester
DocumentBuilderFactory
DocumentBuilder
XMLReader
DocumentHelper
XMLStreamReader
SAXParser
SAXSource
TransformerFactory
SAXTransformerFactory
SchemaFactory
Unmarshaller
XPathExpression
javax.xml.parsers.DocumentBuilder
javax.xml.parsers.DocumentBuilderFactory
javax.xml.stream.XMLStreamReader
javax.xml.stream.XMLInputFactory
org.jdom.input.SAXBuilder
org.jdom2.input.SAXBuilder
org.jdom.output.XMLOutputter
oracle.xml.parser.v2.XMLParser
javax.xml.parsers.SAXParser
org.dom4j.io.SAXReader
org.dom4j.DocumentHelper
org.xml.sax.XMLReader
javax.xml.transform.sax.SAXSource
javax.xml.transform.TransformerFactory
javax.xml.transform.sax.SAXTransformerFactory
javax.xml.validation.SchemaFactory
javax.xml.validation.Validator
javax.xml.bind.Unmarshaller
javax.xml.xpath.XPathExpression
java.beans.XMLDecoder

**XXE **漏洞防御

目前常用的修复方案为 setFeature。设置 setFeature 打开或关闭一些配置,进而防御 XXE 攻击。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 @RequestMapping(value = "/Digester/sec", method = RequestMethod.POST)
   public String DigesterSec(HttpServletRequest request) {
       try {
           String body = WebUtils.getRequestBody(request);
           logger.info(body);
           Digester digester = new Digester();
           
           digester.setFeature("http://apache.org/xml/features/disallow-doctypedecl", true);
           digester.setFeature("http://xml.org/sax/features/external-general entities", false);
           digester.setFeature("http://xml.org/sax/features/external-parameterentities", false);
           digester.parse(new StringReader(body));  // parse xml
           return "Digester xxe security code";
      } catch (Exception e) {
           logger.error(e.toString());
           return EXCEPT;
      }
  }

URL跳 转漏洞:

URL重定向漏洞是指当应用程序使用 Java 的内置函数或类来处理 URL 重定向时,如果没有正确地验证输入,则可能允许攻击者构造恶意的 URL 来重定向到恶意网站。这样,攻击者就可以让用户访问恶意网站。

302 重定向之 sendRedirect

1
2
3
4
5
6
7
8
9
10
11
/**
    * http://127.0.0.1:8080/sendRedirect?url=https://www.baidu.com
    */
   @RequestMapping("/sendRedirect")
   @ResponseBody
   public static void sendRedirect(HttpServletRequest request,
HttpServletResponse response) throws IOException {
       String url = request.getParameter("url");
       // 302 跳转
       response.sendRedirect(url);
  }

301 重定向之 setHeader

1
2
3
4
5
6
7
8
9
10
11
12
/**
    * http://localhost:8080/setHeader?url=http://www.baidu.com
    */
  @RequestMapping("/setHeader")
  @ResponseBody
  public static void setHeader(HttpServletRequest request, HttpServletResponse
response) {
      String url = request.getParameter("url");
      // 301 重定向
      response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
      response.setHeader("Location", url);
  }

URL 跳转和 SSRF 漏洞区别

在调试代码时不难发现,URL 跳转动作主要发生在客户端处,也就是以你的浏览器进行访问和你直接使用浏览器访问意思相同。

而 SSRF 漏洞请求 URL 主要发生在服务端处,也就是服务器端请求了 URL,然后将他获取到的资源返回给了你。


Java代码审计之SSRF&&XXE
http://example.com/2025/06/09/Java代码审计之SSRF&&XXE/
作者
XCDH
发布于
2025年6月9日
许可协议