はじめに
公式ドキュメントでは、PHP のシリアル化と逆シリアル化について次のように紹介されています。
php のすべての値はあなたです関数serialize()を使用して、バイトストリームを含む文字列を返すことができます。 unserialize() 関数は、文字列を PHP の元の値に戻すことができます。オブジェクトをシリアル化すると、オブジェクトのすべての変数が保存されますが、オブジェクトのメソッドは保存されず、クラス名のみが保存されます。オブジェクトを unserialize() できるようにするには、オブジェクトのクラスが定義されている必要があります。クラス A のオブジェクトをシリアル化すると、オブジェクト内のすべての変数の値を含むクラス A に関連する文字列が返されます。
簡単に言えば、シリアル化はオブジェクトを文字列に変換するプロセスであり、逆シリアル化は文字列からオブジェクトを復元するプロセスです。
環境
記事内記載内容の利用環境は以下の通りです。
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, '}');
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) < 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? */ }
実際の効果
デシリアライズ構文の違いは、セキュリティ保護装置のデシリアライズの判断に大きな影響を与えます。 Snort には、次のようなルールがあります。alert tcp any any -> any [80,8080,443] (uricontent:".php"; pcre:"/\{\w:.+?\}/"; sid:1; msg:php_serialize;)
概要
PHP のシリアル化構文と逆シリアル化構文の違いを悪用して、保護をバイパスするレッド チーム攻撃が行われる可能性があります。 青チームの防御では、オブジェクトを保存せず、クラス名のみを保存する定義に記述されたメソッドを検討することをお勧めします。 、保存されたクラスの名前、および防御のためのコロンなどの構文内の同じ文字をインターセプトします。 関連記事チュートリアルの共有:以上がPHP のシリアル化と逆シリアル化の構文の違いを使用して保護をバイパスするの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。