BugkuCTF Web3 Writeup:PHP特性与代码审计实战

 :2026-02-11 18:06    点击:7  

在CTF(Capture The Flag)的征途中,Web方向往往是参赛者挑战逻辑思维、编码能力和安全知识的重要战场,BugkuCTF作为国内知名的CTF平台,其Web题目设计兼具趣味性和挑战性,本文将详细解析BugkuCTF中的一道经典Web题目——Web3,通过这道题目,我们将一同探索PHP语言的某些特殊特性,并学习如何进行基础的代码审计,最终成功获取flag。 初探

我们打开BugkuCTF平台的Web3题目,这类题目会提供一个URL,访问后我们能看到一个简单的页面,或者是一段源代码,对于Web3,我们假设访问后直接展示了一段PHP代码(如果题目环境不同,可能需要先进行信息收集,如查看源码、扫描目录等,但核心思路类似)。

假设我们看到的代码如下(这是一个常见的Web3题目类型,可能略有差异,但核心逻辑一致):

<?php
$flag = 'flag{xxxxxxxxxxxxxxxx}';
if (isset($_GET['v1']) && isset($_GET['v2'])) {
    if ($_GET['v1'] !== $_GET['v2'] && md5($_GET['v1']) === md5($_GET['v2'])) {
        echo $flag;
    } else {
        echo "NO!";
    }
} else {
    echo "NO!";
}
?>

代码审计与漏洞分析

拿到代码后,我们的第一步是仔细阅读和理解代码的逻辑。

  1. 变量初始化与存在性检查

    • $flag = 'flag{xxxxxxxxxxxxxxxx}';:定义了一个变量$flag,这是我们最终的目标。
    • if (isset($_GET['v1']) && isset($_GET['v2'])):检查URL参数v1v2是否都被设置,如果其中一个或两个都没有设置,则输出"NO!"。
  2. 核心条件判断

    • if ($_GET['v1'] !== $_GET['v2'] && md5($_GET['v1']) === md5($_GET['v2'])):这是整个题目的关键,包含两个条件,必须同时满足:
      • 条件一$_GET['v1'] !== $_GET['v2']:要求v1v2的值不完全相等(注意是,不仅比较值,还比较类型)。
      • 条件二md5($_GET['v1']) === md5($_GET['v2']):要求v1v2经过md5()哈希计算后的值完全相等(同样,严格比较)。

漏洞利用思路

我们的目标是构造v1v2的值,使得上述两个条件同时成立。

  • 条件一v1v2不能完全一样,这很容易满足,比如v1=av2=b
  • 条件二md5(v1)等于md5(v2),这就比较棘手了,因为MD5是单向哈希函数,通常不同的输入会产生不同的哈希值(碰撞概率极低)。

是否存在不同的字符串,它们的MD5值是相同的呢?答案是肯定的,这涉及到MD5的碰撞问题,虽然MD5碰撞在实际攻击中很难构造,但在CTF题目中,出题人往往会利用一些已知的MD5碰撞字符串对,或者利用PHP语言本身的特性。

PHP MD5特性利用

在PHP中,md5()函数处理字符串时,有一些特殊情况需要注意:

  1. 数组哈希:当md5()函数的参数是数组时,它会返回一个固定的字符串:NULL,这是因为PHP的md5()函数期望一个字符串参数,如果传入数组,它会返回NULL

    • md5(array()) 返回 NULL
    • md5(array(1,2)) 也返回 NULL
  2. 特定字符串的MD5值:存在一些不同的字符串,它们的MD5值都是以0e开头的数字字符串,在PHP中,0e开头的数字字符串会被科学计数法解析为0

    • md5('240610708') = 0e462097431906509019562988736854
    • md5('QNKCDZO') = 0e830400451993494058024219903391
    • 在比较时,0e4620974319065090195629887368540e830400451993494058024219903391 都被视为 0,因此它们相等。

构造Payload

根据上述分析,我们可以构造两种主要的Payload:

利用数组哈希

  • v1为数组,v2也为数组,但内容不同。
    • v1[]=1&v2[]=2
  • 分析:
    • isset($_GET['v1'])isset($_GET['v2']) 都为真,因为参数存在。
    • $_GET['v1'] !== $_GET['v2']:数组[1][2]显然不相等,满足条件一。
    • md5($_GET['v1'])md5($_GET['v2']):因为传入的是数组,所以都返回NULLNULL === NULL为真,满足条件二。
  • 访问 http://[题目URL]/index.php?v1[]=1&v2[]=2 即可得到flag。

利用特定字符串的MD5碰撞(0e前缀)

  • 寻找两个不同的字符串,它们的MD5值都是以0e开头。
    • 常见的碰撞对有:QNKCDZO240610708(还有其他组合,如 s878926199as155964671a 等)。
  • 构造Payload:
    • v1=QNKCDZO&v2=240610708
  • 分析:
    • isset($_GET['v1'])isset($_GET['v2']) 都为真。
    • $_GET['v1'] !== $_GET['v2']'QNKCDZO''240610708' 是两个不同的字符串,满足条件一。
    • md5('QNKCDZO') = 0e830400451993494058024219903391
    • md5('240610708') = 0e462097431906509019562988736854
    • 0e830400451993494058024219903391 === 0e462097431906509019562988736854:在PHP中,这两个字符串都被解释为0,因此比较结果为真,满足条件二。
  • 访问 http://[题目URL]/index.php?v1=QNKCDZO&v2=240610708 也可以得到flag。
  • 随机配图

将上述任一Payload输入到题目URL中,如果页面输出flag{xxxxxxxxxxxxxxxx},则说明我们的解法是正确的。

通过这道BugkuCTF Web3题目,我们学到了:

  1. 代码审计的重要性:仔细阅读代码逻辑,找出关键判断点和潜在的条件竞争或逻辑漏洞。
  2. PHP语言特性的掌握:了解PHP在处理数组、哈希函数(如md5())时的特殊行为,这些特性往往成为CTF题目的突破口。
  3. 哈希碰撞的概念:虽然MD5被认为是不安全的哈希算法,但在CTF中,利用已知的MD5碰撞字符串或数组绕过哈希比较是一种常见技巧。
  4. Payload的构造与测试:根据分析结果,灵活构造不同的Payload进行尝试,并验证其正确性。

CTF学习是一个不断积累和实践的过程,Web3这类题目虽然简单,但蕴含的基础知识非常重要,希望大家通过本文的解析,能够对PHP特性和代码审计有更深的理解,在CTF的道路上越走越远!


本文由用户投稿上传,若侵权请提供版权资料并联系删除!