fastjson 序列化 不包括转义字符_CTFweb类型(二十二)反序列化的基本概念、魔术方法及相关例题讲解...

f577791c2b02e1e8300bb4c266d1113e.gif

点击上方蓝色字体,关注我们

反序列化的特征有点类似于命令执行,首先要理解反序列化的概念以及它的场景,像CTF中看到某些特征的时候,可以猜测这道题目是否做反序列化。

我们先来理解一下这个概念,反序列化和序列化它其实是对应的就是一个数据的持久化和非持久化的一个过程。就是说一开始我们就是一个变量,去申请一个变量,这个变量其实你要把它保存下来的时候怎么保存?比如说我在这边一个php > $a的时候,我定 $a=1它对1有,但是如果说我在我把shell给关掉之后,$a其实就已经不存在了,那么这个时候它其实就是相当于只能在这一次中去使用。

序列化的目的是希望能够把变量存储在本地,相当于我把这个$a复制出来,知道这个地方$a了,那么下次我要新开一个shell的时候,把复制再粘贴进去,这个$a就会重新回值又可以再次利用,所以对应相反的过程就是反序列化。

1e48a6a2132a991a9ba600130f6ffe99.png序列化和反序列化的目的就是为了程序之间,传输对象会更加方便。 1e48a6a2132a991a9ba600130f6ffe99.png

080eb611c0d29f0e0c965a17390ec112.png

1e48a6a2132a991a9ba600130f6ffe99.png这里提到的是传输对象对应到php中,一般来说就是一个object,对应的是class,就是一个类,在php中A类也可以去申请一个对象,一个$a然后class中其实有对应的一些变量,可以对它做赋值之类的,其实也可以理解成是一个变量。 1e48a6a2132a991a9ba600130f6ffe99.png

为了让这种对象阐述得更方便,所以就产生了序列划分序列化的一个概念。

要注意到序列化,就是一般我们常说的变量,那么它就是一个内存数据,所以这里用的形容词就是稍纵即逝。通常程序结束执行之后就会销毁掉,不销毁会占用内存,那它不是一个持久化的数据。那么序列化刚才讲到了,它的作用是能够让一个非持久化的数据变成一个持久化,也就是把变量保存到本地,虚拟化的目的就是能够让一个变量变成一个可以保存到本地的一个东西。内存变为文件就是是虚拟化的一个简单的概念。反过来,反序列化是把文件变成一个内存,根据我们保存来的文件或者这个内容,能够把它恢复出来,恢复成一个变量。 

当然了,如果有必要把整个代码复制下来,也可以去保存变量,肯定没有这么复杂,相对来说比较简化。恢复程序代码反序列化过程:由变量变成文件,文件变成变量。

相关函数(代码注入) 1e48a6a2132a991a9ba600130f6ffe99.png正常情况下提到的序列化和反序列化,一般会涉及到两个函数,第一个serialize这就是系列的意思,会产生一个可存储的值的表示。对我们刚才讲到的就是文件可存储的,就是序列化的作用,就是把一个变量,你会看到它的next,输出的时候是string,这个字符串方便我们去存储。 1e48a6a2132a991a9ba600130f6ffe99.png

75b36be6ca31fe6fcd36f356e121b05f.png

反序列化的函数就是unserviceable,能看到它就是从已存储的表中创建php的值,所以它的目的就是去申请一个php的值,在serviceable或者unserviceable过程中可以去猜测它是否有搞反序列化,但是很多时候它不一定会有这两个函数存在,这个只是特征之一。

626a34cf527e72b34b5b4ad458ae5d2a.png

序列化 2fe36310a52a0dd404118cf4ea44505d.gif

class非常简单,test_class进行测试,它里面是一个变量public $ date,给它赋一个值,这里的函数会打印出来。如果存在class,那么我们object去定一个变量去创建一个对象,就是newclass,这个就是类名。创建这样一个对象,这里没有对它做一个赋值,直接去调用对象中的方法。现在做对象object,对应的就是class,申请了一个对象,然后我们确定它里面的方法做打印。

