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, (^^ゞ