介紹
官方文檔中介紹php序列化和反序列化如下:
所有php里面的值都可以使用函數serialize()來返回一個包含字節流的字符串來表示。unserialize()函數能夠重新把字符串變回php原來的值。 序列化一個對象將會保存對象的所有變量,但是不會保存對象的方法,只會保存類的名字。 為了能夠unserialize()一個對象,這個對象的類必須已經定義過。如果序列化類A的一個對象,將會返回一個跟類A相關,而且包含了對象所有變量值的字符串。
簡單說序列化是對象轉化字符串的過程,反序列化是字符串還原對象的過程。
環境
文章中所述內容使用環境如下:
立即學習“PHP免費學習筆記(深入)”;
PHP7.3.1、SDKVSCodeC++和C
在網上公開參數反序列化執行流程已經非常詳細,但是對于一些細節地方有一些不足,其中就包括序列化和反序列化之間的語法差異問題。
差異問題
1、序列化
我們通過編譯PHP內核源碼分析,發現PHP序列化在默認情況下在對象轉換中加入:{和}用來拼接成字符串。
[var.c] Line:882 static?void?php_var_serialize_intern() Line:896 if?(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,?'}'); ????????????????????} Line:952 smart_str_appendl(buf,?":{",?2); Line:995 smart_str_appendc(buf,?'}');
咱們來看上面這段代碼,PHP會使用smart_str_appendl為序列化字符串前后拼接:{和},從var.c的第882行開始進入序列化邏輯。在第896行進行序列化字符串拼接,第952行和第995行,對于內嵌方法進行拼接。
2、反序列化
反序列化是將序列化的字符串,按照一定語法規則進行轉化還原。
[var_unserialize.c] Line:655 static?int?php_var_unserialize_internal() Line:674{ ????YYCTYPE?yych;???? ????static?const?unsigned?char?yybm[]?=?{?????????? ??????????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)?<p>通過內核代碼能夠看到第655行進入反序列化,反序列化是利用詞法掃描,判斷各項符號轉換對應對象。能夠看到反序列化中對于}進行了處理,處理中只是對計數器加一并沒有其他操作。</p><p style="box-sizing: border-box; font-family: 微軟雅黑; line-height: 1.1; color: rgb(55, 56, 56); margin: 30px 0px 15px; font-size: 18px; white-space: normal; background-color: rgb(255, 255, 255);"><strong>實際作用</strong></p><p>反序列化語法的差異,對于安全防護設備判斷反序列化產生很大的影響。在Snort中,有段規則如下:</p><pre class="brush:php;toolbar:false">alert?tcp?any?any?->?any?[80,8080,443]?(uricontent:".php";?pcre:"/{w:.+?}/";?sid:1;? msg:php_serialize;)
在攻擊載荷中可以使用大多數字符代替{},從而導致規則失效。
總結
在紅隊攻擊中可以利用PHP序列化和反序列化語法差異,從而達到繞過防護的目的。
在藍隊防御中建議考慮定義中所述不會保存對象的方法,只會保存類的名字。,攔截保存類的名字,以及語法中相同的字符比如冒號進行防御。
相關文章教程分享:網站安全教程