ef2b6fe936db6aa1cb45cf7a52a21c06.png

会打印出来这么一个字母,这就是非常正常的一个class,如果在另一个地方想用class的时候,把它移植出来,把object在另一个php文件中用到必然要做的事情就是把这串代码都复制过去。

如果在这里,给它做了一个改变,object->date =”123”的时候,这里再去执行一下,对它做了一个负值改变,这个时候它打印出来的时候,它就会变的,说明这个时候去改变了data的值,对应的对象已经发生了改变。我这个时候想要它的class对应的对象需要把这些代码都复制下来,无论我这个地方怎么去变化,它对应到的只是类似这样的一个模板,是基于这个模板在变化的。

2434e32ebbae29ad58b2a986a3d0d6ec.png

所以对应到的就是一个serialize的过程,其实就是序列化。可以看一下这个地方其实对应到的就是一个class,这里先定义一个class,它里面一个方式其实是类似的一个结构,然后另一边,先去创建一个对象,创建完对象之后,把对面赋值。比如说A女18岁,名字叫李耳,然后打印出来输出序列化的,然后你注意到这时候我就对它做了一个echo serialize ($usr)就是我对这个对象做了一个序列化,你会发现它输出来这么一串字符串。 

c9e1171a98f8db9a3be89c758a526989.png

这个字符串其实就是我们刚才说到序列化之后输出的一个字符串,通过这个字符串我们再配合class,我们就能够恢复出这个对象。就是这样的一个效果,其实也就意味着只要我有这个值,也知道有这个模板,就能够恢复出class。

假如说我在第二个问题中需要调用的时候,只要有class和这个序列其实我就可以恢复出来了,可能一开始不知道,觉得不太理解,为什么要这样做,后期自然就会理解到,为什么会有这样的一个操作在这里头。

a4da326545e2ff7f999b28ac05cafbfb.png 

虚拟化其实就是这样的一个结构,这个地方不局限于有O对象在里面,很多时候都可以去试看,也可以做一个反序列化的,比如$a = [1,2,3]。对这个数组做序列化。Serialize($a)你会发现这个时候的话就不一样了。它其实是一个数组,数组是a,它里面3的话对应的就有3个。三个值123刚刚对应,那对应的你会看,再看一下就发现是i:0;i:1;i:1;i:2;i:2;i:3 0对应的是1,1对应的是2,相当于前面那是数组的序号,那么第二个就是它的值,数值也可以做一个反序列化,这就是序列化的一个过程。

反序列化理解

虚拟化之后当然要去看反序列化了,漏洞都说叫反序列化漏洞,那就要理解一下反序列化的过程,其实刚才就讲了,就是把序列反回去变成一边一个对象,重建对象过程,比如说这模板还在,对它做一个unserialize 把刚才的字符串。

8fbb12aab07673f7cde7c860e1a718b8.png

做个反序就会把它赋给$usr然后这时候再去调,print_date的时候,能够做一个输出,说明这里对应的class其实就是usr,调的是这个函数,它输出的结果是有值的,这个值其实来自于序列反序列化之后的一个输出。其实你会发现,这边能控制的还是变量,

所以说反序列化的,它还是有局限性的,和你的能够使用的function是有关系的,不可能无限制的去创造去想象。所以它跟命令执行有一定的相关性,但是也不是完全的一模一样。可以说从某种程度上来说,它是一种命令自身的方法命令可以归进去。

魔术方法

那么反序列化讲完之后,最主要的接下来就讲魔术方法。如果没有这个调用过程,其实你会发现你对她做了一个反序列化之后,相当于只是申请了一个对象变量,什么事情都不会发生,不会有危害,但是一旦配合上魔术方法的时候,那么它就会变成了另一种情况。在php中其实有非常多一两个下划线开头的function,我们就把它称为魔术方法。

