首页 > 编程语言 >Java代码审计-SSRF

Java代码审计-SSRF

时间:2024-01-29 16:01:05浏览次数:37  
标签:审计 Java SSRF java url http URL new import

SSRF漏洞

SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内部服务器系统。

支持的协议

file
ftp
mailto
http
https
jar
netdoc

Java 中能发起网络请求的类:

HttpClient 类
HttpURLConnection 类
URLConnection 类
URL 类
OkHttp 类
ImageIO 类
Request 类 (Request 是对 HttpClient 类进行了封装的类,类似于 Python 的 requests 库。)

其中,仅支持 HTTP/HTTPS 协议的类(即类名或封装的类名带 http):

HttpClient 类
HttpURLConnection 类
OkHttp 类
Request 类

支持 sun.net.www.protocol 所有协议的类:

URLConnection 类
URL 类
ImageIO 类

在Java中,sun.net.www.protocol包含了一些用于处理不同网络协议的类。然而,需要注意的是,sun.net.www.protocol包是Sun/Oracle JDK的内部实现细节,它并不是Java平台的公共API的一部分。因此,这些类可能在不同的JDK版本中有所变化,而且它们并不受 Java 官方支持,可能在将来的版本中会被移除。

以下是一些可能存在的sun.net.www.protocol包中的协议类的示例,但这并不是一个完整的列表,具体的类可能会因 JDK 版本而异:

  1. HTTP 协议:
  • sun.net.www.protocol.http.HttpURLConnection
  1. HTTPS 协议:
  • sun.net.www.protocol.https.HttpsURLConnectionImpl
  1. FTP 协议:
  • sun.net.www.protocol.ftp.FtpURLConnection
  1. Jar 协议:
  • sun.net.www.protocol.jar.JarURLConnection
  1. File 协议:
  • sun.net.www.protocol.file.FileURLConnection

请注意,使用这些类可能会导致你的代码对特定的JDK版本产生依赖,并且在未来的版本中可能会出现问题。推荐使用Java平台提供的标准API,如java.net.URLjava.net.HttpURLConnection,以确保更好的可移植性和稳定性。

以上内容由AI生成

程序中发起 HTTP 请求操作一般在获取远程图片、页面分享收藏等业务场景, 在代码审计时可重点关注一些 HTTP 请求操作函数,如下:

审计关键词

HttpClient.execute
HttpClient.executeMethod
HttpURLConnection.connect
HttpURLConnection.getInputStream
URL.openStream
URLConnection.getInputStream
Request.Get.execute
Request.Post.execute
ImageIO.read
OkHttpClient.newCall.execute
HttpServletRequest
BasicHttpRequest

漏洞代码

漏洞代码 1
package com.example;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;

@WebServlet("/ssrf1")
public class ssrf1Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");
        resp.setContentType("text/html; charset=utf-8");
        String url = req.getParameter("url");
        System.out.println(url);
        StringBuffer sb = new StringBuffer();
        URL pic = new URL(url);
        URLConnection urlConnection = pic.openConnection();
        BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(),"UTF-8"));
        String line;
        while ((line =in.readLine())!=null){
            sb.append(line);
        }
        in.close();
        resp.getWriter().write(sb.toString());
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req,resp);
    }
}

访问百度
CleanShot 2024-01-22 at 14.38.48.png
访问本机文件
CleanShot 2024-01-22 at 14.40.19.png

http://localhost:8080/ssrf1?url=file:///Users/Oi/Downloads/_%E6%9C%AA%E5%91%BD%E5%90%8D.txt
漏洞代码 2
package com.example;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import sun.net.www.http.HttpClient;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;

