Shikata Ga Nai

Private? There is no such things.

Winning QR with DOM-Based XSS | Bug Bounty POCを訳してみた

Hello there, ('ω')ノ

 

DOM ベースの XSS で QR を獲得する | バグ報奨金 POCを。

 

脆弱性:

 DOM XSS

記事:

 https://medium.com/@haroonhameed_76621/winning-qr-with-dom-based-xss-bug-bounty-poc-4b4048cf285d

 

今回は、Synack Red Team プログラムで DOM ベースの XSS を実行し、

QR (別名品質ルール) を獲得できる方法について。

 

DOMの理解:

DOM ベースのクロスサイト スクリプティングに関連するソースとシンクを

理解するには、DOM とそのメソッドの一部を簡単に理解する必要があり。

ドキュメント オブジェクト モデルは、Web ページの要素を Web ブラウザで

階層的に表現したもので。

言い換えれば、ブラウザはロードするページを受け取ると、

ページ構造を解析または分析し、ページのさまざまな要素をツリー状の構造に分割し

各要素と属性がそれぞれの場所にネストされて。


DOM ベースの XSS:ソースとシンク

DOM の基本を理解し、JavaScript コードがリアルタイムでページを

変更できることを理解したので、

DOM ベースの XSS とソースとシンクについて説明することに。

 

ソース:

ソース関数は、ページ上のどこかからユーザ入力を受け入れる任意の

JS プロパティまたは関数で。

ソースの例としては、クエリ文字列から入力を読み取る

location.search プロパティがあり。

以下に一般的なソースをいくつか示して。


* document.URL
* document.documentURI
* document.URLUnencoded
* document.baseURI
* location.search
* document.cookie
* document.referrer

 

シンク:

シンクは潜在的に危険な JavaScript 関数であり、

攻撃者が制御するデータが渡されると望ましくない影響を引き起こす可能性があり。

基本的に、関数がセキュリティ チェックを行わずに入力を出力として

画面に返す場合、それはシンクとみなされて。

この例としては、HTML ページのコンテンツを指定されたものに変更する前に

使用した「innerHTML」プロパティがあって。

一般的なシンクには次のものがあり。


* document.write()
* document.writeln()
* document.domain
* element.innerHTML
* element.outerHTML
* element.insertAdjacentHTML
* element.onevent

 

脆弱性分析:

