首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

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

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

解题关键点

.phps文件

浏览器先对URL编码解码一次

PHP中的宽松比较和严格比较

什么是.phps文件?

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

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

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

XCTF题目分析:PHP2

<?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"就授予访问权限。这看起来是不是有点矛盾?实际上,这里隐藏着一个巧妙的陷阱。

代码深入分析

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

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

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

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

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

PHP中的比较运算符

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

=== 是严格比较,它不仅比较值,还比较类型。

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

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

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

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

绕过思路

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

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

第二次编码:%61%64%6d%69%6e %2561%2564%256d%2569%256e

为什么需要两次编码?

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

浏览器首先将%2561%2564%256d%2569%256e解码为%61%64%6d%69%6e

这个值传递给服务器,通过第一个if检查(因为它不等于"admin")

PHP代码中的urldecode()函数再次解码,得到"admin"

最后一个if语句检查通过,我们获得了访问权限

三次编码尝试

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

第二次编码:%61%64%6d%69%6e %2561%2564%256d%2569%256e

第三次编码:%2561%2564%256d%2569%256e %252561%252564%25256d%252569%25256e

结果会是什么呢?

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

浏览器解码一次,变成:%2561%2564%256d%2569%256e

服务器接收到的值是%2561%2564%256d%2569%256e,通过第一个if检查

PHP的urldecode()函数解码一次,变成:%61%64%6d%69%6e

最后的if语句比较时,%61%64%6d%69%6e不等于"admin",所以不会显示flag

四次编码尝试

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

第二次编码:%61%64%6d%69%6e %2561%2564%256d%2569%256e

第三次编码:%2561%2564%256d%2569%256e %252561%252564%25256d%252569%25256e

第四次编码:%252561%252564%25256d%252569%25256e %25252561%25252564%2525256d%25252569%2525256e

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

浏览器解码一次,变成:%2561%2564%256d%2569%256e

服务器接收到的值是%2561%2564%256d%2569%256e,通过第一个if检查

PHP的urldecode()函数解码一次,变成:%61%64%6d%69%6e

最后的if语句比较时,%61%64%6d%69%6e不等于"admin",所以不会显示flag

结语

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

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

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

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OnkPStitO84KgatXu659xqUw0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券