免费发布信息
当前位置:APP交易 > 热点资讯 > app交易 >  JavaWeb中的ssrf审计

JavaWeb中的ssrf审计

发表时间:2021-07-09 17:05:10  来源:红帽社区  浏览:次   【】【】【
红帽社区是一个垂直网络安全社区,融合“红帽先锋”正能量精神,每日分享最新安全资讯,提供安全问答、靶场、众测、漏洞库等功能,是网络安全爱好者学习、交流的优质社区。

JavaWeb中的SSRF审计

漏洞原理

漏洞成因

  web应用提供了从其他的服务器上获取数据的功能。例如通过用户指定的URL,web应用可以获取图片,下载文件,读取文件内容等。如果存在缺陷,可以利用存在缺陷的web应用作为代理攻击远程和本地的服务器。

支持的协议

  Java网络请求支持的协议有:

ssrfCode_1.png

审计思路

  主要关注可以发起网络请求的方法和对应的业务。

业务定位

  常见的从服务端获取其他服务器信息的的功能:

  • 通过URL地址分享网页内容
  • 在线转码服务
  • 在线翻译
  • 通过URL地址加载或下载图片
  • app更新时从远端服务器下载更新包、皮肤等
  • 加载远端配置的文件

常见class

  • HttpClient
  • HttpURLConnection
  • URLConnection
  • URL
  • okhttp

  发起网络请求的类是带HTTP开头的,那只支持HTTP、HTTPS协议。URL和URLConnection是支持sun.net.www.protocol所有协议的。例如如果URL的参数可控的话,可以尝试使用file协议读取系统文件:

import java.io.InputStream; import java.net.URL; import java.net.URLConnection; public class UrlClassTest { public static void main(String[] args) { URL u; try { u = new URL("file:///etc/passwd"); URLConnection uc = u.openConnection(); InputStream in = uc.getInputStream(); byte[] b = new byte[1024]; int len; while ((len = in.read(b)) != -1) { System.out.println(new String(b, 0, len)); } in.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }; } } }

ssrfCode_2.png

相关案例

  以UEditor的SSRF漏洞为例,查看commit发现1.4.3.1版本修复了SSRF漏洞,也就是说1.4.3及之前版本都存在问题:

ssrfCode_3.png

  本身该版本是存在一定的防护的,在config.json的catcherLocalDomain参数可以配置filter的黑名单:

"catcherLocalDomain": ["127.0.0.1", "localhost", "img.baidu.com"],

  在实际运行时,通过ConfigManager加载对应的配置,将catcherLocalDomain参数对应的值存储到Map对象中:

case 5: conf.put("filename", "remote"); conf.put("filter", getArray("catcherLocalDomain")); conf.put("maxSize", Long.valueOf(this.jsonConfig.getLong("catcherMaxSize"))); conf.put("allowFiles", getArray("catcherAllowFiles")); conf.put("fieldName", this.jsonConfig.getString("catcherFieldName") + "[]"); savePath = this.jsonConfig.getString("catcherPathFormat"); break;

  到实际请求远端图片的com.baidu.ueditor.hunter.ImageHunter.java来看,发起网络请求的方法主要是captureRemoteData():

public State captureRemoteData(String urlStr) { HttpURLConnection connection = null; URL url = null; String suffix = null; try { url = new URL(urlStr); if (!validHost(url.getHost())) { return new BaseState(false, 201); } connection = (HttpURLConnection)url.openConnection(); connection.setInstanceFollowRedirects(true); connection.setUseCaches(true); if (!validContentState(connection.getResponseCode())) { return new BaseState(false, 202); } suffix = MIMEType.getSuffix(connection.getContentType()); if (!validFileType(suffix)) { return new BaseState(false, 8); } if (!validFileSize(connection.getContentLength())) { return new BaseState(false, 1); } String savePath = getPath(this.savePath, this.filename, suffix); String physicalPath = this.rootPath + savePath; State state = StorageManager.saveFileByInputStream(connection.getInputStream(), physicalPath); if (state.isSuccess()) { state.putInfo("url", PathFormat.format(savePath)); state.putInfo("source", urlStr); } return state; } catch (Exception e) {} return new BaseState(false, 203); }

  可以看到,通过validHost()方法进行判断是否是合法的host,然后通过HttpURLConnection的方法进行网络请求,validHost()方法是之前查看filters中是否包含当前域名,如果包含则返回false,拒绝发起请求。并且filters的值是通过前面ConfigManager的conf获得的:

public ImageHunter(Map<String, Object> conf) { this.filename = ((String)conf.get("filename")); this.savePath = ((String)conf.get("savePath")); this.rootPath = ((String)conf.get("rootPath")); this.maxSize = ((Long)conf.get("maxSize")).longValue(); this.allowTypes = Arrays.asList((String[])conf.get("allowFiles")); this.filters = Arrays.asList((String[])conf.get("filter")); } private boolean validHost(String hostname) { return !this.filters.contains(hostname); }

  也就是说,具体防御还是依赖于config.json,具体效果如下,正常情况下,访问外网dnslog是没问题的(不在默认的黑名单内):

ssrfCode_4.png

  尝试请求127.0.0.1,此时匹配默认的黑名单,拒绝发起网络请求:

ssrfCode_5.png

  因为只是contains匹配,所以很简单就可以绕过了,这里用127.0.0.1.xip.io代替127.0.0.1,成功绕过黑名单发起网络请求:

ssrfCode_6.png

  同理,因为是默认黑名单,且黑名单覆盖面不全很容易导致绕过,这里可以直接修改成内网地址尝试进行端口探测等攻击利用行为。

ssrfCode_7.png

  再看看1.4.3.1版本是怎么修复的,主要的改动还是在validHost方法,通过InetAddress对象的isSiteLocalAddress()方法进行判断,禁止内网地址的网络请求。

private boolean validHost(String hostname) { try { InetAddress ip = InetAddress.getByName(hostname); if (ip.isSiteLocalAddress()) { return false; } } catch (UnknownHostException e) { return false; } return !this.filters.contains(hostname); }

  查看文档,isSiteLocalAddress方法作用是当IP地址是地区本地地址(SiteLocalAddress)时返回true,否则返回false。

ssrfCode_8.png

  如果是IPv4地址,主要是这三个段:10.0.0.0~ 10.255.255.255、172.16.0.0 ~ 172.31.255.255、192.168.0.0 ~192.168.255.255。简单的对192.168.0.1fuzz一下:

  • 8进制格式:0300.0250.0.1
  • 16进制格式:0xC0.0xA8.0.1
  • 10进制整数格式:3232235521
  • 16进制整数格式:0xC0A80001
  • www.baidu.com@192.168.0.1

  结果如下:

ssrfCode_9.png

修复方案

  • 使用白名单校验HTTP请求url地址,例如通过InetAddress对象的isSiteLocalAddress()方法进行判断,禁止内网地址的网络请求。。

  • 避免将请求响应及错误信息返回给用户。

  • 禁用不需要的协议及限制请求端口,仅仅允许http和https请求等。

责任编辑:
声明:本平台发布的内容(图片、视频和文字)以原创、转载和分享网络内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。

德品

1377 678 6470