19f017b35bea5e0f6d153f419d75d5fa.png

14b1e804e9e2c129ee234342035c8dca.gif

有个_sleep()、_wakeup()在执行serialize之前会先去调动这个函数,像刚才这个地方,你做个unserialize那么你第二个方法是你这个地方是主动调用的,虽然没有看到它去有什么效果实现,它会先去做一次_wakeup(),类似function其实没有定义什么东西的,根本看不到效果,比如说对应的类构造函数这些,这些都可以简单看一下。

这里有些代码,我们可以来看一下它的一个效果。就是说我们这是这样子的,刚才讲到了拿反序列化的过程来说,它会先去使用_wakeup(),那么我们其实就可以给它做一个同名的反过去,因为它说它在虚拟化之前它会做一个调用,如果说反序列化过程存在,那么它必然会再做反序列化之前去执行这个东西。

第一个echo反序列化,echo反序列化完成,如果说它这里确实有调用,那么它肯定会在这里打印出echo wakeup 。就相当于让你们更加明显的看到它确实去做了这一次操作。这里就包括了很多的函数:

3bfbe69b7e614864fab1dfb0054b3360.png

14b1e804e9e2c129ee234342035c8dca.gif

拿_construct()它来说,就类的构造函数disk之类的析构函数后面会讲到,它肯定是和类的调用是有关系的,那你会可以看一下它在什么时候会去调用。

你会发现准备创建对象,对象创建完成,即使你去创建一个新的对象的时候,它就会直接去调用_construct()。所以这个地方它其实就是在调用新对象的时候看出来了,它就会做一个被调用的一个过程。

准备反序列化的话就是unserialize, _wakeup()这种方法就没什么,就是有一个destruct。它这里其实会有两次的destruct,第一次的话其实是由于反序列化结束后去做了一次额外调用。然后第二次的话就是整一个脚本的结束,去再调用一次destruct,所以destruct就是相当于整个结束之后去释放的过程中会去调用。

很多过程,它其实不止会去执行我们去定义的,我们你看我们现在明面上去定义的一些方法,很多时候它其实会执行一些默认的方法。对应到这里就会有很多那么反序列,其实就会有一些关键的点,要关注的重点其实就在于这几个。比如说第一个_construct和destruct。这里提到了就是说会在内向对象创建或者销毁时做一个调用。

如果说删除的东西你可控,那么就会变成一种删除漏洞。那么还有这里面看到这里多了一个_toString(),它的话其实就相当于你做echo的时候,如果通过_toString()打印对象体推销的话,就会自动去调用,相当于你echo这个对象的时候,它就会自动去调用function,就是看到打印过程,它就会去调用这个,其实整个基本的过程已经讲讲了,就是说序列化反序列化模式方法,但是这样讲完之后,其实还是没什么感觉,不知道它的问题会出在哪里,看一道简单题目来理解一下,它到底会有什么问题,这道题目的话其实比较简单,但是确实比较简单,也方便大家理解。

6a9873cd07745af42fc21fa28f10fbc0.png

 这道题目的话是bug库的一道题目,应该你们都可以访问到是XCTF2016年的一道题目,右键源代码看一下,结果你会看到它会有一段源代码放在这边,你就可以看了就变成读读代码,看有什么缺陷。

0ee5124c7d9b72855adf2e4ce103fcfc.png

 它代码意思就是就让你去传一个$usr,用file_get content。如果要file_get,content,之前应该讲到过,就用input去传一个值,比如说php input它能够读取到原生的post的数据,比如说我这里去看一下,就直接把这个值给赋值过去。然后把这个值给它放进去,我们看一下效果,说明肯定我们这个值传进去了。

a8818b74d32b9e0dc322b4f9fa2ec5a4.png

4fa07934519a8fe81ebed2a95fcc9edc.png

