PHP解码陷阱:一次编码不够,两次编码刚好!

admin 2024年10月10日22:01:11评论15 views字数 2987阅读9分57秒阅读模式
PHP解码陷阱:一次编码不够,两次编码刚好!

大家好,我是V浪,欢迎来到HW安全之路。今天,我看到了一个CTF题目:攻防世界-XCTF体验题库 : PHP2,但是官方的WP写的不是太清楚,今天我们一起看看这道题。

解题关键点

  1. .phps文件
  2. 浏览器先对URL编码解码一次
  3. PHP中的宽松比较和严格比较

什么是.phps文件?

在开始我们的主题之前,让我们先了解一下.phps文件。这可能是很多人都不太熟悉的文件类型。

.phps文件实际上是PHP的源代码文件(PHP Source)。它的主要用途是允许用户直接查看PHP代码。为什么需要这种文件呢?因为普通的.php文件在服务器上执行后,用户通过Web浏览器只能看到执行结果,而无法看到背后的代码。而.phps文件则允许我们直接查看PHP的源代码。

这在学习和调试过程中非常有用。但是请注意,在生产环境中暴露.phps文件可能会带来安全风险,因为它可能泄露敏感信息或程序逻辑。

XCTF题目分析:PHP2

让我们通过一个实际的CTF题目来深入理解PHP编码绕过。题目要求我们访问http://111.198.29.45:45191/index.phps,得到以下PHP代码:

<?php
if("admin"===$_GET[id]) {
    echo("<p>not allowed!</p>");
    exit();
}

$_GET[id] = urldecode($_GET[id]);

if($_GET[id] == "admin")
{
    echo "<p>Access granted!</p>";
    echo "<p>Key: xxxxxxx</p>";
}
?>

乍一看,这段代码似乎设置了一个不可能的条件:如果id等于"admin"就拒绝访问,但是紧接着又说如果id等于"admin"就授予访问权限。这看起来是不是有点矛盾?实际上,这里隐藏着一个巧妙的陷阱。

代码深入分析

让我们逐行分析这段代码:

  1. 第一个if语句使用了严格比较(===)来检查id是否等于"admin"。如果是,就会显示"not allowed!"并终止程序。

  2. 接下来,代码对$_GET[id]进行了URL解码。这一步很关键,它改变了id的值。

  3. 最后,使用宽松比较(==)再次检查id是否等于"admin"。如果是,就授予访问权限并显示key。

这段代码的诡异之处在于,它给了我们一个机会在两次检查之间修改id的值。

PHP中的比较运算符

在继续之前,我们需要理解PHP中"==="和"=="的区别:

  • === 是严格比较,它不仅比较值,还比较类型。
  • == 是宽松比较,它只比较值,如果类型不同,PHP会尝试进行类型转换。

URL编码:CTF选手的"隐形斗篷"

URL编码是一种将字符转换为可以在URL中安全传输的格式的方法。例如,空格会被编码为"%20"。在我们的例子中,我们可以利用URL编码来"隐藏"admin字符串。

"admin"经过一次URL编码后变成:%61%64%6d%69%6e

如果我们再对这个结果进行一次编码,就会得到:%2561%2564%256d%2569%256e

绕过思路

现在我们的目标很明确:找到一个值,在第一次检查时不等于"admin",但经过URL解码后等于"admin"。

解决方案就是对"admin"进行两次URL编码:

  1. 第一次编码:admin → %61%64%6d%69%6e
  2. 第二次编码:%61%64%6d%69%6e → %2561%2564%256d%2569%256e

最终,我们应该访问的URL是:http://111.198.29.45:45191/index.php?id=%2561%2564%256d%2569%256e

为什么需要两次编码?

这里有一个关键点需要理解:当我们在浏览器中输入URL时,浏览器会自动对URL进行一次解码。这意味着:

  1. 浏览器首先将%2561%2564%256d%2569%256e解码为%61%64%6d%69%6e
  2. 这个值传递给服务器,通过第一个if检查(因为它不等于"admin")
  3. PHP代码中的urldecode()函数再次解码,得到"admin"
  4. 最后一个if语句检查通过,我们获得了访问权限

三次编码尝试

既然两次编码可以成功,那么三次编码会怎么样呢?让我们来试试:

  1. 第一次编码:admin → %61%64%6d%69%6e
  2. 第二次编码:%61%64%6d%69%6e → %2561%2564%256d%2569%256e
  3. 第三次编码:%2561%2564%256d%2569%256e → %252561%252564%25256d%252569%25256e

我们尝试访问:http://111.198.29.45:45191/index.php?id=%252561%252564%25256d%252569%25256e

结果会是什么呢?

实际上,这个URL不会成功获取flag。原因如下:

  1. 浏览器解码一次,变成:%2561%2564%256d%2569%256e
  2. 服务器接收到的值是%2561%2564%256d%2569%256e,通过第一个if检查
  3. PHP的urldecode()函数解码一次,变成:%61%64%6d%69%6e
  4. 最后的if语句比较时,%61%64%6d%69%6e不等于"admin",所以不会显示flag

四次编码尝试

那么,如果我们进行四次编码呢?

  1. 第一次编码:admin → %61%64%6d%69%6e
  2. 第二次编码:%61%64%6d%69%6e → %2561%2564%256d%2569%256e
  3. 第三次编码:%2561%2564%256d%2569%256e → %252561%252564%25256d%252569%25256e
  4. 第四次编码:%252561%252564%25256d%252569%25256e → %25252561%25252564%2525256d%25252569%2525256e

我们尝试访问:http://111.198.29.45:45191/index.php?id=%25252561%25252564%2525256d%25252569%2525256e

这个URL同样无法获取flag。原因如下:

  1. 浏览器解码一次,变成:%252561%252564%25256d%252569%25256e
  2. 服务器接收到的值是%252561%252564%25256d%252569%25256e,通过第一个if检查
  3. PHP的urldecode()函数解码一次,变成:%2561%2564%256d%2569%256e
  4. 最后的if语句比较时,%2561%2564%256d%2569%256e不等于"admin",所以不会显示flag

结语

通过这个CTF题目,我们深入探讨了PHP中URL编码绕过的原理。我们发现,在这个特定的例子中,两次编码是获取flag的关键。三次或四次编码虽然看起来更复杂,但实际上无法成功绕过检查。

这个例子告诉我们,在CTF比赛中,有时候最简单的解决方案可能就是正确的。过度复杂化可能会适得其反。同时,它也展示了理解底层原理的重要性。只有真正理解了URL编码、浏览器行为和PHP的解码过程,我们才能成功解决这样的挑战。

下次再见,我是V浪,我们HW安全之路上再相会!

原文始发于微信公众号(HW安全之路):PHP解码陷阱:一次编码不够,两次编码刚好!

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年10月10日22:01:11
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   PHP解码陷阱:一次编码不够,两次编码刚好!http://cn-sec.com/archives/3251048.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息