【Java代码审计】SSRF篇

【Java代码审计】SSRF篇

  • 1.SSRF漏洞
  • 2.Java-SSRF漏洞常见接口
  • 3.SSRF漏洞演示
    • URLConnection
    • URLConnection绕过
  • 4.SSRF修复
    • 白名单方式
    • 过滤方式
    • 通用预防SSRF方法

1.SSRF漏洞

SSRF 是 Server-Side Request Forge 的英文首字母缩写,中文意思是服务器端请求伪造。Web 应用程序往往会提供一些能够从远程获取图片或是文件的接口,在这些接口上用户使用指定的 URL 便能完成远程获取图片、下载文件等操作。攻击者可以通过使用 file 协议来读取服务器本地/etc/passwd 和/proc/self/cmdline 等敏感文件,同时攻击者也可以利用被攻击的服务器绕过防火墙直接对处于内网的机器发起进一步的攻击

SSRF漏洞主要有以下几个危害:

  • 获取内网主机、端口和banner信息
  • 对内网的应用程序进行攻击,例如Redis、jboss等
  • 利用file协议读取文件
  • 可以攻击内网程序造成溢出

在这里插入图片描述

在Java中SSRF仅支持sun.net.www.protocol下所有的协议:http、https、file、ftp、mailto、jar及netdoc协议

在这里插入图片描述

正是由于上述协议的限制,以及传入的URL协议必须和重定向后的URL协议一致的原因,使得Java中的SSRF并不能像PHP中一样使用gopher协议来拓展攻击面

在 Java 中可以通过利用 file 协议或 netdoc 协议进行列目录操作,以读取到更多的敏感信息,对于无回显的文件读取可以利用 FTP 协议进行带外攻击,但值得注意的是:部分版本的 Java,即使使用 FTP 协议也无法读取多行文件

在这里插入图片描述


2.Java-SSRF漏洞常见接口

SSRF漏洞通常出现在社交分享、远程图片加载或下载、图片或文章收藏、转码、通过网址在线翻译、网站采集、从远程服务器请求资源等功能点处

SSRF 漏洞 URL 中常出现 url、f、file、page 等参数。SSRF 会使用 HTTP 请求远程地址,因此代码审计时我们要特别留意能够发起 HTTP 请求的类及函数,如

HttpURLConnection.getInputStream
URLConnection.getInputStream
HttpClient.execute
OkHttpClient.newCall.execute
Request.Get.execute
Request.Post.execute
URL.openStream
ImageIO.read

值得注意的是,虽然上面提到的方法都可以发起HTTP请求,导致SSRF漏洞;但若是想支持sun.net.www.protocol中的所有协议,则只能使用以下方法:

URLConnection
URL

若发起网络请求的是带 HTTP 的,那么其将只支持 HTTP、HTTPS 协议

HttpURLConnection
HttpClient
OkHttpClient.newCall.execute

1、urlConnection

urlConnection是一个抽象类,表示指向URL指定资源的活动链接,它有两个直接子类,分别是HttpURLConnection和JarURLConnection。在默认情况下,urlConnection的参数没有有效控制时会引起SSRF漏洞

try {// 从HTTP请求参数中获取名为"url"的URL字符串String url = request.getParameter("url"); // 使用提取到的URL字符串创建一个URL对象URL u = new URL(url);// 打开与该URL的连接URLConnection urlConnection = u.openConnection();// 通过连接获取输入流,并使用BufferedReader逐行读取HTML内容BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));// 读取HTML内容并保存到StringBuffer中String inputLine;StringBuffer html = new StringBuffer(); while ((inputLine = in.readLine()) != null) {html.append(inputLine);}in.close();// 将HTML内容作为字符串返回return html.toString();
} catch(Exception e) {// 如果发生异常,打印异常堆栈跟踪e.printStackTrace(); // 返回"fail"字符串return "fail";
}

2、HttpURLConnection

HttpURLConnection是Java的标准类,它继承自URLConnection,可用于向指定网站发送GET请求与POST请求。同样的,在没有过滤的默认情况下其会产生SSRF漏洞,但是与urlConnection不同的是,它只能利用HTTP、HTTPS协议进行攻击

