(先写目前学到的喵~,之前的后面会补上的)
[TOC]
反序列化是什么喵?
先来了解一下序列化叭:序列化就是将数据转化成一种可逆的数据结构,而逆向的过程就叫做反序列化。
序列化的目的:方便数据的传输与储存
序列化数组
1 | $sites = array('baidu'=>'baidu123','count'=>10);//$sites创建一个数组 |
在网页中序列化之后得到:a:2:{s:5:”baidu”;s:13:”baidu123”;s:5:”count”;i:10;}
这里a为array(一个数组);s为string(一个字符串);i为int(一个整数)
2代表这个数组中有两个属性;5、13、5都代表的是属性的长度
在网页中反序列化格式:array(2){[“baidu”]=>string(13)”baidu123”[“count”]=>int(10)}
序列化对象
序列化时,只保存成员变量,不保存方法
1 | php |
在网页中打印的字符:
(1)O:1:”A”:3:{s:4:”var1”;s:5:”hello”;s:7:”*var2”;s:3:”tom”;s:7:”Avar3”;i:5;} (这一整个是对象喵,
属性是对象的一部分喵)
note:
| 访问修饰符 |
|---|
| public成员变量直接写 |
| protected成员变量前面要加%00*%00(经过URL编码),%00是不可打印字符,所以这也是{}中第二个字符串长度为7 的原因 |
| pravite成员变量前面要加上%00类名%00(这里类名为A) |
类中的魔法方法
魔术方法是什么喵?
官方一点:在 PHP 中,以两个下划线 __ 开头的方法被称为“魔术方法”。它们是一些特殊的方法,不会被你显式地调用,而是在满足特定条件或发生特定事件时,由 PHP 自动触发执行的。
看不懂是干啥的对吧,我也看不懂
我说白了➡_➡:魔术方法的作用就是 我想干点啥(比如我想创建一个对象,我输入new A() ,php引擎就知道我想要干啥,他自己调用一个魔术方法(即__construct()函数)帮我干了这件事,而这个方法可以是我自己定义的【个人理解,如有错误以后会更改的QAQ】
常用的魔术方法喵~(其实还有好多,这里先了解这四个)
| 函数 | 作用 |
|---|---|
__construct() 函数 |
一个对象被创建时被调用 |
__destruct() 函数 |
一个对象被销毁时被调用(在整个php代码结束的时候) |
__toString() 函数 |
当一个对象被当作字符串来使用时会被调用(常见场景:使用echo或print的时候被调用) |
__wakeup()函数 |
unserialize() 函数被“反序列化”(唤醒)时被调用unserialize()一个对象之前被调用 |
!注意:1)__toString()函数是有返回值的,必须返回一个string(字符串)类型的值。如果打印的是一个对象,就会输出 __toString() 方法返回的那个字符串
2)toString()函数和wakeup()函数的访问修饰符必须为public
SO,到现在也看不懂魔术方法能干什么对叭➡_➡,我也不知道,往下看看呢?
e.g.
1 | function __destruct() { |
look at this ➡_➡
这段代码是什么意思呢?它实现了一个“动态函数调用”。
它把储存在对象属性 name 里的字符串,当作一个函数的名字。
然后,它调用这个函数,并把 age 属性的值当作参数。
所以,试想一下,如果我把name里的值定为system;
再把age属性的值定位ls /(或者 cat /flag, whoami 等任意命令)
即
1 | $this->name = "system"; |
那么上面那段代码就等价于
1 | // $func 变成了 "system" |
system("ls /"); 有什么作用不言而喻了吧?
是不是对魔术方法如何使用有一点点的了解了呢?OwO(今天就写到这叭,晚安喵)
OK,书接上回➡_➡,我们来浅看一道小题(题目来源于learnctf,侵权删QAQ)
1 |
|
是不是有思路啦?我们就这样编写➡_➡
1 |
|
得到序列化的内容,再post进去就好啦~是不是简单捏?
常见绕过
1)__wakeup()函数绕过
| __wakeup()函数绕过 |
|---|
| 适用版本:PHP before 5.6.25 以及7.x before 7。0.10 |
| 原理:反序列化时,若表示对象属性个数的值大于真实的属性个数时,就会跳过__wakeup()函数的执行 |
来看栗子喵~
1 | php |
所以,__wakeup()是在__destruct()之前运行的,这会使得age的值永远等于18(这有什么后果捏?➡_➡
但我们是想利用__destruct()来查看根目录、获取flag,这根本没办法完成啊歪!
所以如果我们想要正常通过反序列化来得到flag就必须绕过__wakeup()函数(铿锵有力地说.jpg)
我们只需要把图中的2(真实的属性个数)改为任意一个比2大的数字(表示对象属性个数)就可以了喵~【注:图片只是其中的一步,并不全喵( ̄︶ ̄)↗】
2)引用绕过
&是引用符号喵~
来看个栗子~
1 | class Person { |
由php代码知,只有当name的值强等于age的值的时候,才会返回flag,但age的值又无法猜测,这怎么办哇?
这时候就需要用到引用,即&。那我们就这样写➡_➡
1 |
|
!这里有一个需要注意的点:为什么要把private改为public呢?
原本name和age都是私有的,在类外面是不能通过对象直接访问私有的,但改为public就不一样啦~
或者我们可以这样写php代码:
1 | php |
__construct()函数 是可以访问私有属性的喵~所以这样也可以获得flag啦
Leave a comment