徐绍贤 發表於 2024-4-11 09:30:00

PHP基础知识——PHP伪协议

<h1 id="什么是php伪协议">什么是php伪协议</h1>
<p>在 PHP 中,"伪协议"是一种特殊的语法,用于访问不同的资源或执行特定的操作。这些伪协议以 <code>php://</code> 开头,后面跟着特定的指示符或参数,以实现不同的功能。这些伪协议提供了一种方便的方式来处理各种输入输出操作,而不必依赖于实际的文件或网络资源。</p>
<p>简单的理解就是,<strong>在URL中使用特殊的协议前缀来指示PHP执行特定的代码。</strong></p>
<h1 id="phpini参数设置">php.ini参数设置</h1>
<p>在php.ini里有两个重要的参数allow_url_fopen、allow_url_include。</p>
<ul>
<li>
<p>allow_url_fopen:默认值是ON。允许url里的封装协议访问文件;</p>
</li>
<li>
<p>allow_url_include:默认值是OFF。不允许包含url里的封装协议包含文件;</p>
</li>
</ul>
<h1 id="有哪些伪协议">有哪些伪协议</h1>
<pre><code>file:// — 访问本地文件系统
http:// — 访问 HTTP(s) 网址
ftp:// — 访问 FTP(s) URLs
php:// — 访问各个输入/输出流(I/O streams)
zlib:// — 压缩流
data:// — 数据(RFC 2397)
glob:// — 查找匹配的文件路径模式
phar:// — PHP 归档
ssh2:// — Secure Shell 2
rar:// — RAR
ogg:// — 音频流
expect:// — 处理交互式的流
</code></pre>
<h1 id="应用场景">应用场景</h1>
<p>文件包含<br>
(关于文件包含的函数)</p>
<pre><code>include()、require()、include_once()、require_once()、highlight_file()
show_source() 、readfile() 、file_get_contents() 、fopen() 、file()
</code></pre>
<h1 id="伪协议详解">伪协议详解</h1>
<h2 id="data">data://</h2>
<p>数据流封装器,以传递相应格式的数据。可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行。</p>
<p>allow_url_fopen和allow_url_include都需要开启。</p>
<p>example:</p>
<pre><code>1、data://text/plain,
http://127.0.0.1/include.php?file=data://text/plain,&lt;?php%20phpinfo();?&gt;

2、data://text/plain;base64,
http://127.0.0.1/include.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
</code></pre>
<h2 id="file">file://</h2>
<p>用于访问本地文件系统,并且不受allow_url_fopen,allow_url_include影响<br>
file://协议主要用于访问文件(绝对路径、相对路径以及网络路径)<br>
比如:<code>www.xx.com?file=file:///etc/passwd</code></p>
<h2 id="php">php://</h2>
<p>不需要开启allow_url_fopen,仅php://input、php://stdin、php://memory和php://temp需要开启allow_url_include。</p>
<h3 id="phpfilter">php://filter</h3>
<p>一个中间件,在读入或写入数据的时候对数据进行处理后输出的过程。可以获取指定文件源码。当它与包含函数结合时,php://filter流会被当作php文件执行。所以我们一般对其进行base64编码,让其不执行,展现在页面上。从而导致任意文件读取。</p>
<p>ctf解题常用:<br>
<code>变量=php://filter/read=convert.base64-encode/resource=文件名</code></p>
<p>使用的convert.base64-encode,是一种过滤器。</p>
<p>协议参数</p>
<p><img src="https://img2024.cnblogs.com/blog/2304658/202404/2304658-20240411084950560-1571287670.png" alt="" loading="lazy"></p>
<h3 id="利用filter伪协议绕过死亡exit">利用filter伪协议绕过死亡exit</h3>
<p>何为死亡exit?</p>
<p>举个例子:</p>
<pre><code>file_put_contents($content, '&lt;?php exit();' . $content);

// 或者这样
file_put_contents($content, '&lt;?php exit();?&gt;' . $content);
</code></pre>
<p>如果想插入一句话木马,文件内容会变成这样</p>
<pre><code>&lt;?php exit();?&gt;

&lt;?php @eval($_POST['test']);?&gt;
</code></pre>
<p>即使插入了一句话木马,在被使用的时候也无法被执行。这样的死亡exit通常存在于缓存、配置文件等等不允许用户直接访问的文件当中。</p>
<p>如何绕过?————filter伪协议+base64decode<br>
利用<code>php://filter的base64-decode</code>方法,将<code>$content</code>解码,利用<code>php base64_decode</code>函数特性去除死亡exit。base64编码中只包含64个可打印字符,当PHP遇到不可解码的字符时,会选择性的跳过。</p>
<p>当<code>$content</code>包含 <code>&lt;?php exit; ?&gt;</code>时,解码过程会先去除识别不了的字符,<code>&lt; ; ? &gt;</code>和空格等都将被去除,于是剩下的字符就只有<code>phpexit</code>以及我们传入的字符了。由于base64是4个byte一组,再添加一个字符例如添加字符<code>a</code>后,将<code>phpexita</code>当做两组base64进行解码,也就绕过这个死亡exit了。<br>
这个时候后面再加上编码后的一句话木马,就可以getshell了。</p>
<h3 id="phpinput">php://input</h3>
<p>可以访问请求的原始数据的只读流, 将post请求中的数据作为PHP代码执行。在POST请求中访问POST的data部分,在<code>enctype="multipart/form-data"</code>的时候php://input 是无效的。</p>
<p>当传进去的参数作为文件名变量去打开文件时,可以将参数php://input,同时post方式传进去值作为文件内容,供php代码执行时当做文件内容读取。</p>
<p><img src="https://img2024.cnblogs.com/blog/2304658/202404/2304658-20240411092315978-1370201287.png" alt="" loading="lazy"></p>
<h3 id="其他">其他</h3>
<p>php://stdin、php://stdout 和 php://stderr 允许直接访问 PHP 进程相应的输入或者输出流。 数据流引用了复制的文件描述符,所以如果你打开 php://stdin 并在之后关了它, 仅是关闭了复制品,真正被引用的 STDIN 并不受影响。</p>
<p>注意 PHP 在这方面的行为有很多 BUG 直到 PHP 5.2.1。 推荐简单使用常量 STDIN、 STDOUT 和 STDERR 来代替手工打开这些封装器。</p>
<p>php://stdin 是只读的, php://stdout 和 php://stderr 是只写的。</p>
<h2 id="zip">zip://</h2>
<p>可以访问压缩包里面的文件。当它与包含函数结合时,zip://流会被当作php文件执行。从而实现任意代码执行。相同类型的还有zlib://和bzip2://。</p>
<p>可以配合文件上传获取webshell,将shell.txt压缩成zip,再将后缀名改为jpg上传,通过zip伪协议访问压缩包里的文件,来连接木马</p>
<pre><code>?url=zip://shell.jpg
</code></pre>
<p>注意:此处只能传入绝对路径,要用<code>#</code>分隔压缩包和压缩包里的内容,并且#要用url编码%23。只要是zip的压缩包即可,后缀名可以任意更改。</p>
<h2 id="phar">phar://</h2>
<p>与zip://类似,同样可以访问zip格式压缩包内容</p>
<pre><code>http://127.0.0.1/include.php?file=phar://E:/phpStudy/PHPTutorial/WWW/phpinfo.zip/phpinfo.txt
</code></pre>
<p>利用 phar 拓展 php 反序列化漏洞攻击面</p>
<h2 id="http--https">http:// &amp; https://</h2>
<p>allow_url_fopen和allow_url_include都需要开启。</p>
<p>常规 URL 形式,允许通过 HTTP 1.0 的 GET方法,以只读访问文件或资源。CTF中通常用于远程包含。</p>
<pre><code>http://127.0.0.1/include.php?file=http://127.0.0.1/phpinfo.txt
</code></pre>
<h1 id="参考文章">参考文章</h1>
<p>https://juejin.cn/post/7163831572158742535</p>
<p>https://blog.csdn.net/IDHALASHAO/article/details/130368938</p>
<p>https://crayon-xin.github.io/2018/04/15/php伪协议-php/</p>
<p>https://segmentfault.com/a/1190000018991087</p>
<p>https://paper.seebug.org/680/</p><br><br>
来源:https://www.cnblogs.com/smile2333/p/18128048
頁: [1]
查看完整版本: PHP基础知识——PHP伪协议