DOM Based XSS

DATE : 2023/12/31

What is DOM

DOM이란 Document Object Model의 준말로

페이지(=문서)의 전체적인 구조를 Object로 나타낸 구조를 말한다.

이때 페이지라는 건, 보통 HTML, head, body tag 안에 수많은 태그들이 쌓여 만들어진다.

그렇다 보니 태그 간의 관계를 나타내보면 위의 그림과 같이 트리 구조의 모델을 만들 수 있게 된다.

그림을 보면 알 수 있듯이 말 그대로

문서를 구성하는 태그(Object)로 문서 구조를 나타내는 트리 구조의 모델DOM이라 한다.

최대한 간단하게 이해하고 넘어가자면, 그냥 HTML 파일을 떠올리면 된다.

What is DOM Based XSS

앞서 DOM이 무엇인지 간략히 정의해보았다.

그렇다면 본 주제인 DOM Based XSS는 무엇일까??

DOM Based XSS는 취약한 JavaScript code로 DOM Object를 제어하는 과정에서 발생한다.

예를 들어 아이디 사용 여부를 확인하는 페이지에서 다음과 같은 코드가 실행된다고 상상해보자.

[ idCheck.php ]

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <form action="./idCheck.php" method="get">
        <input type="text" name="id">
        <input type="submit" value="Check">
    </form>
</body>
</html>
<?php
    $conn = mysqli_connect('localhost','root','PASSWORD','stuff');
    
    if(!$conn) {
        echo mysqli_connect_error($conn);
        exit;
    } else {
        $id = $_GET['id'];

        $sql = "select id from id_stack where id='$id'";
        $result = mysqli_query($conn, $sql);
        
        $row = mysqli_num_rows($result);
        if($row == 0) {
            echo '<script>
                var id = (new URLSearchParams(window.location.search)).get("id");
                if(id){
                    document.write("You can use this id : "+id);
                }
            </script>';
    
        } else {
            echo '<script>
                var id = (new URLSearchParams(window.location.search)).get("id");
                if(id){
                    document.write("You can\'t use this id : "+id);
                }
            </script>';
        }
    }

    mysqli_close($conn);
?>

사용자가 입력 칸에 사용하고자 하는 아이디를 입력하면 해당 아이디가 이미 등록된 아이디인지 확인해

사용 가능 여부를 출력해주는 페이지이다.

만약 사용자가 입력한 아이디가 이미 등록된 아이디라면

해당 아이디를 사용할 수 없다는 문구를 출력하고

사용자가 입력한 아이디가 등록되지 않은 아이디라면

해당 아이디를 사용해도 된다는 문구를 출력한다.

이때 브라우저에 문구를 출력하기 위해 작성된 코드는 아래와 같다.

echo '<script>
    var id = (new URLSearchParams(window.location.search)).get("id");
    if(id){
        document.write("You can use this id : "+id);
    }
</script>';

(1) URL에 들어있는 id parameter를 가져와 변수 id에 할당

(2) id가 존재한다면 document.write() 함수로 문구를 화면에 작성(= 출력)

이때 "id가 존재한다"는 의미는 URL 속에 id parameter가 전달되었다는 의미로

사용자가 아이디를 입력한 경우를 뜻한다.

🤔 그렇다면 이 코드에 어느 부분이 취약하다는 것인지 바-로 알아보도록 하자.

코드에 작성된 document.write() 함수에 주목해보면,

이 함수는 인자로 주어진 문자열을 화면에 그대로 출력하는 기능을 수행한다.

이 말은 HTML tag를 넣으면 tag를 생성할 수 있고,

JavaScript를 작성하면 스크립트를 실행할 수 있다는 말이다.

실제로 그렇게 동작하는 지 확인해보기 위해

입력 칸에 다음과 같이 스크립트를 작성해보았다.

사용자가 입력한 스크립트가 document.write 함수로 들어가게 되면

document.write("You can use this id : <script>alert(1)</script>");

위와 같이 브라우저에서 함수가 만들어지게 되고

결과적으로 스크립트가 실행되면서

팝업 창이 뜨는 걸 확인할 수 있게 된다.

이처럼 HTML 객체를 제어하는 javascript가 작성되어 있는 경우,

이를 활용함으로써 공격자가 원하는 스크립트를 실행할 수 있는 공격DOM Based XSS 라 한다.


DOM Based XSS는 예시에서 본 바와 같이

parameter(=스크립트)가 서버로 전달되었다가 서버에서 다시 브라우저로 돌아오게 됨으로써

스크립트가 그제서야 조립되어 페이지 내부로 들어가게 된다. 💡

Stored XSS 같은 경우에는 공격자가 미리 스크립트를 작성해 서버에 저장해뒀다가

사용자가 요청을 보내면 준비되어 있는 스크립트가 응답 속에 같이 포함된 상태로 전달되는 데

DOM Based XSS 같은 경우는 서버에서 아이디의 존재 여부에 따라

상황에 알맞은 <script> 내용을 페이지에 넣고 브라우저에 보내주고 있다.

주의할 점은 이때 전달되는 <script>가

작성해둔 PHP code의 일부이지, 공격자가 삽입한 스크립트가 아니라는 점이다.

공격자가 삽입한 스크립트는 브라우저가 서버로부터 <script> 내용이 포함된 응답을 받고 난 후,

<script> code에 따라 id 값을 할당하고 document.write() 함수로 출력하는 과정에서!

그제서야 조립되어 페이지 내용으로 들어가는 것이다.

그렇다 보니 스크립트가 실행된다고 하더라도

응답 Packet 속에서는 공격자가 삽입한 스크립트 내용을 찾아볼 수 없을 것이다.

이런 경우에는 "삽입한 스크립트가 Response 안에 들어갔느냐"를 찾기 보다는

"document.write()와 같이 악용할 수 있는 취약한 함수가 있는 지"를 찾는 게 더 쉽다.

(ex. document.write() & innerHTML ...)

삽입한 스크립트가 바로 응답 페이지 속에 들어가는 Reflected XSS와도 비교해보면

둘 다 parameter로 스크립트를 전달하지만 (Get method)

Response 에서 삽입한 스크립트를 찾아볼 수 없을 때!

Reflected XSS가 아닌 DOM Baesd XSS라 판단하면 된다. 🤗

Last updated