介绍官方文档对PHP序列化和反序列化的介绍如下:php中的所有值都可以使用函数serialize()返回一个包含字节流express的字符串。unserialize()函数可以将字符串改回PHP的原始值。序列化对象会保存对象的所有变量,但不保存对象的方法,只保存类名。为了能够unserialize()对象,对象的类必须已经定义。如果序列化A类的对象,将返回一个与A类相关并包含该对象所有变量值的字符串。简单的说,序列化就是将一个对象转换为字符串的过程,而反序列化就是将一个对象从字符串中还原出来的过程。环境篇描述内容的使用环境如下:PHP7.3.1、SDKVSCodeC++和C公共参数反序列化执行过程网上已经很详细了,但是在一些细节上还有不足之处,包括序列化和反序列化语法差异问题。不同点1.序列化我们编译了PHP内核源码分析,发现PHP序列化默认加入了对象转换:{和}用来拼接字符串。[var.c]行:882staticvoidphp_var_serialize_intern()行:896if(ce->serialize(struc,&serialized_data,&serialized_length,(zend_serialize_data*)var_hash)==SUCCESS){smart_str_appendl(buf,"C:",2);smart_str_append_unsigned(buf,ZSTR_LEN(Z_OBJCE_P(struc)->name));smart_str_appendl(buf,":\"",2);smart_str_append(buf,Z_OBJCE_P(struc)->name);smart_str_appendl(buf,"\":",2);smart_str_append_unsigned(buf,serialized_length);smart_str_appendl(buf,":{",2);smart_str_appendl(buf,(char*)serialized_data,serialized_length);smart_str_appendc(buf,'}');}行:952smart_str_appendl(buf,":{",2);行:995smart_str_appendc(buf,'}');我们看上面的代码,PHP会使用smart_str_appendl来回拼接序列化后的字符串:{和},从var.c的第一行882行开始进入序列化逻辑。第896行对序列化字符串进行拼接,第952、995行对嵌入方法进行拼接。2.反序列化反序列化就是将序列化后的字符串按照一定的语法规则进行转换和还原。[var_unserialize.c]行:655staticintphp_var_unserialize_internal()行:674{YYCTYPEyych;staticconstunsignedcharyybm[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,128,128,128,128,128,128,128,128,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};if((YYLIMIT-YYCURSOR)<7)YYFILL(7);yych=*YYCURSOR;switch(yych){case'C':case'O':gotoyy4;case'N':gotoyy5;case'R':gotoyy6;case'S':gotoyy7;case'a':gotoyy8;case'b':gotoyy9;case'd':gotoyy10;case'i':gotoyy11;case'o':gotoyy12;case'r':gotoyy13;case's':gotoyy14;case'}':gotoyy15;default:gotoyy2;}行:776yy15:++YYCURSOR;{/*thisisthecasewherewehavelessdatathanplanned*/php_error_docref(NULL,E_NOTICE,"Unexpectedendofserializeddata");return0;/*notsureifitshouldbe0or1here?*/}通过内核代码我们可以看到655行进入反序列化,反序列化使用词法扫描。判断各种符号转换对应的对象,我们可以看到在反序列化的时候已经对}进行了处理,处理只是给计数器加一,没有其他操作。反序列化语法的差异对安全防护设备对反序列化的判断影响很大。在Snort中,有一个段规则如下:alerttcpananyany->any[80,8080,443](uricontent:".php";pcre:"/\{\w:.+?\}/";sid:1;msg:php_serialize;)大多数字符都可以在攻击负载中代替{}使用,这将使规则无效。总结在红队攻击中,可以利用PHP序列化和反序列化的语法差异来达到绕过保护的目的。在蓝队防御中,建议考虑定义中描述的不保存对象,只保存类名的方法,截取保存类的名称,以及语法中的冒号等相同字符进行防御。
