GCCCTF的WP

GCCCTF的WP

Web

PHP签到

  • 打开环境,根据
想了解更多系统信息?机器人总是遵循特定的协议和规则...

联想到robots.txt并进入robots.txt,再进入l34RNpHP.php看到源码

<?php

header('Content-Type: text/plain; charset=UTF-8');

if (!isset($_GET['user'], $_GET['token'], $_GET['sig'], $_GET['ts'], $_GET['nonce'])) {
    readfile(__FILE__);
    exit;
}

$user   = (string)$_GET['user'];
$token  = (string)$_GET['token'];
$sig    = (string)$_GET['sig'];
$ts     = (int)$_GET['ts'];
$nonce  = (string)$_GET['nonce'];

$xff = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? '';
if (strpos($xff, '127.0.0.1') === false && strpos($xff, '::1') === false) {
    exit('hacker!');
}

if (base64_decode($nonce) === false || !preg_match('/^[A-Za-z0-9+\/=]+$/', $nonce)) {
    exit('hacker!!');
}

if (time() - $ts <= 60) {
    // ok
} else {
    exit('expired!');
}

if (strpos($user, 'admin') == false) {

    $key = $_COOKIE['authkey'] ?? 'NULL';
    $mac = hash_hmac('md5', $user . $token . $ts, $key);

    if (substr($mac, 0, 6) == substr($sig, 0, 6)) {

        $stored_hash = '0e830400451993494058024219903391'; 
        if (md5($token) == $stored_hash) {
            @readfile('/flag');
        } else {
            exit('hacker!!!');
        }

    } else {
        exit('hacker!!!!');
    }

} else {
    exit('blocked user');
}

1‍⃣

$stored_hash = '0e830400451993494058024219903391'; 
 if (md5($token) == $stored_hash) {
     @readfile('/flag');
} else {
     exit('hacker!!!');
}
最终是要进入readfile('/flag'),必须要满足md5($token)==$stored_hash(php弱比较)
而在php弱比较中,0e830400451993494058024219903391 = 0 × 10^很多 = 0
所以md5(token)也长成”0e数字数字数字……",经典值就是
QNKCDZO
所以token=QNKCDZO

2‍⃣


$key = $_COOKIE['authkey'] ?? 'NULL';
$mac = hash_hmac('md5', $user . $token . $ts, $key);

if (substr($mac, 0, 6) == substr($sig, 0, 6)) {
外层是if (substr($mac, 0, 6) == substr($sig, 0, 6)) {,所以不仅要让token通过md5,还要让签名sig也通过

而对于mac

$key = $_COOKIE['authkey'] ?? 'NULL';
$mac = hash_hmac('md5', $user . $token . $ts, $key);
  • mac:明文为user+token+ts的拼接字符串;密钥为key;加密方式为hash_hmac——所以想要得到mac,还需要知道key user ts
  • key:如果传了Cookie(比如Cookie:authkey=abc),那么key就是Cookie,没有就是NULL;所以最简单的方法是不带authkey Cookie或者明确Cookie:authkey=NULL;这样key的值就是NULL

3‍⃣

if (strpos($user, 'admin') == false) {
  • strops为查找字符串,如果user=‘admin’,那么返回0(因为admin出现在第0位)
  • 同时在PHP弱比较中0==false,所以strpos($user, ‘admin’) == false返回true
  • 所以user=admin

4‍⃣选ts

if (time() - $ts <= 60) {
    // ok
} else {
    exit('expired!');
}

时间戳不能超过60秒,所以可以用当前时间戳 但是也可以传入未来时间戳

ts=9999999999

那么

time() - $ts < 0

负数也小于0,所以也可以用ts=9999999999 关键是:计算sig用的ts,必须和URL里传的ts一模一样


5‍⃣

if (base64_decode($nonce) === false || !preg_match('/^[A-Za-z0-9+\/=]+$/', $nonce)) {
    exit('hacker!!');
}

要求nonce是Base64的样子 所以随便给

nonce=MQ==

(MQ==解码后是1)


6‍⃣

$xff = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? '';
if (strpos($xff, '127.0.0.1') === false && strpos($xff, '::1') === false) {
    exit('hacker!');
}

所以抓包时加

X-Forwarded-For:127.0.0.1

ps:真的很害怕读源码😭


Comments

评论区

📋 目录