try {// 从HTTP请求参数中获取名为"url"的URL字符串String url = request.getParameter("url"); // 使用提取到的URL字符串创建一个URL对象URL u = new URL(url);// 打开与该URL的连接URLConnection urlConnection = u.openConnection(); // 将URLConnection转换为HttpURLConnection以支持HTTP特定功能HttpURLConnection httpUrl = (HttpURLConnection)urlConnection;// 通过连接获取输入流,并使用BufferedReader逐行读取HTML内容BufferedReader in = new BufferedReader(new InputStreamReader(httpUrl.getInputStream())); // 读取HTML内容并保存到StringBuffer中String inputLine;StringBuffer html = new StringBuffer();while ((inputLine = in.readLine()) != null) { html.append(inputLine); }in.close();// 将HTML内容作为字符串返回return html.toString();
} catch(Exception e) {// 如果发生异常,打印异常堆栈跟踪e.printStackTrace(); // 返回"error"字符串return "error";
}

3、Request

Request与Python中的request对象类似,其主要用来发送HTTP请求。在没有过滤的默认情况下会产生SSRF漏洞

try {// 从HTTP请求参数中获取名为"url"的URL字符串String url = request.getParameter("url");// 使用提取到的URL字符串创建一个HttpGet请求对象// 使用Apache HttpClient库的Request.Get方法// 通过execute()方法发送请求并获取响应内容// 使用returnContent()方法获取响应内容的字符串表示形式return Request.Get(url).execute().returnContent().toString();
} catch(Exception e) {// 如果发生异常,打印异常堆栈跟踪e.printStackTrace();// 返回"fail"字符串return "fail";
}

4、openStream

通过URL对象的openStream()方法,能够得到指定资源的输入流。这时如果URL对象可控,则会产生SSRF漏洞

try {// 根据URL获取下载的图片文件名,不含扩展名String downLoadImgFileName = Files.getNameWithoutExtension(url) + "." + Files.getFileExtension(url);// 设置响应头,指示浏览器以附件形式下载文件response.setHeader("content-disposition", "attachment;fileName=" + downLoadImgFileName);// 使用URL打开连接URL u = new URL(url);int length;byte[] bytes = new byte[1024];// 打开URL连接的输入流inputStream = u.openStream();// 获取响应输出流,用于向浏览器发送文件内容outputStream = response.getOutputStream();// 读取输入流中的数据,并将其写入响应输出流while ((length = inputStream.read(bytes)) > 0) {outputStream.write(bytes, 0, length);}
} catch (Exception e) {// 如果发生异常,打印异常堆栈跟踪e.printStackTrace();
} finally {// 在finally中关闭输入流和输出流if (inputStream != null) {inputStream.close();}if (outputStream != null) {outputStream.close();}
}

5、HttpClient

HttpClient是Apache Jakarta Common下的一个子项目,用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持HTTP协议最新的版本和建议。但是在默认情况下,其也会产生SSRF漏洞