14b1e804e9e2c129ee234342035c8dca.gif

Base64  做个转码,看到它这句话就是有一个class。刚才讲到了,在echo的时候,会去做一个调用,然后你会发现这个东西有一个file_get content读文件的意思 $disfile它就会去读file这个变量其实如果说我能够控制$disfile,然后能够去触发这个方式,就能够去也是实现个任意文件读取,其实这个地方它其实就会引出来,目的就是去实现控制,能够去对class实现一个确认,赋$disfile给它一个flag这个值,然后能够触发function,所以目的就是这样子,那么有了前提条件之后,我们就能进一步去往下想,既然讲到了我们去读flag的时候,它检测我们的flag有没有什么方法能够过滤掉绕过什么之类的,所以说我们就可以去换继续去读取index.php,也就是我们的主页,我们把它给读取出来看一下。

这个就是打印出来的内容,然后这个的话就是一段,这个地方其实肯定是中文的员工,然后它这里没办法显示,其实就是正常情况下,base64中文都会有问题,就网上找在线才可以,然后你会看到到这个地方它会去做一个正则匹配去整个匹配,是否你传的file中是否有flag的话,它就没有办法了。

然后你会看到下面看到有一个到include $file,

58072464f852c8d50f80b1cd664f376a.png

 会包含这个文件,然后password就unserialize($password)、echo password。这里就存在一个过程——触发echo的过程,如果定义了_toString这个方法,在测试的时候,做一个echo打印对象体,就直接去打印对应的object,也就是unserialize之后回来的一个对象,它做个打印的时候,会自然的去触发function。如果触发了function,我们就可以去实现里面的操作,如果能够控制$file,就能够对它实现一个读取文件,其实整个思路很简单,它对实现的反序列化的时候,我们去构造序列,虚拟构造其中肯定是基于class在构造,这个class的话你可以就去申请一下,比如说$a =new flag。

d8cf6d46df918956a59d4177dc13b608.png

 这样生起来做一个对象,里面的值是没有的肯定要对它们的变量做一个赋值,比如$a->file=‘flag.php’ 这里有了这个对象,就要对它做一个echo serialize($a)

e87c2ed4a79bfd4d0df883543a9e4274.png

 想办法去实现一个调用,这时候就能够打印出一个字符串,那打印出来的字母串就是这个。

59faa3d0a28f46cd32ca1f89f590db4e.png

如果要反序列化成功这个类必须知道当前返回出来的模板是哪一个,所以$file要去包含的文件,肯定就是你要去包含的hint.php。再对应过来我们这repeater的时候,我们现在是对它实现了一个包含就是文件读取,我这里肯定是hin我们这时候文件包含的目的是让它去包含这个类,然后接下来就传一个pass。$pass就等于pass变量的值传进去,Password就等于序列。

6b024c6301099a01b52ce797c761561e.png

看到它就简单的实现了一个文件读取,整个过程其实就是一个反序列化的利用过程。你会发现里面有一个前面的那种文件读取,文件包含包含,只是一些铺垫,最主要还是这个地方。

0aeb7e8f294e69cc3e2c6c5fb7ca1281.png

14b1e804e9e2c129ee234342035c8dca.gif

会发现unserialize的过程存在一个反序列化,hint.php中存在一个对应的class,这class就有个_toSring()函数,_toSring()函数中包含了一个file_get content,那我的目的就是通过file_get content去夺取flag,那么_toSring()它的触发条件你给我们了,它自动会去触发,那么我们主要的目的就是能够控制$file,要怎么来控制?通过反序列化的序列来实现,因为我们序列可控,我们在基于class去生成序列,那么先定义class,然后去获取对象,在对象中做一个赋值生成序列,然后再传递过去,去实现一个利用。所以序列化肯定是基于已有的,正常情况下肯定是基于已有的function来做一个实现的。

6ef3ec6948d6e655bcf30ab127142cb0.gif

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值