Java代码审计漏洞-SSRF服务器请求伪造

Java代码审计漏洞-SSRF服务器请求伪造

ssrf基础:https://www.cnblogs.com/-meditation-/p/16227632.html

补充一点:SSRF利用的协议PHP和JAVA的有区别,高版本的JAVA可以用file ftp mailto http https jar netdoc, 具体还没有研究。

漏洞代码

HttpURLConnection与URLConnection的区别

URLConnection 可以使用邮件、文件传输协议,而HttpURLConnection 就单指浏览器的HTTP协议。URLConnection实例不会在创建时建立实际的网络连接。

可能存在漏洞的点

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

HttpURLConnection

@WebServlet("/ssrfServlet")
public class ssrfServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    this.doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String url = request.getParameter("url");   //接收url的传参
        String htmlContent;
        PrintWriter writer = response.getWriter();  //获取响应的打印流对象
        URL u = new URL(url);   //实例化url的对象
        try {
          //每次当调用此URL的协议处理程序的URLStreamHandler.openConnection(URL)方法时, 都会创建一个新的URLConnection实例。
          //URLConnection实例不会在创建时建立实际的网络连接。 只会在调用URLConnection.connect()时发生。
            URLConnection urlConnection = u.openConnection(); //打开一个URL连接,并运行客户端访问资源。
            HttpURLConnection httpUrl = (HttpURLConnection) urlConnection;  //强转为HttpURLConnection
            BufferedReader base = new BufferedReader(new InputStreamReader(httpUrl.getInputStream(), "UTF-8"));  //获取HttpURLConnection中的资源
            StringBuffer html = new StringBuffer();
          //把base里的资源传给htmlContent
            while ((htmlContent = base.readLine()) != null) {
                html.append(htmlContent);  //htmlContent添加到html里面
            }
            base.close();

            writer.println(html);//响应中输出读取的资源
            writer.flush();

        } catch (Exception e) {
            e.printStackTrace();
            writer.println("请求失败");
            writer.flush();
        }
}
  
//openConnection:每次当调用此URL的协议处理程序的URLStreamHandler.openConnection(URL)方法时, 都会创建一个新的URLConnection实例。
//openStream():打开到此URL的连接并返回一个用于从该连接读入的InputStream。
String url = request.getParameter("picurl");//接收picurl的传参
StringBuffer response = new StringBuffer();

URL pic = new URL(url);
HttpURLConnection con = (HttpURLConnection) pic.openConnection();//创建一个新的URLConnection并强制转换为HttpURLConnection
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

public class SSRFServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String url = req.getParameter("url");   //接收url的传参
        String htmlContent;
        PrintWriter writer = resp.getWriter();  //获取响应的打印流对象
        URL u = new URL(url);   //实例化url的对象
        try {
            URLConnection urlConnection = u.openConnection();//打开一个URL连接,并运行客户端访问资源。
            //HttpURLConnection httpUrl = (HttpURLConnection) urlConnection;  //强转为HttpURLConnection
            BufferedReader base = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "UTF-8"));   //获取url中的资源
           
            StringBuffer html = new StringBuffer();
           //把base里的资源传给htmlContent
            while ((htmlContent = base.readLine()) != null) {
                html.append(htmlContent);  //htmlContent添加到html里面
            }
            base.close();

            writer.println(html);//响应中输出读取的资源
            writer.flush();

        } catch (Exception e) {
            e.printStackTrace();
            writer.println("请求失败");
            writer.flush();
        }
    }

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

imageIO

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


        InputStream  istream = url.openStream();  //打开到此URL的连接并返回一个用于从该连接读入的InputStream。
        ImageInputStream stream =  ImageIO.createImageInputStream(istream);  //获取文件流


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

        return bi;
    }
}
@WebServlet("/httpclientServlet")
public class httpclientServlet extends HttpServlet {


    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String geturl = request.getParameter("url");
      //输出流 用于输出字符流数据或者二进制的字节流数据都可以
        ServletOutputStream outputStream = response.getOutputStream();
      //ByteArrayOutputStream对byte类型数据进⾏写⼊的类 相当于⼀个中间缓冲层,将类写⼊到⽂件等其他outputStream。
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        URL url = new URL(geturl);
      //获取文件流
        BufferedImage image = ssrf.read(url);
			//image流写到OS流
        ImageIO.write(image, "png", os);
      //os.toByteArray()将流转换为数组
        InputStream input = new ByteArrayInputStream(os.toByteArray());
        int len;
        byte[] bytes = new byte[1024];
        while ((len = input.read(bytes)) > 0) {
            outputStream.write(bytes, 0, len);
        }

    }
}

HttpClient

//创建一个DefaultHttpClient的实例
CloseableHttpClient httpClient = HttpClients.createDefault();
//发送GET请求  POST: HttpPost httpPost = new HttpPost(url);
  HttpGet getRequest = new HttpGet(url);
  HttpResponse response = httpClient.execute(getRequest);

  if(response.getStatusLine().getStatusCode() == 200)
    {
        HttpEntity entity = response.getEntity();
        return EntityUtils.toByteArray(entity);
    }
  throw new IOException("Error:下载图片失败");

OkHttp

okhttp是一个第三方类库,用于android中请求网络

  String url = request.getParameter("url");
  OkHttpClient httpClient = new OkHttpClient();
  Request request = new Request.Builder()
        .url(url)
        .build();
  Response response = httpClient.newCall(request).execute();
  return response.body().string(); 

HttpRequest

HttpRequest request = HttpRequest.get("http://www.baidu.com",true,'q',"baseball gloves","size",100);

做代码审计的时候,一般直接用自动化工具扫,或全局搜关键字。

防御

  1. 限制协议只能为http/https,防止跨协议。就是用HttpURLConnection。
  2. 对获取的URL进行判断,设置url白名单。

参考文章

https://www.cnblogs.com/CoLo/p/15236424.html

https://www.freebuf.com/vuls/293473.html

https://zhuanlan.zhihu.com/p/469314036

https://www.csdn.net/tags/MtTaEgxsNjE5MzQyLWJsb2cO0O0O.html

posted @ 2022-05-07 12:04  九天揽月丶  阅读(437)  评论(0编辑  收藏  举报