高度な PHP アプリケーション脆弱性監査技術
?
- 高度な PHP アプリケーション脆弱性監査技術
- はじめに
- 従来のコード監査テクノロジー
- PHP バージョンとアプリケーション コード監査
- その他の要素とアプリケーション コード監査
- 辞書を展開してください
- 変数自体のキー
- 変数カバレッジ
- 初期化変数のトラバース
- parse_str() 変数カバレッジの脆弱性
- import_request_variables () 変数カバレッジの脆弱性
- PHP5 グローバル
- magic_quotes_gpc とコード セキュリティ
- magic_quotes_gpc とは
- マジック クオートからの保護がない場合
- 変数のエンコードとデコード
- 2 回目の攻撃
- マジック クオートによってもたらされる新たなセキュリティ問題
- 変数キーとマジック クォーテーション マーク
- コードインジェクション
- コードインジェクションを引き起こす可能性のある PHP の関数
- 変数関数と二重引用符
- PHP 自体の関数の脆弱性と欠陥
- PHP 関数のオーバーフローの脆弱性
- PHP 関数のその他の脆弱性
- session_destroy() ファイル削除の脆弱性
- ランダム関数
- 特殊文字
- 切り捨て
- 切り捨てを含む
- データの切り捨て
- ファイル操作の特殊文字
- 新しい辞書をさらに探す方法
- デモ
- あとがき
- 付録
?
はじめに
PHP は広く使用されているスクリプト言語であり、特に Web 開発に適しています。クロスプラットフォームで、習得が簡単で強力です。統計によると、Yahoo、Sina、163、sohu などの大規模ポータルを含む、世界中の Web サイトの 34% 以上に PHP アプリケーションが含まれています。また、Discuz、phpwind、phpbb、vbb、wordpress、boblog など、多くのよく知られた Web アプリケーション システム (bbs、ブログ、wiki、cms など) は PHP を使用して開発されています。 Web セキュリティのアップグレードがホットスポットになるにつれ、PHP アプリケーションのコード セキュリティの問題が徐々に注目されるようになり、この分野に投資するセキュリティ担当者が増えており、公開されるアプリケーション コードの脆弱性も増えています。このような状況に対応して、多くのアプリケーション担当者はコード監査を実施するためにセキュリティ部門を設立したり、セキュリティ担当者を雇用したりしているため、多くの自動化された商用コード監査ツールが登場しています。つまり、大企業の製品安全率は大幅に向上し、明らかな抜け穴は基本的になくなり、誰もが知っている監査技術は役に立たないという状況が生じているのです。私たちは、専門家によって n 回スキャンされた多くのツールやコードに直面しています。多くのセキュリティ担当者は少し悲観的で、一部の公式セキュリティ担当者も自分のコードに非常に自信を持っていますが、「絶対的なものはない」ということを忘れないでください。セキュリティ」に基づいて、新しい脆弱性を悪用する新しい方法を見つける必要があります。この記事では、従来とは異なる技術的な経験をいくつか紹介します。
さらに、この記事の脆弱性の多くはインターネット上の専門家や友人の共有に由来していることを指摘しておきます。ここで彼らに感謝しなければなりません:)
従来のコード監査テクノロジー。
WEB アプリケーションの脆弱性探索は、基本的に変数と関数の 2 つの要素を中心に展開します。つまり、脆弱性を悪用するには、送信した悪意のあるコードが n 回の変数変換を通じて変数に渡され、最終的に実行のためにターゲット関数に渡される必要があります。 「すべての入力は有害です。」この文は変数の入力のみを強調しています。多くのプログラマは、「入力」を単に gpc[$_GET,$_POST,$_COOKIE] ですが、変数は転送プロセス中に n 回多くの変更を受けました。その結果、多くのフィルターは単なる「張り子の虎」になってしまいます。コードの安全性を別の言葉で説明しましょう。「関数に入るすべての変数は有害です」。
現在、最も一般的に使用されている PHP コード監査テクノロジは、主にセキュリティの脆弱性につながる可能性のある危険な関数を探す静的分析です。一般的に使用されている検索ツール (grep、findstr など)。また、多くの自動ツールでは、これらの関数の検索に正規表現が使用されます。以下に挙げる辞書など、よく使われる関数をいくつか挙げておきます(今回は省略)。ただし、基本的に既存の辞書の抜け穴を見つけるのは難しいため、辞書を拡張する必要があります。これらの辞書もこの記事の主な焦点です。 その他の方法には、PHP ソース コードを変更して変数フローを分析する方法や、危険な関数をフックしてアプリケーション コードを監査する方法などがありますが、これらも上記の辞書に依存します。 PHP のバージョンとアプリケーション コードの監査これまでのところ、PHP には php4、php5、php6 の 3 つの主要なバージョンがあり、使用率はおおよそ次のとおりです。?
?
PHP には自動アップグレード メカニズムがないため、現在の PHP バージョンが共存しており、パッチが適用されていない多くの既存の脆弱性にもつながります。これらの脆弱な機能は、当社の WEB アプリケーション コード監査の焦点でもあり、当社の辞書の重要な情報源でもあります。
アプリケーション コード監査に関連するその他の要素
多くのコード監査人は、コードを取得した後にそのコードを調べるだけであり、コードのセキュリティは他の多くの要素と関連していることを無視しています。上記のような要素が挙げられます。 PHP のバージョンに関して、より重要なのは、オペレーティング システムのタイプ (主に 2 つの主要陣営が勝利/*nix)、WEB サーバー ソフトウェア (主に 2 つのタイプ) です。 iis/apache) などの要因。これは、システムや Web サーバーが異なれば、セキュリティ機能や特性も異なるためです。これについては、以下の一部で説明します。
したがって、企業の WEB アプリケーション コードを監査するときは、企業が使用しているシステム、WEB サーバー ソフトウェア、PHP のバージョン、その他の情報を把握する必要があります。
辞書を展開してください
以下では、いくつかの非伝統的な PHP アプリケーション コード監査に対するいくつかの脆弱性の種類と悪用テクニックを詳細に紹介します。
変数自体のキー
変数の送信というと、GET/POST/COOKIEなどで送信された変数の値しか見ていない人が多いですが忘れています。一部のプログラムでは、変数が処理のために関数に抽出されるときに、変数自体のキーも含まれます。
<span style="color: #666600;" class="pun"><?</span><span class="pln">php</span><span style="color: #880000;" class="com">//key.php?aaaa'aaa=1&bb'b=2 </span><span class="pln"></span><span style="color: #880000;" class="com">//print_R($_GET); </span><span class="pln">?</span><span style="color: #000088;" class="kwd">foreach</span><span style="color: #666600;" class="pun">(</span><span class="pln">$_GET AS $key </span><span style="color: #666600;" class="pun">=></span><span class="pln"> $value</span><span style="color: #666600;" class="pun">)</span><span class="pln"></span><span style="color: #666600;" class="pun">{</span><span class="pln">? ? ? ? </span><span style="color: #000088;" class="kwd">print</span><span class="pln"> $key</span><span style="color: #666600;" class="pun">.</span><span style="color: #008800;" class="str">"\n"</span><span style="color: #666600;" class="pun">;</span><span class="pln"></span><span style="color: #666600;" class="pun">}</span><span class="pln"></span><span style="color: #666600;" class="pun">?></span>
上記のコードでは、変数自体のキーを抽出して表示します。上記のコードの場合、URL:
<span class="pln">key</span><span style="color: #666600;" class="pun">.</span><span class="pln">php</span><span style="color: #666600;" class="pun">?<</span><span class="pln">script</span><span style="color: #666600;" class="pun">></span><span class="pln">alert</span><span style="color: #666600;" class="pun">(</span><span style="color: #006666;" class="lit">1</span><span style="color: #666600;" class="pun">);</</span><span class="pln">script</span><span style="color: #666600;" class="pun">>=</span><span style="color: #006666;" class="lit">1</span><span style="color: #666600;" class="pun">&</span><span class="pln">bbb</span><span style="color: #666600;" class="pun">=</span><span style="color: #006666;" class="lit">2</span>
を送信すると、 xss の脆弱性。このキーが include() や SQL クエリなどの関数に送信された場合はどうなるでしょうか? :)
?
漏洞审计策略 |
PHP版本要求:无 系统要求:无 审计策略:通读代码 |
?
变量覆盖
很多的漏洞查找者都知道extract()这个函数在指定参数为EXTR_OVERWRITE或者没有指定函数可以导致变量覆盖,但是还有很多其他情况导致变量覆盖的如:
遍历初始化变量
请看如下代码:
<span style="color: #666600;" class="pun"><?</span><span class="pln">php</span><span style="color: #880000;" class="com">//var.php?a=fuck</span><span class="pln">$a</span><span style="color: #666600;" class="pun">=</span><span style="color: #008800;" class="str">'hi'</span><span style="color: #666600;" class="pun">;</span><span class="pln"></span><span style="color: #000088;" class="kwd">foreach</span><span style="color: #666600;" class="pun">(</span><span class="pln">$_GET </span><span style="color: #000088;" class="kwd">as</span><span class="pln"> $key </span><span style="color: #666600;" class="pun">=></span><span class="pln"> $value</span><span style="color: #666600;" class="pun">)</span><span style="color: #666600;" class="pun">{</span><span class="pln">? ? ? ? $$key </span><span style="color: #666600;" class="pun">=</span><span class="pln"> $value</span><span style="color: #666600;" class="pun">;</span><span class="pln"></span><span style="color: #666600;" class="pun">}</span><span class="pln"></span><span style="color: #000088;" class="kwd">print</span><span class="pln"> $a</span><span style="color: #666600;" class="pun">;</span><span class="pln"></span><span style="color: #666600;" class="pun">?></span>
很多的WEB应用都使用上面的方式(注意循环不一定是foreach),如Discuz!4.1的WAP部分的代码:
<span class="pln">$chs </span><span style="color: #666600;" class="pun">=</span><span style="color: #008800;" class="str">''</span><span style="color: #666600;" class="pun">;</span><span class="pln"></span><span style="color: #000088;" class="kwd">if</span><span style="color: #666600;" class="pun">(</span><span class="pln">$_POST </span><span style="color: #666600;" class="pun">&&</span><span class="pln"> $charset </span><span style="color: #666600;" class="pun">!=</span><span style="color: #008800;" class="str">'utf-8'</span><span style="color: #666600;" class="pun">)</span><span style="color: #666600;" class="pun">{</span><span class="pln">? ? ? ? $chs </span><span style="color: #666600;" class="pun">=</span><span style="color: #000088;" class="kwd">new</span><span style="color: #660066;" class="typ">Chinese</span><span style="color: #666600;" class="pun">(</span><span style="color: #008800;" class="str">'UTF-8'</span><span style="color: #666600;" class="pun">,</span><span class="pln"> $charset</span><span style="color: #666600;" class="pun">);</span><span class="pln">? ? ? ? </span><span style="color: #000088;" class="kwd">foreach</span><span style="color: #666600;" class="pun">(</span><span class="pln">$_POST </span><span style="color: #000088;" class="kwd">as</span><span class="pln"> $key </span><span style="color: #666600;" class="pun">=></span><span class="pln"> $value</span><span style="color: #666600;" class="pun">)</span><span style="color: #666600;" class="pun">{</span><span class="pln">? ? ? ? ? ? ? ? $$key </span><span style="color: #666600;" class="pun">=</span><span class="pln"> $chs</span><span style="color: #666600;" class="pun">-></span><span style="color: #660066;" class="typ">Convert</span><span style="color: #666600;" class="pun">(</span><span class="pln">$value</span><span style="color: #666600;" class="pun">);</span><span class="pln">? ? ? ? </span><span style="color: #666600;" class="pun">}</span><span class="pln">? ? ? ? unset</span><span style="color: #666600;" class="pun">(</span><span class="pln">$chs</span><span style="color: #666600;" class="pun">);</span>
?
漏洞审计策略 |
PHP版本要求:无 系统要求:无 审计策略:通读代码 |
?
parse_str()变量覆盖漏洞
<span style="color: #880000;" class="com">//var.php?var=new</span><span class="pln">$var </span><span style="color: #666600;" class="pun">=</span><span style="color: #008800;" class="str">'init'</span><span style="color: #666600;" class="pun">;</span><span class="pln"> ? ? ? ? ? ? ? ? ? ? parse_str</span><span style="color: #666600;" class="pun">(</span><span class="pln">$_SERVER</span><span style="color: #666600;" class="pun">[</span><span style="color: #008800;" class="str">'QUERY_STRING'</span><span style="color: #666600;" class="pun">]);</span><span class="pln"> </span><span style="color: #000088;" class="kwd">print</span><span class="pln"> $var</span><span style="color: #666600;" class="pun">;</span>
该函数一样可以覆盖数组变量,上面的代码是通过$_SERVER['QUERY_STRING']来提取变量的,对于指定了变量名的我们可以通过注射“=”来实现覆盖其他的变量:
<span style="color: #880000;" class="com">//var.php?var=1&a[1]=var1%3d222</span><span class="pln">$var1 </span><span style="color: #666600;" class="pun">=</span><span style="color: #008800;" class="str">'init'</span><span style="color: #666600;" class="pun">;</span><span class="pln">parse_str</span><span style="color: #666600;" class="pun">(</span><span class="pln">$a</span><span style="color: #666600;" class="pun">[</span><span class="pln">$_GET</span><span style="color: #666600;" class="pun">[</span><span style="color: #008800;" class="str">'var'</span><span style="color: #666600;" class="pun">]]);</span><span class="pln"></span><span style="color: #000088;" class="kwd">print</span><span class="pln"> $var1</span><span style="color: #666600;" class="pun">;</span>
上面的代码通过提交$var来实现对$var1的覆盖。
?
漏洞审计策略(parse_str) |
PHP版本要求:无 系统要求:无 审计策略:查找字符parse_str |
?
?
漏洞审计策略(mb_parse_str) |
PHP版本要求:php4<4.4.7 php5<5.2.2 系统要求:无 审计策略:查找字符mb_parse_str |
?
import_request_variables()变量覆盖漏洞
<span style="color: #880000;" class="com">//var.php?_SERVER[REMOTE_ADDR]=10.1.1.1</span><span class="pln">echo </span><span style="color: #008800;" class="str">'GLOBALS '</span><span style="color: #666600;" class="pun">.(</span><span style="color: #000088;" class="kwd">int</span><span style="color: #666600;" class="pun">)</span><span class="pln">ini_get</span><span style="color: #666600;" class="pun">(</span><span style="color: #008800;" class="str">"register_globals"</span><span style="color: #666600;" class="pun">).</span><span style="color: #008800;" class="str">"n"</span><span style="color: #666600;" class="pun">;</span><span class="pln">import_request_variables</span><span style="color: #666600;" class="pun">(</span><span style="color: #008800;" class="str">'GPC'</span><span style="color: #666600;" class="pun">);</span><span class="pln"></span><span style="color: #000088;" class="kwd">if</span><span style="color: #666600;" class="pun">(</span><span class="pln">$_SERVER</span><span style="color: #666600;" class="pun">[</span><span style="color: #008800;" class="str">'REMOTE_ADDR'</span><span style="color: #666600;" class="pun">]</span><span style="color: #666600;" class="pun">!=</span><span style="color: #008800;" class="str">'10.1.1.1'</span><span style="color: #666600;" class="pun">)</span><span style="color: #000088;" class="kwd">die</span><span style="color: #666600;" class="pun">(</span><span style="color: #008800;" class="str">'Go away!'</span><span style="color: #666600;" class="pun">);</span><span class="pln">echo </span><span style="color: #008800;" class="str">'Hello admin!'</span><span style="color: #666600;" class="pun">;</span>
?
漏洞审计策略(import_request_variables) |
PHP版本要求:php4<4.4.1 php5<5.2.2 系统要求:无 审计策略:查找字符import_request_variables |
?
PHP5 Globals
从严格意义上来说这个不可以算是PHP的漏洞,只能算是一个特性,测试代码:
<span style="color: #666600;" class="pun"><?</span><span class="pln"></span><span style="color: #880000;" class="com">// register_globals =ON</span><span class="pln"></span><span style="color: #880000;" class="com">//foo.php?GLOBALS[foobar]=HELLO</span><span class="pln">php echo $foobar</span><span style="color: #666600;" class="pun">;</span><span class="pln"> </span><span style="color: #666600;" class="pun">?></span>
但是很多的程序没有考虑到这点,请看如下代码:
<span style="color: #880000;" class="com">//为了安全取消全局变量</span><span class="pln"></span><span style="color: #880000;" class="com">//var.php?GLOBALS[a]=aaaa&b=111</span><span class="pln"></span><span style="color: #000088;" class="kwd">if</span><span style="color: #666600;" class="pun">(</span><span class="pln">ini_get</span><span style="color: #666600;" class="pun">(</span><span style="color: #008800;" class="str">'register_globals'</span><span style="color: #666600;" class="pun">))</span><span style="color: #000088;" class="kwd">foreach</span><span style="color: #666600;" class="pun">(</span><span class="pln">$_REQUEST </span><span style="color: #000088;" class="kwd">as</span><span class="pln"> $k</span><span style="color: #666600;" class="pun">=></span><span class="pln">$v</span><span style="color: #666600;" class="pun">)</span><span class="pln"> unset</span><span style="color: #666600;" class="pun">(</span><span class="pln">$</span><span style="color: #666600;" class="pun">{</span><span class="pln">$k</span><span style="color: #666600;" class="pun">});</span><span class="pln"></span><span style="color: #000088;" class="kwd">print</span><span class="pln"> $a</span><span style="color: #666600;" class="pun">;</span><span class="pln"></span><span style="color: #000088;" class="kwd">print</span><span class="pln"> $_GET</span><span style="color: #666600;" class="pun">[</span><span class="pln">b</span><span style="color: #666600;" class="pun">];</span>
如果熟悉WEB2.0的攻击的同学,很容易想到上面的代码我们可以利用这个特性进行crsf攻击。
?
漏洞审计策略 |
PHP版本要求:无 系统要求:无 审计策略:通读代码 |
?
magic_quotes_gpc与代码安全
?
什么是magic_quotes_gpc
当打开时,所有的 '(单引号),"(双引号),\(反斜线)和 NULL 字符都会被自动加上一个反斜线进行转义。还有很多函数有类似的作用 如:addslashes()、mysql_escape_string()、mysql_real_escape_string()等,另外还有parse_str()后的变量也受magic_quotes_gpc的影响。目前大多数的主机都打开了这个选项,并且很多程序员也注意使用上面那些函数去过滤变量,这看上去很安全。很多漏洞查找者或者工具遇到些函数过滤后的变量直接就放弃,但是就在他们放弃的同时也放过很多致命的安全漏洞。 :)
哪些地方没有魔术引号的保护
1) $_SERVER变量
PHP5的$_SERVER变量缺少magic_quotes_gpc的保护,导致近年来X-Forwarded-For的漏洞猛暴,所以很多程序员考虑过滤X-Forwarded-For,但是其他的变量呢?
?
漏洞审计策略($_SERVER变量) |
PHP版本要求:无 系统要求:无 审计策略:查找字符_SERVER |
?
2) getenv()得到的变量(使用类似$_SERVER变量)
?
漏洞审计策略(getenv()) |
PHP版本要求:无 系统要求:无 审计策略:查找字符getenv |
?
3) $HTTP_RAW_POST_DATA与PHP输入、输出流
主要应用与soap/xmlrpc/webpublish功能里,请看如下代码:
<span style="color: #000088;" class="kwd">if</span><span style="color: #666600;" class="pun">(</span><span style="color: #666600;" class="pun">!</span><span class="pln">isset</span><span style="color: #666600;" class="pun">(</span><span class="pln"> $HTTP_RAW_POST_DATA </span><span style="color: #666600;" class="pun">)</span><span style="color: #666600;" class="pun">)</span><span style="color: #666600;" class="pun">{</span><span class="pln">? ? ? ? $HTTP_RAW_POST_DATA </span><span style="color: #666600;" class="pun">=</span><span class="pln"> file_get_contents</span><span style="color: #666600;" class="pun">(</span><span style="color: #008800;" class="str">'php://input'</span><span style="color: #666600;" class="pun">);</span><span class="pln"></span><span style="color: #666600;" class="pun">}</span><span class="pln"></span><span style="color: #000088;" class="kwd">if</span><span style="color: #666600;" class="pun">(</span><span class="pln"> isset</span><span style="color: #666600;" class="pun">(</span><span class="pln">$HTTP_RAW_POST_DATA</span><span style="color: #666600;" class="pun">)</span><span style="color: #666600;" class="pun">)</span><span class="pln">? ? ? ? $HTTP_RAW_POST_DATA </span><span style="color: #666600;" class="pun">=</span><span class="pln"> trim</span><span style="color: #666600;" class="pun">(</span><span class="pln">$HTTP_RAW_POST_DATA</span><span style="color: #666600;" class="pun">);</span>
?
漏洞审计策略(数据流) |
PHP版本要求:无 系统要求:无 审计策略:查找字符HTTP_RAW_POST_DATA或者php://input |
?
4) 数据库操作容易忘记'的地方如:in()/limit/order by/group by
如Discuz!<5.0的pm.php:
<span style="color: #000088;" class="kwd">if</span><span style="color: #666600;" class="pun">(</span><span class="pln">is_array</span><span style="color: #666600;" class="pun">(</span><span class="pln">$msgtobuddys</span><span style="color: #666600;" class="pun">))</span><span style="color: #666600;" class="pun">{</span><span class="pln">? ? ? ? $msgto </span><span style="color: #666600;" class="pun">=</span><span class="pln"> array_merge</span><span style="color: #666600;" class="pun">(</span><span class="pln">$msgtobuddys</span><span style="color: #666600;" class="pun">,</span><span class="pln"> array</span><span style="color: #666600;" class="pun">(</span><span class="pln">$msgtoid</span><span style="color: #666600;" class="pun">));</span><span class="pln">? ? ? ? ? ? ? ? </span><span style="color: #666600;" class="pun">......</span><span class="pln"></span><span style="color: #000088;" class="kwd">foreach</span><span style="color: #666600;" class="pun">(</span><span class="pln">$msgto </span><span style="color: #000088;" class="kwd">as</span><span class="pln"> $uid</span><span style="color: #666600;" class="pun">)</span><span style="color: #666600;" class="pun">{</span><span class="pln">? ? ? ? $uids </span><span style="color: #666600;" class="pun">.=</span><span class="pln"> $comma</span><span style="color: #666600;" class="pun">.</span><span class="pln">$uid</span><span style="color: #666600;" class="pun">;</span><span class="pln">? ? ? ? $comma </span><span style="color: #666600;" class="pun">=</span><span style="color: #008800;" class="str">','</span><span style="color: #666600;" class="pun">;</span><span class="pln"></span><span style="color: #666600;" class="pun">}</span><span class="pln"></span><span style="color: #666600;" class="pun">......</span><span class="pln">$query </span><span style="color: #666600;" class="pun">=</span><span class="pln"> $db</span><span style="color: #666600;" class="pun">-></span><span class="pln">query</span><span style="color: #666600;" class="pun">(</span><span style="color: #008800;" class="str">"SELECT m.username, mf.ignorepm FROM {$tablepre}members m? ? ? ? LEFT JOIN {$tablepre}memberfields mf USING(uid)? ? ? ? WHERE m.uid IN ($uids)"</span><span style="color: #666600;" class="pun">);</span>
?
漏洞审计策略 |
PHP版本要求:无 系统要求:无 审计策略:查找数据库操作字符(select,update,insert等等) |
?
变量的编码与解码
一个WEB程序很多功能的实现都需要变量的编码解码,而且就在这一转一解的传递过程中就悄悄的绕过你的过滤的安全防线。
这个类型的主要函数有:
1) stripslashes() 这个其实就是一个decode-addslashes()
2) 其他字符串转换函数:
?
base64_decode | 对使用 MIME base64 编码的数据进行解码 |
base64_encode | 使用 MIME base64 对数据进行编码 |
rawurldecode | 对已编码的 URL 字符串进行解码 |
rawurlencode | 按照 RFC 1738 对 URL 进行编码 |
urldecode | 解码已编码的 URL 字符串 |
urlencode | 编码 URL 字符串 |
... | ... |
?
另外一个 unserialize/serialize
3) 字符集函数(GKB,UTF7/8...)如iconv()/mb_convert_encoding()等
目前很多漏洞挖掘者开始注意这一类型的漏洞了,如典型的urldecode:
<span class="pln">$sql </span><span style="color: #666600;" class="pun">=</span><span style="color: #008800;" class="str">"SELECT * FROM article WHERE articleid='"</span><span style="color: #666600;" class="pun">.</span><span class="pln">urldecode</span><span style="color: #666600;" class="pun">(</span><span class="pln">$_GET</span><span style="color: #666600;" class="pun">[</span><span class="pln">id</span><span style="color: #666600;" class="pun">]).</span><span style="color: #008800;" class="str">"'"</span><span style="color: #666600;" class="pun">;</span>
当magic_quotes_gpc=on时,我们提交?id=%2527,得到sql语句为:
<span class="pln">SELECT </span><span style="color: #666600;" class="pun">*</span><span class="pln"> FROM article WHERE articleid</span><span style="color: #666600;" class="pun">=</span><span style="color: #008800;" class="str">'''</span>
?
漏洞审计策略 |
PHP版本要求:无 系统要求:无 审计策略:查找对应的编码函数 |
?
二次攻击
详细见附录[1]
1)数据库出来的变量没有进行过滤
2)数据库的转义符号:
- mysql/oracle转义符号同样是\(我们提交'通过魔术引号变化为\',当我们update进入数据库时,通过转义变为')
- mssql的转义字符为'(所以我们提交'通过魔术引号变化为\',mssql会把它当为一个字符串直接处理,所以魔术引号对于mssql的注射没有任何意义)
从这里我们可以思考得到一个结论:一切进入函数的变量都是有害的,另外利用二次攻击我们可以实现一个webrootkit,把我们的恶意构造直接放到数据库里。我们应当把这样的代码看成一个vul?
?
漏洞审计策略 |
PHP版本要求:无 系统要求:无 审计策略:通读代码 |
?
魔术引号带来的新的安全问题
首先我们看下魔术引号的处理机制:
<span style="color: #666600;" class="pun">[\-->\\,</span><span style="color: #008800;" class="str">'-->\',"-->\",null-->\0]</span>
这给我们引进了一个非常有用的符号“\”,“\”符号不仅仅是转义符号,在WIN系统下也是目录转跳的符号。这个特点可能导致php应用程序里产生非常有意思的漏洞:
1)得到原字符(',\,",null])
<span class="pln">$order_sn</span><span style="color: #666600;" class="pun">=</span><span class="pln">substr</span><span style="color: #666600;" class="pun">(</span><span class="pln">$_GET</span><span style="color: #666600;" class="pun">[</span><span style="color: #008800;" class="str">'order_sn'</span><span style="color: #666600;" class="pun">],</span><span style="color: #006666;" class="lit">1</span><span style="color: #666600;" class="pun">);</span><span class="pln"></span><span style="color: #880000;" class="com">//提交 ? ? ? ? ? ? ? ? '</span><span class="pln"></span><span style="color: #880000;" class="com">//魔术引号处理 ? ? ? ? \'</span><span class="pln"></span><span style="color: #880000;" class="com">//substr ? ? ? ? ? ? ? '</span><span class="pln">$sql </span><span style="color: #666600;" class="pun">=</span><span style="color: #008800;" class="str">"SELECT order_id, order_status, shipping_status, pay_status, "</span><span style="color: #666600;" class="pun">.</span><span class="pln">? ?</span><span style="color: #008800;" class="str">" shipping_time, shipping_id, invoice_no, user_id "</span><span style="color: #666600;" class="pun">.</span><span class="pln">? ?</span><span style="color: #008800;" class="str">" FROM "</span><span style="color: #666600;" class="pun">.</span><span class="pln"> $ecs</span><span style="color: #666600;" class="pun">-></span><span class="pln">table</span><span style="color: #666600;" class="pun">(</span><span style="color: #008800;" class="str">'order_info'</span><span style="color: #666600;" class="pun">).</span><span class="pln">? ?</span><span style="color: #008800;" class="str">" WHERE order_sn = '$order_sn' LIMIT 1"</span><span style="color: #666600;" class="pun">;</span>
2)得到“\”字符
<span class="pln">$order_sn</span><span style="color: #666600;" class="pun">=</span><span class="pln">substr</span><span style="color: #666600;" class="pun">(</span><span class="pln">$_GET</span><span style="color: #666600;" class="pun">[</span><span style="color: #008800;" class="str">'order_sn'</span><span style="color: #666600;" class="pun">],</span><span style="color: #006666;" class="lit">0</span><span style="color: #666600;" class="pun">,</span><span style="color: #006666;" class="lit">1</span><span style="color: #666600;" class="pun">);</span><span class="pln"></span><span style="color: #880000;" class="com">//提交 ? ? ? ? ? ? ? ? '</span><span class="pln"></span><span style="color: #880000;" class="com">//魔术引号处理 ? ? ? ? \'</span><span class="pln"></span><span style="color: #880000;" class="com">//substr ? ? ? ? ? ? ? \ ? ?</span><span class="pln">$sql </span><span style="color: #666600;" class="pun">=</span><span style="color: #008800;" class="str">"SELECT order_id, order_status, shipping_status, pay_status, "</span><span style="color: #666600;" class="pun">.</span><span class="pln">? ?</span><span style="color: #008800;" class="str">" shipping_time, shipping_id, invoice_no, user_id "</span><span style="color: #666600;" class="pun">.</span><span class="pln">? ?</span><span style="color: #008800;" class="str">" FROM "</span><span style="color: #666600;" class="pun">.</span><span class="pln"> $ecs</span><span style="color: #666600;" class="pun">-></span><span class="pln">table</span><span style="color: #666600;" class="pun">(</span><span style="color: #008800;" class="str">'order_info'</span><span style="color: #666600;" class="pun">).</span><span class="pln">? ?</span><span style="color: #008800;" class="str">" WHERE order_sn = '$order_sn' and order_tn='"</span><span style="color: #666600;" class="pun">.</span><span class="pln">$_GET</span><span style="color: #666600;" class="pun">[</span><span style="color: #008800;" class="str">'order_tn'</span><span style="color: #666600;" class="pun">].</span><span style="color: #008800;" class="str">"'"</span><span style="color: #666600;" class="pun">;</span>
提交内容:
<span style="color: #666600;" class="pun">?</span><span class="pln">order_sn</span><span style="color: #666600;" class="pun">=</span><span style="color: #008800;" class="str">'&order_tn=%20and%201=1/* </span>
执行的SQL语句为:
<span class="pln">SELECT order_id</span><span style="color: #666600;" class="pun">,</span><span class="pln"> order_status</span><span style="color: #666600;" class="pun">,</span><span class="pln"> shipping_status</span><span style="color: #666600;" class="pun">,</span><span class="pln"> pay_status</span><span style="color: #666600;" class="pun">,</span><span class="pln"> shipping_time</span><span style="color: #666600;" class="pun">,</span><span class="pln"> shipping_id</span><span style="color: #666600;" class="pun">,</span><span class="pln"> invoice_no</span><span style="color: #666600;" class="pun">,</span><span class="pln"> user_id FROM order_info WHERE order_sn </span><span style="color: #666600;" class="pun">=</span><span style="color: #008800;" class="str">'\' and order_tn='</span><span style="color: #000088;" class="kwd">and</span><span style="color: #006666;" class="lit">1</span><span style="color: #666600;" class="pun">=</span><span style="color: #006666;" class="lit">1</span><span style="color: #880000;" class="com">/*'</span>
?
漏洞审计策略 |
PHP版本要求:无 系统要求:无 审计策略:查找字符串处理函数如substr或者通读代码 |
?
变量key与魔术引号
我们最在这一节的开头就提到了变量key,PHP的魔术引号对它有什么影响呢?
<span style="color: #666600;" class="pun"><?</span><span class="pln">php</span><span style="color: #880000;" class="com">//key.php?aaaa'aaa=1&bb'b=2 </span><span class="pln"></span><span style="color: #880000;" class="com">//print_R($_GET); </span><span class="pln">?</span><span style="color: #000088;" class="kwd">foreach</span><span style="color: #666600;" class="pun">(</span><span class="pln">$_GET AS $key </span><span style="color: #666600;" class="pun">=></span><span class="pln"> $value</span><span style="color: #666600;" class="pun">)</span><span class="pln">? ? ? ? </span><span style="color: #666600;" class="pun">{</span><span class="pln">? ? ? ? </span><span style="color: #000088;" class="kwd">print</span><span class="pln"> $key</span><span style="color: #666600;" class="pun">.</span><span style="color: #008800;" class="str">"\n"</span><span style="color: #666600;" class="pun">;</span><span class="pln">? ? ? ? </span><span style="color: #666600;" class="pun">}</span><span class="pln"></span><span style="color: #666600;" class="pun">?></span>
1)当magic_quotes_gpc = On时,在php5.24下测试显示:
<span class="pln">aaaa</span><span style="color: #666600;" class="pun">\</span><span style="color: #008800;" class="str">'aaabb\'b</span>
从上面结果可以看出来,在设置了magic_quotes_gpc = On下,变量key受魔术引号影响。但是在php4和php<5.2.1的版本中,不处理数组第一维变量的key,测试代码如下:
<span style="color: #666600;" class="pun"><?</span><span class="pln">php</span><span style="color: #880000;" class="com">//key.php?aaaa'aaa[bb']=1 </span><span class="pln">print_R</span><span style="color: #666600;" class="pun">(</span><span class="pln">$_GET</span><span style="color: #666600;" class="pun">);</span><span class="pln"> </span><span style="color: #666600;" class="pun">?></span>
结果显示:
<span style="color: #660066;" class="typ">Array</span><span style="color: #666600;" class="pun">(</span><span style="color: #666600;" class="pun">[</span><span class="pln">aaaa</span><span style="color: #008800;" class="str">'aaa] => Array ( [bb\'] => 1 ) ) </span>
数组第一维变量的key不受魔术引号的影响。
?
漏洞审计策略 |
PHP版本要求:php4和php<5.2.1 系统要求:无 审计策略:通读代码 |
?
2)当magic_quotes_gpc = Off时,在php5.24下测试显示:
<span class="pln">aaaa</span><span style="color: #008800;" class="str">'aaabb'</span><span class="pln">b</span>
对于magic_quotes_gpc = Off时所有的变量都是不安全的,考虑到这个,很多程序都通过addslashes等函数来实现魔术引号对变量的过滤,示例代码如下:
<span style="color: #666600;" class="pun"><?</span><span class="pln">php </span><span style="color: #880000;" class="com">//keyvul.php?aaa'aa=1'</span><span class="pln"></span><span style="color: #880000;" class="com">//magic_quotes_gpc = Off</span><span class="pln">?</span><span style="color: #000088;" class="kwd">if</span><span style="color: #666600;" class="pun">(!</span><span class="pln">get_magic_quotes_gpc</span><span style="color: #666600;" class="pun">())</span><span class="pln"></span><span style="color: #666600;" class="pun">{</span><span class="pln">?$_GET ?</span><span style="color: #666600;" class="pun">=</span><span class="pln"> addslashes_array</span><span style="color: #666600;" class="pun">(</span><span class="pln">$_GET</span><span style="color: #666600;" class="pun">);</span><span class="pln"></span><span style="color: #666600;" class="pun">}</span><span class="pln"></span><span style="color: #000088;" class="kwd">function</span><span class="pln"> addslashes_array</span><span style="color: #666600;" class="pun">(</span><span class="pln">$value</span><span style="color: #666600;" class="pun">)</span><span class="pln"></span><span style="color: #666600;" class="pun">{</span><span class="pln">? ? ? ? </span><span style="color: #000088;" class="kwd">return</span><span class="pln"> is_array</span><span style="color: #666600;" class="pun">(</span><span class="pln">$value</span><span style="color: #666600;" class="pun">)</span><span style="color: #666600;" class="pun">?</span><span class="pln"> array_map</span><span style="color: #666600;" class="pun">(</span><span style="color: #008800;" class="str">'addslashes_array'</span><span style="color: #666600;" class="pun">,</span><span class="pln"> $value</span><span style="color: #666600;" class="pun">)</span><span style="color: #666600;" class="pun">:</span><span class="pln"> addslashes</span><span style="color: #666600;" class="pun">(</span><span class="pln">$value</span><span style="color: #666600;" class="pun">);</span><span class="pln"></span><span style="color: #666600;" class="pun">}</span><span class="pln">print_R</span><span style="color: #666600;" class="pun">(</span><span class="pln">$_GET</span><span style="color: #666600;" class="pun">);</span><span class="pln"></span><span style="color: #000088;" class="kwd">foreach</span><span style="color: #666600;" class="pun">(</span><span class="pln">$_GET AS $key </span><span style="color: #666600;" class="pun">=></span><span class="pln"> $value</span><span style="color: #666600;" class="pun">)</span><span class="pln"></span><span style="color: #666600;" class="pun">{</span><span class="pln">? ? ? ? </span><span style="color: #000088;" class="kwd">print</span><span class="pln"> $key</span><span style="color: #666600;" class="pun">;</span><span class="pln"></span><span style="color: #666600;" class="pun">}</span><span class="pln"></span><span style="color: #666600;" class="pun">?></span>
以上的代码看上去很完美,但是他这个代码里addslashes($value)只处理了变量的具体的值,但是没有处理变量本身的key,上面的代码显示结果如下:
<span style="color: #660066;" class="typ">Array</span><span class="pln"></span><span style="color: #666600;" class="pun">(</span><span class="pln">? ? </span><span style="color: #666600;" class="pun">[</span><span class="pln">aaa</span><span style="color: #008800;" class="str">'aa] => 1\')aaa'</span><span class="pln">aa</span>
?
漏洞审计策略 |
PHP版本要求:无 系统要求:无 审计策略:通读代码 |
?
代码注射
PHP中可能导致代码注射的函数
很多人都知道eval、preg_replace+/e可以执行代码,但是不知道php还有很多的函数可以执行代码如:
?
assert() |
call_user_func() |
call_user_func_array() |
create_function() |
变量函数 |
... |
?
ここでは、create_function() コード実行の脆弱性に関して最近出現したいくつかのコードを見てみましょう:
<span style="color: #666600;" class="pun"><?</span><span class="pln">php</span><span style="color: #880000;" class="com">//このコードの解釈方法</span><span class="pln">$sort_by</span><span style="color: #666600;" class="pun">=</span><span class="pln">$_GET</span><span style="color: #666600;" class="pun">[</span><span style="color: #008800;" class="str">'sort_by ' </span><span style="color: #666600;" class="pun">];</span><span class="pln">$sorter</span><span style="color: #666600;" class="pun">=</span><span style="color: #008800;" class="str">'strnatcasecmp'</span><span style="color: #666600;" class="pun">;</span><span class="pln">$databases</span> <span style="color: #666600;" class="pun">=</span><span class="pln">array</span><span style="color: #666600;" class="pun">(</span><span style="color: #008800;" class="str">'テスト'</span><span style="color: #666600;" class="pun">,</span><span style="color: #008800;" class="str">'テスト'</span><span style="color: #666600;" class="pun"> ) ;</span><span class="pln">$sort_function </span><span style="color: #666600;" class="pun">=</span><span style="color: #008800;" class="str">' ?return 1 * '</span><span style="color: #666600;" class="pun">.</span><span class="pln"> $sorter </span><span style="color: #666600;" class="pun"> .</span><span style="color: #008800;" class="str">'($a["'</span><span style="color: #666600;" class="pun">.</span><span class="pln"> $sort_by </span><span style="color: #666600;" class="pun">.</span><span style="color: #008800;" class="str">'"], $b[" ' </span><span style="color: #666600;" class="pun">.</span><span class="pln"> $sort_by </span><span style="color: #666600;" class="pun">.</span>