WordPress のシーケンス解除の脆弱性は最近非常に有名になっていますが、具体的な脆弱性については分析しません: http://drops.wooyun.org/papers/596,?
英語の原文も読むことができます: http://vagosec.org/2013/09/wordpress-php-object-injection/。 ?
wp の公式 Web サイトにパッチがあります。パッチを回避しようとしましたが、成功したと思ったら、自分が甘かったことがわかり、wp のパッチを回避できませんでした。ですが、unserialize の小さな機能を発見したので共有したいと思います。?
1. Unserialize() 関数関連のソースコード: ?if ((YYLIMIT - YYCURSOR) < 7) YYFILL(7);?<br style="margin: 0px; padding: 0px;">????????yych = *YYCURSOR;?<br style="margin: 0px; padding: 0px;">????????switch (yych) {?<br style="margin: 0px; padding: 0px;">????????case 'C':?<br style="margin: 0px; padding: 0px;">????????case 'O':????????goto yy13;?<br style="margin: 0px; padding: 0px;">????????case 'N':????????goto yy5;?<br style="margin: 0px; padding: 0px;">????????case 'R':????????goto yy2;?<br style="margin: 0px; padding: 0px;">????????case 'S':????????goto yy10;?<br style="margin: 0px; padding: 0px;">????????case 'a':????????goto yy11;?<br style="margin: 0px; padding: 0px;">????????case 'b':????????goto yy6;?<br style="margin: 0px; padding: 0px;">????????case 'd':????????goto yy8;?<br style="margin: 0px; padding: 0px;">????????case 'i':????????goto yy7;?<br style="margin: 0px; padding: 0px;">????????case 'o':????????goto yy12;?<br style="margin: 0px; padding: 0px;">????????case 'r':????????goto yy4;?<br style="margin: 0px; padding: 0px;">????????case 's':????????goto yy9;?<br style="margin: 0px; padding: 0px;">????????case '}':????????goto yy14;?<br style="margin: 0px; padding: 0px;">????????default:????????goto yy16;?<br style="margin: 0px; padding: 0px;">????????}
上記のコードは判定ですシーケンス文字列の処理メソッド (シーケンス文字列 O:4:"test":1:{s:1:"a";s:3:"aaa";} など) このシーケンス文字列を処理するには、まず最初のstring The Character is O, then case 'O':??goto yy13?yy13:?<br style="margin: 0px; padding: 0px;">????????yych = *(YYMARKER = YYCURSOR);?<br style="margin: 0px; padding: 0px;">????????if (yych == ':') goto yy17;?<br style="margin: 0px; padding: 0px;">????????goto yy3;
上記のコードからわかるように、ポインターは移動します2 番目の文字を指す 1 ビットを使用して、その文字が次であるかどうかを判断し、次に yy17?yy17:?<br style="margin: 0px; padding: 0px;">???????yych = * YYCURSOR; に進みます。 ?<br style="margin: 0px; padding: 0px;">??? ????if (yybm[0 yych] & 128) {?<br style="margin: 0px; padding: 0px;">????????????goto yy20;?<br style="margin: 0px; padding: 0px;">??? ????<br style="margin: 0px; padding: 0px;">??????if (yych == ' ') goto yy19;?<br style="margin: 0px; padding: 0px;"><br style="margin: 0px; padding: 0px;">....?<br style="margin: 0px; padding: 0px;"><br style="margin: 0px; padding: 0px;">yy19:?<br style="margin: 0px; padding: 0px;"> ???? ???yych = * YYCURSOR;?<br style="margin: 0px; padding: 0px;">?????????if (yybm[0 yych] & 128) {?<br style="margin: 0px; padding: 0px;">????????? goto yy20;?<br style="margin: 0px; padding: 0px;">?????????}?<br style="margin: 0px; padding: 0px;">??????goto yy18;
より 上記からわかるようにコードの場合はポインタが移動し、文字が数字の場合は yy20 に進み、 ' ' の場合は yy19 に進み、次の文字が数字の場合は yy20 に進みます。 yy18 に移動するだけではありません。yy18 はシーケンス処理を直接終了します。yy20 はオブジェクト シーケンスの処理であるため、上記からわかるように:?O: 4:"テスト":1:{s:1:"a";s:3:"aaa" ;} ?<code style="margin: 0px auto; padding: 4px 8px; display: block; font-family: 'Lucida Console', 'Courier New', Courier, mono, monospace; font-size: 12px; color: #333333; background-color: #f8f8f8; border: 1px solid #cccccc; line-height: 18px; overflow: auto; white-space: normal;">O: 4:"test":1:{s:1:"a";s:3:"aaa";}?<br style="margin: 0px; padding: 0px;">O:4:"test":1:{s:1:"a";s:3:"aaa";}
O:4:"test":1:{s:1:"a";s:3:"aaa";}
<🎜> はすべて逆シリアル化できますアンシリアライズしても結果は同じです。?
2. 実際のテスト: ?<?php?<br style="margin: 0px; padding: 0px;">var_dump(unserialize('O: 4:"test":1:{s:1:"a";s:3:"aaa";}'));?<br style="margin: 0px; padding: 0px;">var_dump(unserialize('O:4:"test":1:{s:1:"a";s:3:"aaa";}'));?<br style="margin: 0px; padding: 0px;">?>
出力: ?object(__PHP_Incomplete_Class)#1 (2) { ["__PHP_Incomplete_Class_Name"]=> string(4) "test" ["a"]=> string(3) "aaa" }?<br style="margin: 0px; padding: 0px;">object(__PHP_Incomplete_Class)#1 (2) { ["__PHP_Incomplete_Class_Name"]=> string(4) "test" ["a"]=> string(3) "aaa" }
実際には、もう 1 つの ' ' で処理できるオブジェクトの型だけでなく、他の型も処理できます。具体的なテストについてはあまり説明しません。?
3.我们看下wp的补丁:?function is_serialized( $data, $strict = true ) {?<br style="margin: 0px; padding: 0px;">?????????// 文字列でない場合はシリアル化されません?<br style="margin: 0px; padding: 0px;">???????if ( ! is_string( $data ) )?<br style="margin: 0px; padding: 0px;">? ?????????????return false;?<br style="margin: 0px; padding: 0px;">?????????$data = トリム( $data );?<br style="margin: 0px; padding: 0px;">??????? ? if ( 'N;' == $data )?<br style="margin: 0px; padding: 0px;">???????????????return true;?<br style="margin: 0px; padding: 0px;">?????????$length = strlen ( $data );?<br style="margin: 0px; padding: 0px;">?????????if ( $length ???????????????return false;?<br style="margin: 0px; padding: 0px;">?????????if ( ':' !== $data[1] )?<br style="margin: 0px; padding: 0px;">???????????????return false;?<br style="margin: 0px; padding: 0px;">?????????if ( $strict ) {//output?<br style="margin: 0px; padding: 0px;">???????????????$lastc = $data[ $length - 1 ]; ?<br style="margin: 0px; padding: 0px;">??????????????????if ( ';' !== $lastc && '}' !== $lastc )?<br style="margin: 0px; padding: 0px;">?????? ????????????????return false;?<br style="margin: 0px; padding: 0px;">??????????} else {//input?<br style="margin: 0px; padding: 0px;">??????? ???????$semicolon = strpos( $data, ';' );?<br style="margin: 0px; padding: 0px;">???????????????$brace???? = strpos( $data, '}' );?<br style="margin: 0px; padding: 0px;">??????????????????// どちらか ; ?<br style="margin: 0px; padding: 0px;">???????????????if ( false === $semicolon && false === $brace )?<br style="margin: 0px; padding: 0px;">????? ???????????????????return false;?<br style="margin: 0px; padding: 0px;">??????????????????// ただし、どちらも最初の X 文字。?<br style="margin: 0px; padding: 0px;">??????????????????if ( false !== $semicolon && $semicolon ??????? ????????????????return false;?<br style="margin: 0px; padding: 0px;">???????????????if ( false !== $brace && $中括弧 ?????????????????????return false;?<br style="margin: 0px; padding: 0px;">?????????}? <br style="margin: 0px; padding: 0px;">?????????$token = $data[0];?<br style="margin: 0px; padding: 0px;">?????????switch ( $token ) {?<br style="margin: 0px; padding: 0px;">???????? ??????????case 's' :?<br style="margin: 0px; padding: 0px;">?????????????????????if ( $strict ) {?<br style="margin: 0px; padding: 0px;">?????????????????????????????????if ( '"' !== $data[ $length - 2 ] ) ?<br style="margin: 0px; padding: 0px;">????????????????????????????????????return false;?<br style="margin: 0px; padding: 0px;">????????????????????????} elseif ( false === strpos( $data, '"' ) ) {?<br style="margin: 0px; padding: 0px;">??? ????????????????????????????return false;?<br style="margin: 0px; padding: 0px;">??????????????? ??????????}?<br style="margin: 0px; padding: 0px;">???????????????ケース 'a' :?<br style="margin: 0px; padding: 0px;">????????? ????case 'O' :?<br style="margin: 0px; padding: 0px;">?????????????????????エコー "a";?<br style="margin: 0px; padding: 0px;">?? ???????????????????return (bool) preg_match( "/^{$token}:[0-9] :/s", $data ); ?<br style="margin: 0px; padding: 0px;">??????????????????ケース 'b' :?<br style="margin: 0px; padding: 0px;">??????????????????ケース 'i' : ?<br style="margin: 0px; padding: 0px;">??????????????????ケース 'd' :?<br style="margin: 0px; padding: 0px;">????????????????????? ???$end = $strict ? '$' : '';?<br style="margin: 0px; padding: 0px;">?????????????????????return (bool) preg_match( "/^{$token}:[ 0-9.E-] ;$end/", $data );?<br style="margin: 0px; padding: 0px;">?????????}?<br style="margin: 0px; padding: 0px;">?????????return false;?<br style="margin: 0px; padding: 0px;">}
パッチ内?return (bool) preg_match( "/^{$token}:[0-9] :/s", $data );<code style="margin: 0px auto; padding: 4px 8px; display: block; font-family: 'Lucida Console', 'Courier New', Courier, mono, monospace; font-size: 12px; color: #333333; background-color: #f8f8f8; border: 1px solid #cccccc; line-height: 18px; overflow: auto; white-space: normal;">return (bool) preg_match( "/^{$token}:[0-9] :/s", $data );
「 」をもう 1 つ追加できますバイパス、この方法でシーケンス値をデータベースに書き込みましたが、データベースから抽出されたデータは、再度検証するときにバイパスできません。個人的には、このパッチはデータベースに出入りするデータに変更を加えることができませんでした。データの内外の変更に焦点を当てる必要がなくなりました。 ?
4. 概要?
wp パッチはバイパスされませんが、unserialize() のこの小さな機能は多くの開発者によって無視される可能性があり、その結果、プログラムにはセキュリティ上の欠陥があります。 ?
上記の分析に誤りがある場合は、指摘するメッセージを残してください。 ?
5. 参考?
《WordPress < 3.6.1 PHP オブジェクトインジェクション》?
http:/ /vagosec.org/2013/09/wordpress-php-object-injection/?
《var_unserializer.c ソースコード》?
https://github. com /php/php-src/blob/73cd2e0ab14d804c6bf0b689490bdd4fd6e969b1/ext/standard/var_unserializer.c?
"PHP 文字列のシリアル化と逆シリアル化の間の一貫性のない構文解析によって引き起こされるセキュリティ上の危険"?
http://zone.wooyun.org/content/1664