官方文件中介紹PHP序列化和反序列化如下: (推薦學習:PHP視訊教學)
所有php裡面的值都可以使用函數serialize()來返回一個包含位元組流的字串來表示。unserialize()函數能夠重新把字串變回php原來的值。序列化一個物件將會儲存物件的所有變數,但是不會儲存物件的方法,只會儲存類的名字。為了能夠unserialize()一個物件,這個物件的類必須已經定義過。如果序列化類A的一個物件,將會返回一個跟類A相關,而且包含了物件所有變數值的字串。
簡單說序列化是物件轉化字串的過程,反序列化是字串還原物件的過程。
環境
文章中所述內容使用環境如下:
PHP7.3.1、SDK VSCode C++和C
環境設定建議參考:《WINDOWS下用VSCODE偵錯PHP7原始碼》
在網上公開引數反序列化執行流程已經非常詳細,但是對於一些細節地方有一些不足,其中就包括序列化和反序列化之間的語法差異問題
差異問題
序列化
我們通過編譯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行,對於內嵌方法進行拼接。
反序列化
反序列化是將序列化的字串,按照一定語法規則進行轉化還原。
[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) < 7) YYFILL(7); yych = *YYCURSOR; switch (yych) { case 'C': case 'O': goto yy4; case 'N': goto yy5; case 'R': goto yy6; case 'S': goto yy7; case 'a': goto yy8; case 'b': goto yy9; case 'd': goto yy10; case 'i': goto yy11; case 'o': goto yy12; case 'r': goto yy13; case 's': goto yy14; case '}': goto yy15; default: goto yy2; } Line:776 yy15: ++YYCURSOR; { /* this is the case where we have less data than planned */ php_error_docref(NULL, E_NOTICE, "Unexpected end of serialized data"); return 0; /* not sure if it should be 0 or 1 here? */ }
通過核心程式碼能夠看到第655行進入反序列化,反序列化是利用詞法掃描,判斷各項符號轉換對應物件。能夠看到反序列化中對於}進行了處理,處理中只是對計數器加一並沒有其他操作。
實際作用
反序列化語法的差異,對於安全防護裝置判斷反序列化產生很大的影響。在Snort中,有段規則如下:
alert tcp any any -> any [80,8080,443] (uricontent:".php"; pcre:"/{w:.+?}/"; sid:1; msg:php_serialize;)
在攻擊載荷中可以使用大多數位符代替{},從而導致規則失效。
總結
在紅隊攻擊中可以利用PHP序列化和反序列化語法差異,從而達到繞過防護的目的。
在藍隊防禦中建議考慮定義中所述不會儲存物件的方法,只會儲存類的名字。,攔截儲存類的名字,以及語法中相同的字元比如冒號進行防禦。
以上就是PHP序列化和反序列化語法差異問題的詳細內容,更多請關注TW511.COM其它相關文章!