ホームページ > バックエンド開発 > PHPチュートリアル > PHP のシリアル化と逆シリアル化の構文の違い

PHP のシリアル化と逆シリアル化の構文の違い

(*-*)浩
リリース: 2023-04-07 20:24:01
オリジナル
2620 人が閲覧しました

PHP のシリアル化と逆シリアル化の構文の違い

公式ドキュメントでは、PHP のシリアル化と逆シリアル化について次のように紹介されています: (推奨学習: PHP ビデオ チュートリアル )

所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示。unserialize()函数能够重新把字符串变回php原来的值。序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。为了能够unserialize()一个对象,这个对象的类必须已经定义过。如果序列化类A的一个对象,将会返回一个跟类A相关,而且包含了对象所有变量值的字符串。
ログイン後にコピー

簡単に言えば、シリアル化はオブジェクトを文字列に変換するプロセスであり、逆シリアル化は文字列からオブジェクトを復元するプロセスです。

環境

記事内に記載されている内容の利用環境は以下のとおりです。

PHP7.3.1、SDK
VSCode
C++和C
ログイン後にコピー

推奨環境参考資料構成: " VSCODE を使用して WINDOWS で PHP7 ソース コードをデバッグする>>

インターネット上のパブリック パラメーターの逆シリアル化実行プロセスは非常に詳細ですが、シリアル化やシリアル化などの詳細にはいくつかの欠陥があります。デフォルトでは、文字列に連結するためのオブジェクト変換に { と } が追加されます。

[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 を使用してシリアル化された文字列を {and} の前後で結合し、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 &#39;C&#39;:
    case &#39;O&#39;:    goto yy4;
    case &#39;N&#39;:    goto yy5;
    case &#39;R&#39;:    goto yy6;
    case &#39;S&#39;:    goto yy7;
    case &#39;a&#39;:    goto yy8;
    case &#39;b&#39;:    goto yy9;
    case &#39;d&#39;:    goto yy10;
    case &#39;i&#39;:    goto yy11;
    case &#39;o&#39;:    goto yy12;
    case &#39;r&#39;:    goto yy13;
    case &#39;s&#39;:    goto yy14;
    case &#39;}&#39;:    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 行目で逆シリアル化が開始されていることがわかります。逆シリアル化では、字句スキャンを使用して、各シンボル変換の対応するオブジェクトを決定します。デシリアライズ中に } が処理されることがわかりますが、この処理中、カウンターは 1 だけインクリメントされ、他の操作は実行されません。

実際の効果

デシリアライズ構文の違いは、セキュリティ保護装置のデシリアライズの判断に大きな影響を与えます。 Snort には、次のようなルールがあります。

alert tcp any any -> any [80,8080,443] (uricontent:".php"; pcre:"/\{\w:.+?\}/"; sid:1; msg:php_serialize;)
ログイン後にコピー

攻撃ペイロードでは、ほとんどの文字が {} の代わりに使用できるため、ルールが無効になります。

概要

PHP のシリアル化構文と逆シリアル化構文の違いを悪用して、保護をバイパスするレッド チーム攻撃が行われる可能性があります。

青チームの防御では、オブジェクトを保存せず、クラス名のみを保存する定義に記述されたメソッドを検討することをお勧めします。 、保存されたクラスの名前、および防御のためのコロンなどの構文内の同じ文字をインターセプトします。

以上がPHP のシリアル化と逆シリアル化の構文の違いの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
php
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート