参考:
伪协议简介
php伪协议,事实上是其支持的协议与封装协议
支持的种类有这12种
- 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:// — 处理交互式的流
先整理一下关于php://的用法
php://
PHP 提供了一些杂项输入/输出(IO)流,允许访问 PHP 的输入输出流、标准输入输出和错误描述符, 内存中、磁盘备份的临时文件流以及可以操作其他读取写入文件资源的 过滤器。
php://stdin, php://stdout 和 php://stderr
php://stdin、php://stdout 和 php://stderr 允许直接访问 PHP 进程相应的输入或者输出流。 数据流引用了复制的文件描述符,所以如果你打开php://stdin并在之后关了它, 仅是关闭了复制品,真正被引用的 STDIN 并不受影响。 推荐简单使用常量 STDIN、 STDOUT 和 STDERR 来代替手工打开这些封装器。
php://stdin是只读的,php://stdout 和 php://stderr 是只写的。
php://input
php://input
是个可以访问请求的原始数据的只读流。因为它不依赖于特定的 php.ini
指令。可以将想要执行的php代码放在post的数据中,不用以键值对的形式出现
注:enctype=”multipart/form-data” 的时候 php://input 是无效的。即php://input 不读取表单数据参数
结合一道题来看,源码为:
<!--
$user = $_GET["user"];
$file = $_GET["file"];
$pass = $_GET["pass"];
if(isset($user)&&(file_get_contents($user,'r')==="the user is admin")){
echo "hello admin!<br>";
include($file); //class.php
}else{
echo "you are not admin ! ";
}
-->
php://output
php://output
是一个只写的数据流, 允许你以 print 和 echo 一样的方式 写入到输出缓冲区。php://filter
可以说这是最常使用的一个伪协议,一般可以利用进行任意文件读取。
php://filter 是一种元封装器, 设计用于数据流打开时的筛选过滤应用。 这对于一体式(all-in-one)的文件函数非常有用,类似 readfile()、 file() 和 file_get_contents(), 在数据流内容读取之前没有机会应用其他过滤器。
php://filter 参数
名称 | 描述 |
---|---|
resource=<要过滤的数据流> | 它指定了你要筛选过滤的数据流。这个参数是必须的。 |
read=<读链的筛选列表> | 该参数可选。可以设定一个或多个过滤器名称,这采用一个|或以管道符 /分隔的多个过滤器名称 |
write=<写链的筛选列表> | 该参数可选。可以设定一个或多个过滤器名称,以管道符(_ |
<;两个链的筛选列表> | 任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。 |
还是结合上面那道题:
过滤器
过滤器有很多种,有字符串过滤器、转换过滤器、压缩过滤器、加密过滤器,这里只说一种转换过滤器中的一种
convert.base64-encode & convert.base64-decode
convert.base64-encode和convert.base64-decode使用这两个过滤器等同于分别用 base64_encode()和 base64_decode()函数处理所有的流数据。 convert.base64-encode支持以一个关联数组给出的参数。如果给出了line-length,base64 输出将被用 line-length个字符为长度而截成块。如果给出了* line-break-chars*,每块将被用给出的字符隔开。这些参数的效果和用 base64_encode()再加上 chunk_split()相同。
为什么要base64编码后再读取呢?
这涉及到include()的特性,如果include的文件不是txt格式会直接输出,如果包含<?php ?>这种格式在,则会执行相关代码。
综上,如果不加编码的话,引入的文件若符合php格式则会自动执行,将结果包含在流中,如果想要读取运行php文件的源码,就可以先base64编码,再传入include函数,这样就不会被认为是php文件,不会执行,会输出文件的base64编码,再解码即可。
file://
file://与php:filter类似,访问本地文件,但是只能传入绝对路径
data
data 与input 类似,都是用户可以控制传入的php代码,格式为:data: text/plain,<?php 执行内容 ?>
或者是:
data:text/plain;(注意是分号不是逗号,与前面不同)base64,编码后的php代码
有一点要注意的问题,base64编码后的加号和等号要手动的url编码,否则无法识别
http
include中也可以传入外部链接,采用http://,如图
一道实例:
来自攻防世界 Web_php_include
访问URL,直接出现源码:
<?php
show_source(__FILE__);
echo $_GET['hello'];
$page=$_GET['page'];
while (strstr($page, "php://")) {
$page=str_replace("php://", "", $page);
}
include($page);
?>
看到源码后,分析一下,过滤了php://有如下3种思路:
- data来代替php://
- 利用大小写绕过过滤Php://,直接php://input 代码执行
- 利用http://127.0.0.1/index.php?的方式来绕过过滤,这种方法比较巧妙,但是也比较巧合,需要该应用可直接在本地根目录去访问/index.php才能达到这个效果http://192.168.100.161:50281/?page=http://127.0.0.1/index.php/?hello=%3C?system(%22ls%22);?%3E
今日分享:
高效的时间管理!!
嘿嘿,我自己说的,今天做的还不错,稍微表扬一下自己~
没有评论:
发表评论