主な焦点はメイン ドメイン (https://redacted.com) で。

そのため、サブドメインの列挙は行わず、魅力的な JavaScript ファイルを

探し始めて。

幸運にも興味深い JavaScript ファイルを見つけて。

 

function getParameterByName(name, url) {
    if (!url) url = window.location.href;
    name = name.replace(/[\[\]]/g, "\\$&");
    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
        results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return null;
    return decodeURIComponent(results[2].replace(/\+/g, " "))

 

----------

この関数は、指定された名前のクエリパラメータを取得するためのもので。

以下は処理の詳細で。

1. `name` は取得したいクエリパラメータの名前です。

2. `url` はオプションの引数で、クエリパラメータを含む URL を指定します。

 デフォルトでは現在のウィンドウの URL (`window.location.href`) が使用されます。

3. `name` に含まれる特殊文字(`[`、`]`)をエスケープするために、

 `name` を正規表現で置換しています。

 具体的には、`/[\[\]]/g` の正規表現を使用して、`[` と `]` をエスケープします。

4. `name` を含むクエリパラメータを検索するための正規表現パターンを作成します。

 パターンは `[?&]` + `name` + `(=([^&#]*)|&|#|$)` となっています。

   ・ `[?&]` は `?` もしくは `&` のいずれかの文字とマッチします。

  これはクエリパラメータの開始位置や複数のクエリパラメータの間を

  示すために使用されます。

   ・ `name` は検索するクエリパラメータの名前です。

   ・ `=([^&#]*)` は `=` の後に続く値をキャプチャします。

  値は `[^&#]*` によって `&` や `#` までの任意の文字列として定義されます。

   ・ `|&|#|$` は、値が存在しない場合やクエリパラメータの最後である場合に

  マッチします。

5. 正規表現パターンを使用して、与えられた URL (`url`) からクエリパラメータの

 値を取得します。

 結果は `results` に代入されます。

6. もし `results` が存在しない場合、つまり指定された名前のクエリパラメータが

 見つからなかった場合は、`null` を返します。

7. もし `results[2]` が存在しない場合、つまりクエリパラメータの値が

 見つからなかった場合も、`null` を返します。

8. クエリパラメータの値が見つかった場合は、`results[2]` を

 デコードしてから `+` をスペースに置換し、デコードされた値を返します。

 

この関数は、与えられた URL から特定のクエリパラメータの値を

抽出するために使用されます。

----------

 

URL から 2 つのパラメータとその値を取得するこの JavaScript 関数

getParamByName では、2 つのパラメータを受け取り。

1 つは文字列である name で、URL からパラメータ名を取得し。

この場合は target= で。

2 番目のパラメータの値は、document.URL、document.location などの

URL になり。

この場合、ソースとシンクは次のとおりで。

 

ソース:

window.location.href

 

シンク:

else{cmsService.getClientConfig().then(function(result){if(angular.isDefined(result)){uaService.createAndSetDemographics(result)}$window.location.href=vm.credentials.redirect||"/"})

 

JavaScript を正常に実行するには、ソースから値を取得した後、

次の関数が true である必要があって。

 

$location.path("/")
            } else {
                if (result.token) {
                    window.localStorage.wptoken = result.token
                }
                if (result.status == "ACTIONREQUIRED_2FA_SETUP" && result.token) {
                    twoFactorAuthService.requireAuthSetup("login")
                } else if (result.status == "ACTIONREQUIRED_2FA_VERIFICATION" && result.token) {
                    twoFactorAuthService.requireAuthVerification("login")
                } else if (result.success != "true" && result.status.length > 0) {
                    vm.submitted = false;
                    vm.onError(result.status)
                } else {
                    cmsService.getClientConfig().then(function(result) {
                        if (angular.isDefined(result)) {
                            uaService.createAndSetDemographics(result)
                        }
                        $window.location.href = vm.credentials.redirect || "/"
                    })

 

----------

このコードは、条件に基づいて異なる処理を実行するためのもので。

以下は処理の詳細で。

 

1. 最初の行では、`$location.path("/")` が実行されていますが、

 この行の前後のコンテキストが不足しているため、具体的な動作はわからず。

2. `result.token` が存在する場合、`window.localStorage.wptoken` に

 `result.token` の値が代入されます。

 これはトークンをローカルストレージに保存するためのコードです。

3. `result.status` が "ACTIONREQUIRED_2FA_SETUP" であり、

 かつ `result.token` が存在する場合、

 `twoFactorAuthService.requireAuthSetup("login")` が呼び出されます。

 これは2要素認証の設定が必要な場合に特定の処理を実行するためのコードです。

4. `result.status` が "ACTIONREQUIRED_2FA_VERIFICATION" であり、

 かつ `result.token` が存在する場合、

 `twoFactorAuthService.requireAuthVerification("login")` が呼び出されます。

 これは2要素認証の検証が必要な場合に特定の処理を実行するためのコードです。

5. `result.success` が "true" ではなく、かつ `result.status` の長さが0より大きい場合

 `vm.submitted` が `false` に設定され、`vm.onError(result.status)` が呼び出されます。

 これはエラーが発生した場合にエラーメッセージを表示するための処理です。

6. 上記の条件に当てはまらない場合、`cmsService.getClientConfig()` が

 呼び出されます。

 この関数はクライアントの設定を取得し、その結果を使用して処理を実行します。

7. `angular.isDefined(result)` が `true` の場合、

 `uaService.createAndSetDemographics(result)` が呼び出されます。

 これはユーザエージェントの情報を作成し、設定します。

8. 最後の行では、`$window.location.href` に `vm.credentials.redirect` の値が

 代入されます。

 もし `vm.credentials.redirect` が未定義の場合、

 デフォルトとして "/" が使用されます。

 これにより、指定されたリダイレクト先にページが遷移します。

 このコードは、条件に基づいて特定の処理を実行し、

 リダイレクトを行うためのものです。

----------

 

この例では、最後のステートメントが true であるため、JavaScript が実行されて。

 

JavaScript コードを理解すると、target  パラメータからユーザ指定の入力

を受け取り、それを DOM 別名シンクで実行することが明確にわかって。

そこで、次の JavaScript ペイロードを使用して。

 

 javascript:alert(document.domain)

 

 

Best regards, (^^ゞ