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


    28题

    <!DOCTYPE html>
    <html>
    <head>
    <title>Web 350</title>
    <style type="text/css">
            body {
                    background:gray;
                    text-align:center;
            }
    </style>
    </head>
    
    <body>
            <?php
                    $auth = false;
                    $role = "guest";
                    $salt =
                    if (isset($_COOKIE["role"])) {
                            $role = unserialize($_COOKIE["role"]);
                            $hsh = $_COOKIE["hsh"];
                            if ($role==="admin" && $hsh === md5($salt.strrev($_COOKIE["role"])))
    // strrev返回 string 反转后的字符串。 
                             {
                                    $auth = true;
                            } else {
                                    $auth = false;
                            }
                    } else {
                            $s = serialize($role);
                            setcookie('role',$s);
                            $hsh = md5($salt.strrev($s));
                            setcookie('hsh',$hsh);
                    }
                    if ($auth) {
                            echo "<h3>Welcome Admin. Your flag is 
                    } else {
                            echo "<h3>Only Admin can see the flag!!</h3>";
                    }
            ?>
            
    </body>

    这个题目出处应该是Jarvis OJ中的flag在管理员手里,题目地址在:http://web.jarvisoj.com:32778/

    简单分析一下代码:

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

    首先给三个变量赋值,$auth和$role的值是我们可见的,$salt应该是后端赋值而我们不可见。

    接着在COOKIE中传输role,并且将其反序列化的值赋给role

    	if (isset($_COOKIE["role"])) {
                            $role = unserialize($_COOKIE["role"]);

    接着是给hsh赋值

    $hsh = $_COOKIE["hsh"];

    然后是一个判断,进而给auth赋值

    if ($role==="admin" && $hsh === md5($salt.strrev($_COOKIE["role"])))
    // strrev返回 string 反转后的字符串。 
                             {
                                    $auth = true;
                            } else {
                                    $auth = false;
                            }

    我们看到最后想要获取flag需要 $auth为真

    		if ($auth) {
                            echo "<h3>Welcome Admin. Your flag is xxx"
                    } else {
                            echo "<h3>Only Admin can see the flag!!</h3>";
                    }

    即我们需要满足这个条件

    $role==="admin" && $hsh === md5($salt.strrev($_COOKIE["role"]))

    如果COOKIE中没有role的话,就进入else,使用代码最开始赋值的auth和role进行以下操作

    		else {
                            $s = serialize($role);
                            setcookie('role',$s);
                            $hsh = md5($salt.strrev($s));
                            setcookie('hsh',$hsh);
                    }

    但else里面的操作正常来说是不能拿到flag的

    所以我们需要突破的是:

    $role==="admin" && $hsh === md5($salt.strrev($_COOKIE["role"]))

    先看后面的一个比较:

    $hsh === md5($salt.strrev($_COOKIE["role"]))

    左边的$hsh是我们COOKIE中传递过去的$hsh 哈希值

    右边是使用盐值和反转后的传过去的role值连接后,并进行md5加密的结果,需要与$hsh相等

    这里看上去是无懈可击的,虽然我们可以传递hsh和role的值,但是因为我们不知道盐值,所以得到的md5很难凭猜或者爆破来令其与hsh相等。

    但是如MD5,SHA1, SHA2等,都是基于Merkle–Damgård结构,而这类算法的问题在于:如果你知道加密前的原文,和加密后的密文,只需要再知道盐值的长度,就能在原文后面添加信息并计算出相应的密文。

    在pcat的博文中介绍过应用场景为:

    如果一个应用程序是这样操作的:

    1. 准备了一个密文和一些数据构造成一个字符串里,并且使用了MD5之类的哈希函数生成了一个哈希值(也就是所谓的signature/签名)

    2. 让攻击者可以提交数据以及哈希值,虽然攻击者不知道密文

    3. 服务器把提交的数据跟密文构造成字符串,并经过哈希后判断是否等同于提交上来的哈希值

    这个时候,该应用程序就易受长度扩展攻击

    另外,只有盐值在前,原文在后,才可以用hash长度扩展攻击。

    预测得到的是:

    md5(盐+原文+填充+恶意扩充)

    算法原理在这篇文章中非常详细了,具体可移步:

    https://www.freebuf.com/articles/web/31756.html

    哈希长度扩展攻击我们通常使用HashPump进行利用

    HashPump是一个借助于OpenSSL实现了针对多种散列函数的攻击的工具,支持针对MD5、CRC32、SHA1、SHA256和SHA512等长度扩展攻击。而MD2、SHA224和SHA384算法不受此攻击的影响,因其部分避免了对状态变量的输出,并不输出全部的状态变量。

    其安装过程为:

    git clone https://github.com/bwall/HashPump
    apt-get install g++ libssl-dev
    cd HashPump
    make
    make install

    对于该题,我们先进行抓包,获取初始哈希值

    1.png

    role进行url解码后为:

    s:5:"guest";

    hsh为

    3a4727d57463f122833d9e732f94e4e0

    这里还利用了PHP反序列化unserialize的一个特性,即

    unserialize()会忽略多余的字符

    举例代码为:

    <?php
        $s = 's:5:"admin";  s:5:"guest";';
        echo unserialize($s);
    ?>

    输出结果为:

    3.png

    可以看出后面的

    s:5:"guest";

    并没有进行反序列化,而是被忽略了,这也是我们使用填充字符进行哈希长度扩展攻击的关键。

    另外我们虽然不知道盐值的长度,但是我们可以进行逐个尝试

    4.png

    将获得的结果反序后重放

    5.png

    尝试得到盐值的长度为12,获得flag

    这里其实可以写一个脚本进行尝试,这样可以快很多,减少体力劳动

     

    参考链接:

    https://www.freebuf.com/articles/web/31756.html

    https://www.cnblogs.com/pcat/p/5478509.html

    https://blog.csdn.net/zpy1998zpy/article/details/80858080

    https://www.jianshu.com/p/af6c0bb5ae3a

    https://skysec.top/2017/08/16/jarvisoj-web/#flag%E5%9C%A8%E7%AE%A1%E7%90%86%E5%91%98%E6%89%8B%E9%87%8C

    http://yulige.top/?p=271

    https://blog.cindemor.com/post/ctf-web-19.html

  • 相关阅读:
    form表单介绍
    if条件语句
    表格.html
    列表.html
    CSS Js链接HTML文件
    DQL
    mysql介绍
    第一次接触mysql
    逻辑运算、作用域问题、DOM
    Js数据类型具体分析
  • 原文地址:https://www.cnblogs.com/Cl0ud/p/13380114.html
Copyright © 2020-2023  润新知