0x00 前提

主要是因为自己的学习Java 代码审计中的学习思路吧,主要自己一个人学习,有点闭门造车,百度学习法,但是还是记录一下,也分享一下,也便于将来的总结和反思,如果我能终能学到什么,我也会重新梳理思路,为那些自学者提供一个好的思路,所以有了下面的系列文章java代码审计自学篇。

这个是因为刚刚造轮子,学习了一下Java的GUI是怎么写的,造了一个轮子,要写一个爬虫,由于中间出现了小bug,看了看网络请求这块,后来发现顺便就是把SSRF这个漏洞就一起研究。

0x01 SSRF漏洞

SSRF(Server-Side Request Forge, 服务端请求伪造),攻击者让服务端发起指定的请求,SSRF攻击的目标一般是从外网无法访问的内网系统。

这个不必多说了,直接copy吧

Java中的SSRF和PHP的有点区别:协议支持少一些,而且部分协议是受限的比如gopher协议,所以总体上来说Java的SSRF危害肯没PHP那么大。

通常 ssrf 容易出现的功能点,还是和php那些都一样:

基本上都是发起url请求的地方:

1、通过关键字 share、url、link、src、source、target、display、3g、target、domain、u

2、通过URL地址加载

3、下载图片、文章收藏功能

4、通过url 地址分享文章

0x02 详情介绍

最开始是看到了URLConnection写的爬虫,后来发现这个算是比较原始的了,相当于直接请求出去,接受回来的字节码的流文件,没啥处理,直接接受,后面都得自己处理,比如 charset都得自己去匹配,要不又的是GBK有的是UTF-8的,写的好烦

第一种:URLConnection 发起的请求

支撑的协议有

1
file ftp mailto http https jar netdoc gopher

注意:

gopher 实际在 jdk8 版本以后被阉割了,所以没有PHP那种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
29
30
31
32
33
34
35
36
37
38
39
40
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;

class URLConnectionDemo {

public static void main(String[] args) throws IOException {

URL url = new URL("https://www.baidu.com");
// 打开和url之间的连接
URLConnection connection = url.openConnection();
// 设置请求参数 键-通过该请求是已知的(例如,“关键字Accept ”)
connection.setRequestProperty("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36");
//设置指定的超时值
connection.setConnectTimeout(1000);
//如果是写爬虫的话,最后加上,要不一直抛出异常重试,实测如果写特别影响效率,尤其是全网乱爬
//将读超时设置为指定的超时,以毫秒为单位
connection.setReadTimeout(1000);
// 建立实际连接
connection.connect();

// 获取响应头字段信息列表
connection.getHeaderFields();
System.out.println(connection.getHeaderFields());

StringBuilder response = new StringBuilder();
//获取流到缓冲区
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;


while ((line = in.readLine()) != null) {
response.append(line);
}

System.out.print(response.toString());
}
}

1、URL 建立一个对象, 调用openConnection 来获取一个 URLConnection 的实例

2、然后设置各种请求参数以及一些配置

3、使用其中的 connect 方法来发起请求,用 getInputStream 来获请求的响应流

4、最后接收自行处理

漏洞点

如果 URL 是可控的,那么就会存在 SSRF 漏洞

如果中间存在这句话,就不能使用gopher协议, 因为到不了发起请求的连接之前就会抛出异常中断

1
con.setRequestMethod("GET");

漏洞利用

URL 是可控的,file协议读取etc/passwd

1
URL url = new URL("file:///etc/passwd");

image-20200731140914542

第二种:限制过的http请求

还有一些封装过的http请求,这些其实都做过限制,或者要换协议直接抛异常了,所以鸡肋一些

大概就只能做内网探测了

1
2
3
4
5
6
HttpClient.execute
HttpClient.executeMethod
HttpURLConnection.connect
HttpURLConnection.getInputStream
URL.openStream
Request.Get(url).execute()

HttpClients漏洞示例

我后来改成这个做了爬虫,这个感觉兼容性不错的。

1
2
3
4
5
String url = request.getParameter("url");
CloseableHttpClient client = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(url);
//发起请求
HttpResponse httpResponse = client.execute(httpGet);

0x03 漏洞修复

  • 限制协议为HTTP、HTTPS协议。

  • 禁止URL传入内网IP或者设置URL白名单。

302跳转这个问题是,Java会默认跟随跳转,但是跳转是有协议限制的,gopher都不行,所以限制上面那些就可以了。

0x04 总结

总的来说,Java的SSRF 漏洞比较受到限制,而且大家也比较少用原生的,封装过的用多一些?

大概率只能:

  • 利用file协议任意文件读取 (限制在URLConnection这种方式)
  • 利用http协议端口探测
  • 利用 http 进行 ntlmrelay 攻击 (这种大家自己研究一下吧。。。)

Reference

凌天实验室–园长 Github javaweb-sec

https://joychou.org/java/javassrf.html