티스토리 뷰

728x90
반응형

드림핵 xss-2 문제풀이하던 중 이미지 캡쳐

문제 설명

해당 문제는 드림핵(dreamhack.io)의 워게임 문제로 등록된 xss-1 또는 xss-2 문제로 Cross Site Scripting의 이해를 돕기 위해 출제된 문제입니다. 문제의 목표는 파라미터를 통한 Reflected XSS 취약점을 발생하게 하면 성공하는 문제인데요. 다만 xss-1 문제에서는 단순히 param 파라미터에 <script>alert(1)</script> 을 넣고 전송하면 페이지에 그대로 script 태그가 삽입되면서 alert(1) 이라는 javascript 코드가 잘 실행되었는데요. 문제는 xss-2 에서는 param 파라미터의 값이 HTML 페이지에 정적으로 로딩되지 않고 동적으로 로딩되면서 실행이 되지 않습니다.

 

바로 이 문제에서 동적 로딩으로 인해서 <script> 태그는 정상적으로 실행되지 않는 이유와 <img> 나 <svg> 태그와 같은 Event 속성을 가진 태그에서는 왜 javascript 가 실행되는지에 대한 의문을 가져보면서 동시에 javascript 동적 로딩에 대한 이해를 좀 더 다져보고자 합니다.

 

직접 문제풀이릏 해보고자 하는 분이라면 아래 링크를 통해서 실습해보면 좋을 것 같습니다. 

 https://dreamhack.io/wargame/challenges/268/

 

xss-2

여러 기능과 입력받은 URL을 확인하는 봇이 구현된 서비스입니다. XSS 취약점을 이용해 플래그를 획득하세요. 플래그는 flag.txt, FLAG 변수에 있습니다. Reference ClientSide: XSS

dreamhack.io

javascript 동적 로딩 이해하기

우선 정적 로딩부터...

일반적인 웹 브라우저는 웹 페이지를 렌더링할 때 소스코드를 위에서부터 아래까지의 요소들을 순서대로 렌더링합니다.

다음과 같은 HTML 코드가 있다고 가정해봅시다.

<!doctype html>
<html>
  <head>
    <link rel="stylesheet" href="/static/css/bootstrap.min.css">
    <link rel="stylesheet" href="/static/css/bootstrap-theme.min.css">
    <link rel="stylesheet" href="/static/css/non-responsive.css">
    <title>Index XSS-1</title>

  </head>
<body>

    <div class="container">
      
    <div id='vuln'></div>
    <script>var x=new URLSearchParams(location.search); document.getElementById('vuln').innerHTML = x.get('param');</script>

    </div>

    <!-- Bootstrap core JavaScript -->
    <script src="/static/js/jquery.min.js"></script>
    <script src="/static/js/bootstrap.min.js"></script> 
</body>
</html>

이 때 브라우저는 위에 있는 bootstrap.min.css 파일부터 읽어들여서 로딩할 것이고 제일 마지막에는 bootstrap.min.js 파일을 읽어서 로딩할 것입니다.

 

그 증명은 개발자도구의 Network 탭에서 확인할 수 있습니다. (참고로 해당 페이지는 드림핵 문제의 xss-2 문제의 코드를 예시로 드는 것입니다.)

위와 같이 HTML 소스코드에 정의된 순서대로 로딩하는 것을 보실 수 있습니다.

 

동적 로딩 살펴보기

지금까진 정적인 파일들의 로딩에 대하여 언급하였으니 이제부터는 동적 로딩이 되는 요소들을 살펴봅시다.

바로 script 태그에 선언된 javascript 들이 이에 해당됩니다. jquery.min.js 나 bootstrap.min.js 파일의 내용물에 대해서는 따로 언급하지 않겠습니다. 현재 방금 전의 코드에서 중간에 <script> 태그에 삽입된 내용인 아래 내용만 언급할 예정입니다.

<script>var x=new URLSearchParams(location.search); document.getElementById('vuln').innerHTML = x.get('param');</script>

코드의 의미로는 location.search 즉 ? 물음표 뒤에 오는 파라미터들을 가져오라는 것이며 그 파라미터들 중에서 param 파라미터의 값에 해당하는 것을 vuln 이라는 ID를 가진 요소에 HTML 포맷으로 삽입하라는 것입니다.

 

즉 위 코드가 실행되는 순간의 URL 파라미터가 예를 들어서 아래와 같다면,

?param=<script>alert(1)</script>

vuln 이라는 ID값을 가진 div 태그에는 아래와 같이 삽입되어진다는 의미입니다.

<div id="vuln"><script>alert(1)</script></div>

하지만 위 코드는 실행되지 않습니다. 그 이유는 아까도 언급했다시피 웹 브라우저는 웹 페이지를 렌더링할 때 소스코드를 위에서 아래로 내려오면서 읽는다고 하였습니다. 그리고 브라우저가 해당 script 부분의 내용을 해석할 때 쯤이면 이미 <div id=”vuln”></div> 부분은 건너뛴 상태인 것입니다.

 

그럼 다시 생각해서 "<div id=”vuln”></div> 부분이 script 태그 아래로 내려가면 잘 실행되는가?" 라는 의문이 들 수 있는데요. 그것도 사실 실행되지 않습니다. 아래의 코드를 보겠습니다.

<script>var x=new URLSearchParams(location.search); document.getElementById('vuln').innerHTML = x.get('param');</script>
<div id="vuln"></div>

이 경우에는 script 에서 "vuln 이라는 ID를 가진 요소를 찾으려고 보았는데 찾지 못했다!" 라는 결과가 나옵니다. (참고로 아래 이미지에서는 null 요소에 대해서 innerHTML 이라는 속성을 찾지 못했다라고 하는 데요. 결국에는 vuln 이라는 ID를 찾지 못해서 발생한 오류입니다.)

Uncaught TypeError : Cannot set properties of null (setting 'innerHTML')

그 이유는 다시 말하지만 브라우저는 위에서부터 소스코드를 읽어온다고 했습니다. 근데 위에서 내려오면서 읽어봤는데 vuln ID를 가진 요소는 없었기 때문입니다.

 

결국 위 내용이 증명하는 바는 웹 브라우저는 HTML 코드를 읽어들일 때 위에서 아래의 순서로 읽어온다는 것을 짐작케 합니다.

 

그렇기 때문에 이 문제에서 이해를 요구하는 것은 브라우저 HTML 렌더링 이후에 동적으로 수행되는 요소를 이용해서 script 를 동작하게 하는 방법인 것임을 알 수 있습니다.

 

그리고 그 방법은 바로 DOM Event 라는 것입니다. Event 를 사용하게 되면 브라우저는 특정 이벤트가 발생했을 때 별도의 로직으로 처리하기 때문에 HTML 소스코드 렌더링 순서와는 별개의 것이 됩니다. 가장 대표적인 Event Attribute 을 가진 HTML 태그는 아래와 같습니다.

<img src="" onerror="">
<svg src="" onload="">

사실 이 외에도 Event 들을 정말 다양하고 이런 Event를 가진 태그들도 다양합니다. 더 다양한 HTML DOM Events 에 대해서 참고하려면 아래 링크를 방문해보세요.

https://www.w3schools.com/jsref/dom_obj_event.asp

 

HTML DOM Event Object

W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

www.w3schools.com

 

 

- 끝 -

728x90
반응형
댓글