@WebServlet("/ssrf2")
public class ssrf2Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String  url =req.getParameter("url");
        String content=null;
        CloseableHttpClient httpclinet = HttpClients.createDefault(); //限制协议只能扫描内容
        HttpGet httpGet = new HttpGet(url);
        CloseableHttpResponse execute = httpclinet.execute(httpGet);
        if(execute.getStatusLine().getStatusCode()==200){
            HttpEntity entity = execute.getEntity();
            content = EntityUtils.toString(entity, "utf-8");
        }
        resp.getWriter().write(content);
        execute.close();
        httpclinet.close();

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req,resp);
    }
}

ImageIO ssrf
package com.example;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageInputStream;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

public class ssrf {
    public static BufferedImage read(URL url) throws IOException {
        if (url == null) {
            System.out.println("输入内容为空");
        }

        InputStream istream = url.openStream();
        ImageInputStream stream =  ImageIO.createImageInputStream(istream);  //获取文件流


        BufferedImage bi = ImageIO.read(stream);  //返回 BufferedImage作为供给的解码结果

        return bi;
    }
}

package com.example;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

@WebServlet("/ssrf3")
public class ssrf3Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String geturl = req.getParameter("url");
        ServletOutputStream outputStream = resp.getOutputStream();
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        URL url = new URL(geturl);
        BufferedImage image = ssrf.read(url);

        ImageIO.write(image, "png", os);
        InputStream input = new ByteArrayInputStream(os.toByteArray());
        int len;
        byte[] bytes = new byte[1024];
        while ((len = input.read(bytes)) > 0) {
            outputStream.write(bytes, 0, len);
        }

    }
}

可以判断文件是否存在
72.png
73.png

常见的漏洞代码

String url = request.getParameter("picurl");
StringBuffer response = new StringBuffer();

URL pic = new URL(url);
HttpURLConnection con = (HttpURLConnection) pic.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", "Mozilla/5.0");
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
    response.append(inputLine);
}
in.close();
modelMap.put("resp",response.toString());
return "getimg.htm";
URLConnection类
//urlConnection ssrf vul
String url = request.getParameter("url");
URL u = new URL(url);
URLConnection urlConnection = u.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); //发起请求,触发漏洞
String inputLine;
StringBuffer html = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
    html.append(inputLine);
}
System.out.println("html:" + html.toString());
in.close();
ImageIO类
// ImageIO ssrf vul
String url = request.getParameter("url");
URL u = new URL(url);
BufferedImage img = ImageIO.read(u); // 发起请求,触发漏洞
其他类

// Request漏洞示例
String url = request.getParameter("url");
return Request.Get(url).execute().returnContent().toString();//发起请求

// openStream漏洞示例
String url = request.getParameter("url");
URL u = new URL(url);
inputStream = u.openStream();  //发起请求


// OkHttpClient漏洞示例
String url = request.getParameter("url");
OkHttpClient client = new OkHttpClient();
com.squareup.okhttp.Request ok_http = new com.squareup.okhttp.Request.Builder().url(url).build();
client.newCall(ok_http).execute();  //发起请求

// HttpClients漏洞示例
String url = request.getParameter("url");
CloseableHttpClient client = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(url);
HttpResponse httpResponse = client.execute(httpGet); //发起请求

修复建议

  1. 设置内网ip黑名单(正确判定内网ip、正确获取host)
    
  2. 禁止30x跳转(跟随跳转需要从1开始重新检测)
    
  3. 限制请求的端口为http常用的端口,如 80、443、8080、8090等
    
  4. 去除url中的特殊字符
    
  5. 如果是域名的话,可以将url中的域名改为ip
    
  6. 根据请求来源,判定请求地址是否是固定请求来源,若是,则将这几个特定的域名/IP 添加到白名单,并拒绝白名单域名/IP 之外的请求
    
  7. 若业务需求和请求来源并不固定,则可以自己编写一个 ssrfCheck 函数,检测特定的域名、判断是否是内网 IP、判断是否为 http/https 协议等
    
  8. 请求时设置host header为ip 
    
  9. 统一错误信息,避免用户根据错误信息来判断远端服务器的端口状态
    
  10. 根据业务需求,判定所需的域名是否是常用的几个,若是,则将这几个特定的域名加入白名单,并拒绝白名单域名之外的请求
    

