There is a ssrf vulnerability
Nmslgkd opened this issue · 2 comments
1.After downloading the source code, go to the get_image_base64 function in the app/api/controller/v1/PublicController.php file.
`/**
- 获取图片base64
- @param Request $request
- @return mixed
*/
public function get_image_base64(Request $request)
{
[$imageUrl, $codeUrl] = $request->postMore([
['image', ''],
['code', ''],
], true);
try {
$code = CacheService::get($codeUrl, function () use ($codeUrl) {
$codeTmp = $code = $codeUrl ? image_to_base64($codeUrl) : false;
if (!$codeTmp) {
$putCodeUrl = put_image($codeUrl);
$code = $putCodeUrl ? image_to_base64(app()->request->domain(true) . '/' . $putCodeUrl) : false;
$code ?? unlink($_SERVER["DOCUMENT_ROOT"] . '/' . $putCodeUrl);
}
return $code;
});
$image = CacheService::get($imageUrl, function () use ($imageUrl) {
$imageTmp = $image = $imageUrl ? image_to_base64($imageUrl) : false;
if (!$imageTmp) {
$putImageUrl = put_image($imageUrl);
$image = $putImageUrl ? image_to_base64(app()->request->domain(true) . '/' . $putImageUrl) : false;
$image ?? unlink($_SERVER["DOCUMENT_ROOT"] . '/' . $putImageUrl);
}
return $image;
});
return app('json')->successful(compact('code', 'image'));
} catch (\Exception $e) {
return app('json')->fail($e->getMessage());
}
}`
2.The function accepts an image parameter from the front end and assigns it to the variable $imageUrl
[$imageUrl, $codeUrl] = $request->postMore([ ['image', ''], ['code', ''], ], true);
3.Enter the image_to_base64 function by tracking the $imageUrl parameter
$codeTmp = $code = $codeUrl ? image_to_base64($codeUrl) : false;
4.$image_to_base64 function source code:
`/**
- 获取图片转为base64
- @param string $avatar
- @return bool|string
/
function image_to_base64($avatar = '', $timeout = 9)
{
$avatar = str_replace('https', 'http', $avatar);
try {
$url = parse_url($avatar);
$url = $url['host'];
$header = [
'User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:45.0) Gecko/20100101 Firefox/45.0',
'Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
'Accept-Encoding: gzip, deflate, br',
'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'Host:' . $url
];
$dir = pathinfo($url);
$host = $dir['dirname'];
$refer = $host . '/';
$curl = curl_init();
curl_setopt($curl, CURLOPT_REFERER, $refer);
curl_setopt($curl, CURLOPT_URL, $avatar);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_ENCODING, 'gzip');
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
$data = curl_exec($curl);
$code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
if ($code == 200) {
return "data:image/jpeg;base64," . base64_encode($data);
} else {
return false;
}
} catch (\Exception $e) {
return false;
}
}`
5.Continue to track the $imageUrl variable ($avatar in the image_to_base64 function), you can find that the parameter $avatar is directly set to the request path of curl, and no filtering is done
curl_setopt($curl, CURLOPT_URL, $avatar);
6.Find the corresponding route in app/api/route/v1.php, and verify it after setting up the environment
Request a domain name in dnslog:

Then construct the corresponding data packet:

Request data received successfully:
