SSRF 形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。比如从指定 URL 地址获取网页文本内容,加载指定地址的图片,下载等等。这里主要介绍java中URLConnection()
和openStream()
两个方法产生SSRF的原理和修复方法
@RequestMapping(value = "/urlConnection/vuln", method = {RequestMethod.POST, RequestMethod.GET})
public String URLConnectionVuln(String url) {
return HttpUtils.URLConnection(url);
}
这里调用的是HttpUtils.URLConnection(url)
public static String URLConnection(String url) {
try {
URL u = new URL(url);
URLConnection urlConnection = u.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); //send request
// BufferedReader in = new BufferedReader(new InputStreamReader(u.openConnection().getInputStream()));
String inputLine;
StringBuilder html = new StringBuilder(); while ((inputLine = in.readLine()) != null) {
html.append(inputLine);
}
in.close();
return html.toString();
} catch (Exception e) {
logger.error(e.getMessage());
return e.getMessage();
}
}
跟进URLConnection
方法,而URLConnection
里又调用了URL.openConnection()
来发起请求, 这个请求可以直接执行url协议(伪协议)
漏洞利用:
使用file协议读文件
使用http协议访问百度
修复方法:
这里先是对url调用了SecurityUtil.isHttp()
来进行检查
@GetMapping("/urlConnection/sec")
public String URLConnectionSec(String url) { // Decline not http/https protocol
if (!SecurityUtil.isHttp(url)) {
return "[-] SSRF check failed";
}
try {
SecurityUtil.startSSRFHook();
return HttpUtils.URLConnection(url);
} catch (SSRFException | IOException e) {
return e.getMessage();
} finally {
SecurityUtil.stopSSRFHook();
}
}
SecurityUtil.isHttp()比较简单,就是判断url是否是以http://或https://开头
public static boolean isHttp(String url) {
return url.startsWith("http://") || url.startsWith("https://");
}
单纯的ban掉其他协议显然是不够的,还不能够防止对内网进行探测,于是在获取url内容之前,开启了一个hook来对用户行为进行监听,SecurityUtil.startSSRFHook()
,就有效防止了ssrf攻击
openStream()
方法的实现也是调用了openConnection
生成一个URLConnection
对象,然后再通过这个对象调用的getInputStream()
方法的
@GetMapping("/openStream")
public void openStream(@RequestParam String url, HttpServletResponse response) throws IOException {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
String downLoadImgFileName = WebUtils.getNameWithoutExtension(url) + "." + WebUtils.getFileExtension(url);
// download
response.setHeader("content-disposition", "attachment;fileName=" + downLoadImgFileName); URL u = new URL(url);
int length;
byte[] bytes = new byte[1024];
inputStream = u.openStream(); // send request
outputStream = response.getOutputStream();
while ((length = inputStream.read(bytes)) > 0) {
outputStream.write(bytes, 0, length);
}
} catch (Exception e) {
logger.error(e.toString());
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
}
}
通过WebUtils.getNameWithoutExtension(url) + "." + WebUtils.getFileExtension(url)
来获取下载文件名,然后执行inputStream = u.openStream();
来看一下openStream(),也是调用了openConnection()
,也会根据传入的协议的不同来进行处理
public final InputStream openStream() throws java.io.IOException {
return openConnection().getInputStream();
}
由此可以得知,openStream()
方法同样也可以进行ssrf来探测内网以及文件下载,修复方案同上
关键词:URLConnection、openConnection、openStream
漏洞利用:
关于SSRF漏洞利用相关可以看这篇文章,总结的很详细!
从一文中了解SSRF的各种绕过姿势及攻击思路
Web3正频繁出现在公众视野中,然而受阻于晦涩难懂的技术原理及陌生又拗口的专业术语,很多人对此望而却步。本书试图用通俗的语言、简单的结构、翔实的案例让零基础的读者迅速掌握Web3的核心要义。
Web3不仅仅是技术和金融语境,它和每个人的生活都息息相关。作为深耕Web3的研究机构,Inverse DAO将带你通过纵向时间线、横向技术线来立体、客观、完整地理解Web3。通过本书你既可以快速读懂行业,也可以躬身实践参与。
希望本书可以抛砖引玉,启迪你的智慧之光,发现Web3更多、更广、更深的奥秘,助你在新的科技浪潮下,无往而不胜。