标签:审计,Java,SSRF,java,url,http,URL,new,import
From: https://www.cnblogs.com/Gp3r/p/17994718

相关文章

  • Java代码审计-XXE
    一、XXE漏洞简介XXE(XML外部实体注入,XMLExternalEntity),在应用程序解析XML输入时,当允许引用外部实体时,可构造恶意内容,导致读取任意文件、探测内网端口、攻击内网网站、发起DoS拒绝服务攻击、执行系统命令等。Java中的XXE支持sun.net.www.protocol里的所有协议:http,https,file,f......
  • Java代码审计-FileUpload
    Web应用通常都会包含文件上传功能,用户可以将其本地的文件上传到Web服务器上。如果服务器端没有能够正确的检测用户上传的文件类型是否合法(例如上传了jsp后缀的WebShell)就将文件写入到服务器中就可能会导致服务器被非法入侵。漏洞成因后缀名无限制//导入必要的类库package......
  • javax.annotation.Nullable找不到
    您需要包括一个存在该类的罐子。您可以在这里找到它如果使用Maven,则可以添加以下依赖项声明:<dependency><groupId>com.google.code.findbugs</groupId><artifactId>jsr305</artifactId><version>3.0.2</version></dependency>对于Gradle:dependencies......
  • Windows下安装和配置Java JDK
    1、......
  • 配置java环境(Redhat)
    安装前准备:下载java的Jdkhttps://www.oracle.com/java/technologies/downloads/   (jdk-8u202-linux-x64.tar.gz)1.查看系统是否有java环境: java-version2.如果有版本输出则需要卸载之前的jdk,找出安装的jdk: rpm-qa|grepjdk3.根据 rpm-qa|grepjdk命令列出的......
  • JVM(Java虚拟机) 整理
    JVM整体结构本文主要说的是HotSpot虚拟机,JVM全称是JavaVirtualMachine,中文译名:Java虚拟机简化一下:Java字节码文件Class文件本质上是一个以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑的排列在Class文件中,JVM根据其特定的规则解析该二进制数据,从而得到......
  • java中二分查找前提必须是升序吗?
    二分查找不必须是升序,降序排列的数组也可以执行二分查找。二分查找算法是一种高效的搜索方法,它要求数据集是有序的,无论是升序还是降序都可以。在升序排列的情况下,算法会将目标值与中间值比较,如果目标值较小,则在左半部分继续查找;如果目标值较大,则在右半部分继续查找。在降序排列的......
  • 【干货】一文掌握JavaScript检查对象空值的N种技巧!
    在开发JavaScript应用程序时,经常需要检查对象是否为空。这是因为在处理和操作对象数据时,我们需要确保对象包含有效的值或属性。以下是一些常见情况,我们需要检查JavaScript对象是否为空:防止空引用错误:当我们尝试访问或使用一个空对象时,可能会导致空引用错误(如TypeError:Cann......
  • 【干货】一文掌握JavaScript检查对象空值的N种技巧!
    在开发JavaScript应用程序时,经常需要检查对象是否为空。这是因为在处理和操作对象数据时,我们需要确保对象包含有效的值或属性。以下是一些常见情况,我们需要检查JavaScript对象是否为空:防止空引用错误:当我们尝试访问或使用一个空对象时,可能会导致空引用错误(如TypeError:Can......
  • 深入浅出Java多线程(二):Java多线程类和接口
    引言大家好,我是你们的老伙计秀才!今天带来的是[深入浅出Java多线程]系列的第二篇内容:Java多线程类和接口。大家觉得有用请点赞,喜欢请关注!秀才在此谢过大家了!!!在现代计算机系统中,多线程技术是提升程序性能、优化资源利用和实现并发处理的重要手段。特别是在Java编程语言中,多线程机......