public class SSRFExample {public static void main(String[] args) {try {String userInputUrl = "http://example.com"; // 用户可控的URL输入CloseableHttpClient httpClient = HttpClients.createDefault();HttpGet httpGet = new HttpGet(userInputUrl);String response = httpClient.execute(httpGet, httpResponse -> {int status = httpResponse.getStatusLine().getStatusCode();if (status >= 200 && status < 300) {return EntityUtils.toString(httpResponse.getEntity());} else {throw new Exception("Unexpected response status: " + status);}});System.out.println(response);httpClient.close();} catch (Exception e) {e.printStackTrace();}}
}

3.SSRF漏洞演示

URLConnection

漏洞代码:

public static String URLConnection(String url) {try {URL u = new URL(url);URLConnection conn = u.openConnection();// 通过getInputStream() 读取 URL 所引用的资源数据BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));String content;StringBuffer html = new StringBuffer();while ((content = reader.readLine()) != null) {html.append(content);}reader.close();return html.toString();} catch (Exception e) {return e.getMessage();}
}

payload,使用file协议读取系统文件:

http://127.0.0.1:8888/SSRF/URLConnection/vul?url=file:///etc/passwd

读取成功:

在这里插入图片描述

URLConnection绕过

SSRF修复经常碰到的问题,虽然过滤了内网地址,但通过短链接跳转、IP进制的方式可以绕过:

public String URLConnection2(String url) {if (!Security.isHttp(url)) {return "不允许非http协议!!!";} else if (Security.isIntranet(Security.urltoIp(url))) {return "不允许访问内网!!!";} else {return HttpClientUtils.URLConnection(url);}
}

绕过:

短链接绕过:
http://127.0.0.1:8888/SSRF/URLConnection/vul2?url=http://xxx-8.cn/0
ip进制绕过:
http://127.0.0.1:8888/SSRF/URLConnection/vul2?url=http://12345678

4.SSRF修复

对于 SSRF 漏洞的修复比较简单,总结下来主要包括以下几点:

  • 正确处理 302 跳转(在业务角度看,不能直接禁止 302,而是对跳转的地址重新进行检查)
  • 限制协议只能为 HTTP/HTTPS,防止跨协议
  • 设置内网 IP 黑名单(正确判定内网 IP、正确获取 host)
  • 在内网防火墙上设置常见的 Web 端口白名单(防止端口扫描,则可能业务受限比较大)

白名单方式

public String URLConnection3(String url) {if (!Security.isHttp(url)) {return "不允许非http/https协议!!!";} else if (!Security.isWhite(url)) {return "非可信域名!";} else {return HttpClientUtils.URLConnection(url);}
}

此时,尝试访问内网IP,被拦截:

在这里插入图片描述

过滤方式

public String HTTPURLConnection(String url) {// 校验 url 是否以 http 或 https 开头if (!Security.isHttp(url)) {log.error("[HTTPURLConnection] 非法的 url 协议:" + url);return "不允许非http/https协议!!!";}// 解析 url 为 IP 地址String ip = Security.urltoIp(url);log.info("[HTTPURLConnection] SSRF解析IP:" + ip);// 校验 IP 是否为内网地址if (Security.isIntranet(ip)) {log.error("[HTTPURLConnection] 不允许访问内网:" + ip);return "不允许访问内网!!!";}// 访问 urltry {return HttpClientUtils.HTTPURLConnection(url);} catch (Exception e) {log.error("[HTTPURLConnection] 访问失败:" + e.getMessage());return "访问失败,请稍后再试!!!";}
}

此时,尝试访问内网IP,被拦截:

在这里插入图片描述

通用预防SSRF方法

private static int connectTime = 5 * 1000; // 连接超时时间,单位为毫秒/*** 检查URL是否存在SSRF漏洞* @param url 要检查的URL* @return 返回是否存在SSRF漏洞,存在返回true,否则返回false*/
public static boolean checkSsrf(String url) {HttpURLConnection httpURLConnection;String finalUrl = url;try {do {// 只允许 http/https 协议if (!Pattern.matches("^https?://.*/.*$", finalUrl)) {return false;}// 判断是否为内网 IPif (isInnerIp(url)) {return false;}// 打开URL连接httpURLConnection = (HttpURLConnection) new URL(finalUrl).openConnection();// 不跟随跳转httpURLConnection.setInstanceFollowRedirects(false);// 不使用缓存httpURLConnection.setUseCaches(false);// 设置超时时间httpURLConnection.setConnectTimeout(connectTime);// 发送DNS请求httpURLConnection.connect();int statusCode = httpURLConnection.getResponseCode();// 如果是重定向状态码,则获取重定向的URLif (statusCode >= 300 && statusCode <= 307 && statusCode != 304 && statusCode != 306) {String redirectedUrl = httpURLConnection.getHeaderField("Location");if (redirectedUrl == null) break;// 获取到跳转之后的 URL,再次进行检查finalUrl = redirectedUrl;} else {break;}} while (httpURLConnection.getResponseCode() != HttpURLConnection.HTTP_OK); // 如果没有返回200,则继续对跳转后的链接进行检查httpURLConnection.disconnect();} catch (Exception e) {// 发生异常,返回true表示存在SSRF漏洞return true;}// 没有发生异常,返回true表示存在SSRF漏洞return true;
}/*** 判断IP地址是否为内网IP* @param url 要判断的URL* @return 返回是否为内网IP,是则返回true,否则返回false*/
private static boolean isInnerIp(String url) throws URISyntaxException, UnknownHostException {URI uri = new URI(url);String host = uri.getHost(); // URL转换为host// 发送DNS请求,host转IP,各种进制也会转换为常见的x.x.x.x格式InetAddress inetAddress = InetAddress.getByName(host);String ip = inetAddress.getHostAddress();// 内网IP段String blackSubnetlist[] = {"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "127.0.0.0/8"};for (String subnet : blackSubnetlist) {SubnetUtils subnetUtils = new SubnetUtils(subnet); // 使用commons-net 3.6if (subnetUtils.getInfo().isInRange(ip)) {return true; // 如果IP在内网段中,则直接返回true}}// 如果IP不在内网段中,则返回falsereturn false;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/589340.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Coze工作流介绍(一)

Coze工作流介绍 工作流支持通过可视化的方式&#xff0c;对插件、大语言模型、代码块等功能进行组合&#xff0c;从而实现复杂、稳定的业务流程编排&#xff0c;例如旅行规划、报告分析等。 当目标任务场景包含较多的步骤&#xff0c;且对输出结果的准确性、格式有严格要求时…

鱼哥赠书活动第17期:看完这本《Python数据分析》菜鸟也能做Python数据分析?

鱼哥赠书活动第17期&#xff1a;看完这本《Python数据分析》菜鸟也能做Python数据分析&#xff1f; 一、Python是办公自动化的重要工具二、Python是提升职场竞争力的利器三、Python是企业数字化的重要平台四、Python是AI发展的重要通道之一内容简介:第一部分&#xff08;第1~7章…

c++|vector使用及模拟实现

目录 一、vector的介绍 二、vector的使用(常用接口) 2.1string类的成员函数 2.1.1构造函数 2.1.2析构函数 2.1.3“”运算符重载函数 2.2 迭代器(iterator) 及 对象的遍历访问 2.2.1iterator 2.2.2 operator[] && at() 2.2.4 back() && front() 2.2…

Node.js环境调用百度智能云(百度云)api鉴权认证三步走

方式一 :Postman脚本的方式生成v1版本的认证字符串 Postman脚本下载 下载Postman pre-request Script 设置 Authorization 示例脚本 方式二&#xff1a;在线签名工具生成 (试用于验证编程字符串签名是否有错误) 签名计算工具 https://cloud.baidu.com/signature/index.html …

【蓝桥杯嵌入式】六、真题演练(一)-1演练篇:第 14 届真题

温馨提示&#xff1a; 真题演练分为模拟篇和研究篇。本专栏的主要作用是记录我的备赛过程&#xff0c;我打算先自己做一遍&#xff0c;把遇到的问题和不同之处记录到演练篇&#xff0c;然后再返回来仔细研究一下&#xff0c;找到最佳的解题方法记录到研究篇。 目录 解题记录&…

索引的概念

索引的概念    1.索引是一种可选的与表相关的数据库对象&#xff0c;用于提高数据的查询效率。    2.索引是一种有序的数据结构。    3.如果一个表没有创建索引&#xff0c;则对该表进行查询时需要进行全表扫描&#xff1b;如果创建了索引&#xff0c;则在有条件查询时…

java 枚举

枚举的格式 枚举是一种特殊的类 枚举类的最开始必须罗列所有类型 枚举类提供了一些父类的方法 values() :获取所有的的枚举对象,是一个数组 public enum A {A1, A2, A3;String name;A() {this.name "default";}String getName() {return name;}void setName(Strin…

AI预测福彩3D第25弹【2024年4月3日预测--第4套算法重新开始计算第10次测试】

今天继续对第4套算法进行测试&#xff0c;因为第4套算法已连续多期命中&#xff0c;相对来说还算稳定。好了&#xff0c;废话不多说了&#xff0c;直接上预测的结果吧~ 2024年4月3日福彩3D的七码预测结果如下 第一套&#xff1a; 百位&#xff1a;1 2 …

Windows系统下配置安装adb与Andriod手机有线和无线通信

目录 一、adb二、adb下载2.1 同版本获取2.2 官网下载 三、添加环境变量四、测试adb是否安装成功五、数据线adb连接手机5.1 开启开发者选项5.2 数据线连接电脑和手机5.2.1 没反应问题 5.3 终端测试 六、无线adb连接手机6.1 设置端口号6.2 添加手机ip地址6.3 测试无线adb连接 七、…

【网站项目】面向学生成绩分析系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

再拓信创生态圈|宁盾身份域管与深信服桌面云完成兼容互认证

近日&#xff0c;宁盾国产化身份域管&#xff08;即身份目录服务软件&#xff09;与深信服桌面云系统aDesk完成产品兼容性互认证。经过共同严格测试&#xff0c;宁盾国产化身份域管能够与深信服桌面云系统兼容对接运行&#xff0c;双方相互兼容&#xff0c;共同为企事业单位提供…

SQLynx发布3.0.0版本:带来更流畅便捷的SQL开发体验

作为新一代的一站式数据库管理开发工具&#xff0c; SQLynx自发布上线以来&#xff0c;一直受到广大用户的好评与鼓励。 为了给用户提供更高效、更便捷、更可靠的数据库管理开发体验&#xff0c;SQLynx今日正式发布3.0.0版本&#xff0c;同步在麦聪软件官网上线&#xff0c;全…