记一次对CTF青龙组历年真题的自我理解

admin 2020年12月22日17:18:50评论303 views字数 1729阅读5分45秒阅读模式

记一次对CTF青龙组历年真题的自我理解

打开题目,我们可以看到的是这样一个页面


记一次对CTF青龙组历年真题的自我理解

记一次对CTF青龙组历年真题的自我理解


记一次对CTF青龙组历年真题的自我理解


记一次对CTF青龙组历年真题的自我理解


当我看到unserialize的时候 我知道了 这是一道PHP反序列化的题目了

在这里我先说一下反序列化的常年事故:

什么是反序列化:

php程序为了保存和转储对象,提供了序列化的方法,php序列化是为了在程序运行的过程中对对象进行转储而产生的。序列化可以将对象转换成字符串但仅保留对象里的成员变量,不保留函数方法。

php序列化的函数为serialize。反序列化的函数为unserialize。


基本上都是围绕着 这两个函数来展开的

通俗的说反序列化 和 序列化的意思就是:

序列化:将对象转换成字符串

反序列化:将序列化后的字符串转换为对象 还原

这两个关系相当于一正一反

接下来我们来介绍对象中的魔术方法:

__construct:在创建对象时候初始化对象,一般用于对变量赋初值。

__destruct:和构造函数相反,当对象所在函数调用完毕后执行。

__toString:当对象被当做一个字符串使用时调用。

__sleep:序列化对象之前就调用此方法(其返回需要一个数组)

__wakeup:反序列化恢复对象之前调用该方法

__call:当调用对象中不存在的方法会自动调用该方法。

__get:在调用私有属性的时候会自动执行

__isset()在不可访问的属性上调用isset()或empty()触发__unset()在不可访问的属性上使用unset()时触发


这道题目我们主要介绍这两个魔术方法:

__construct  构造方法 在对象调用的时候触发


记一次对CTF青龙组历年真题的自我理解


在对象调用的时候 会执行__construct里面的代码

__destruct 恰好跟构造方法相反 在对象销毁的时候调用


记一次对CTF青龙组历年真题的自我理解


查看一下


记一次对CTF青龙组历年真题的自我理解


在对象销毁的时候就是结束的时候会调用这个析构方法

我们再来看一下反序列化 和 序列化的这个函数

序列化:


记一次对CTF青龙组历年真题的自我理解


输出为:


记一次对CTF青龙组历年真题的自我理解


为什么输出这么一个字符串

O:2:"AB":1:{s:4:"name";N;}

这个字符串的意思就是:

O 代表 object 对象的意思

2 代表2个元素

AB 是对象的名字

S 代表string类型


接下来我来解开这道题:


记一次对CTF青龙组历年真题的自我理解


可以看到isset判断get传过来的参数有没有数据

然后if判断,这里用到了一个过滤的函数 我们不用管

$obj = unserialize($str);

这里使用到了一个反序列化的函数

反序列化 GET传过来的参数


记一次对CTF青龙组历年真题的自我理解


然后我们可以看到这里

当对象结束(销毁)的时候会调用这个函数

我们可以看到if 判断 op === “2” 注意:这是三个等于号

强制给他转换成”1”

在这里我们可以绕过这个限制

利用php弱类型的特性 我们可以想象把op想象成 “  2” (空格2)

这样子就不会执行后面的这个语句了

然后他调用了$this->process() 这个函数


记一次对CTF青龙组历年真题的自我理解


我们可以看到 如果op == “1” 他会调用write 写入函数 如果op == “2” 的话他会调用查看函数

既然我们要拿flag 当然查看比较好了

上面说过 op == “  2”(空格2) 因为他会自动转换 注意这次是二个等于号

php比较的时候如果和数字比较会把不是数字的转换成数字在进行比较

相互之间会互相转换!

这样我们会执行这个函数:


记一次对CTF青龙组历年真题的自我理解


这样子就可以拿到flag 肯定有人会问filename要怎么构造?

我们来构造这个语句:


记一次对CTF青龙组历年真题的自我理解


整体的语句是这样子的

我来解释一下:

定义这个类 必须和题目的类名是一样的

Public 这是权限修饰符 最高权限 谁都可以访问的 公共的

我们定义 op = ‘  2’(空格2

Filename  = “flag.php”

Contennt 给随便的值都是可以的

然后我们来new 这个对象

这时候我们来 serialize 序列化这个对象 $flag01 = serialize($flag);

因为题目要反序列化 我们写的化当然是要来序列化

序列化的结果就是:


记一次对CTF青龙组历年真题的自我理解


O:11:"FileHandler":3:{s:2:"op";s:2:" 2";s:8:"filename";s:8:"flag.php";s:8:"contennt";s:2:"nc";}

序列化之后的结果就是这样子的 这就是我们最终的payload

我们直接把payload放上去执行:


记一次对CTF青龙组历年真题的自我理解


这时候我右键源代码:


记一次对CTF青龙组历年真题的自我理解


这就是flag的值


记一次对CTF青龙组历年真题的自我理解

本文始发于微信公众号(疯猫网络):记一次对CTF青龙组历年真题的自我理解

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2020年12月22日17:18:50
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   记一次对CTF青龙组历年真题的自我理解http://cn-sec.com/archives/214242.html

发表评论

匿名网友 填写信息