티스토리 뷰

728x90
반응형

출처 : http://xss-game.appspot.com/level3

 

3단계에서는 어떤 input 입력란이 없었다. 마찬가지로 alert 를 띄우면 되는 문제인데, image 1, image 2, image 3 버튼을 눌러보았을 때 URL이 변경되는 걸 확인할 수 있다. 아래는 image 3 을 눌렀을 때 URL인데 frame#3 이 의미심장하다. 이 곳에 한번 다른 문자열을 임의로 입력해보겠다.

 

 

한번 hello 라는 문자열을 입력해보았고 그 결과는 다음과 같았다.

 

 

이미지가 NaN 이라고 나오며, 아래 이미지는 깨지는 걸 알 수 있다. 그리고 HTML 소스코드를 보았을 때는 다음과 같았다. 우리가 입력한 hello 가 img 태그의 src 내에 cloud와 .jpg 문자열 사이에 들어감을 알 수 있다.

 

 

그러면 이 곳에 이미지 태그를 활용한 injection을 해보면 되겠다. 일반적으로 img 태그를 활용한 alert 띄우는 방법은 아래와 같다. 아래 코드는 img 태그의 src 가 존재하지 않는 이미지 경로일 경우에 onerror 속성에 정의한 javascript 를 실행하게 되는 기능을 한다.

<img src="none" onerror="alert(1)">

우리가 입력한 hello를 이번에는 그럼 아래와 같이 입력해보자.

" onerror="alert(1)" class="

그러면 아래와 같이 img 태그가 완성될 것으로 예상된다.

<img src="/static/level3/cloud" onerror="alert(1)" class=".jpg">

 

하지만 예상외로 alert 가 나오지 않았는데, 그 이유는 다음과 같다. 아래 script는 페이지가 처음 로딩 될 때 정의되고 실행되는 스크립트이다. 우선 chooseTab이란 함수가 정의되고, window 가 로딩이 되었을 때 chooseTab(unescape(self.location.hash.substr(1)) || "1") 가 실행된다고 한다.

 

우선 아래 코드부터 설명하자면, self.location.hash는 현재 URL 주소의 hash 태그를 추출하는데, 이 때 substr(1)은 첫 번째 글자를 제거하라는 함수이다. 그래서 아래 URL 을 예로 들면 #abcd 에서 abcd만 추출되는 것이다.

self.location.hash.substr(1)

// http://www.test.com/hello#abcd
// abcd

그리고 unescape 함수는 쉽게 말해 URL 디코딩 함수다. 그냥 URL 인코딩된 문자열이 들어왔을 때 디코딩해준다.

그리고 디코딩된 문자열을 chooseTab 함수의 파라미터로 넘겨주게 된다.

 

chooseTab 함수를 자세히 보자. 우리가 넘겨준 디코딩된 문자열을 num이라는 변수에 들어갈 것이다. 여기서 왜 우리가 넘겨준 " onerror="alert(1)" class=" 라는 문자열이 동작하지 않았는지 알 수 있다. 아래 html 변수에 삽입하는 문자열을 보면, img 태그의 src 속성을 감싸고 있는 따옴표가 작은 따옴표(')이기 때문이다. html 태그에서 작은 따옴표 안에 큰 따옴표(")가 들어오면 그것을 문자열로 인식해서 html encoding을 해버린다. 그렇기 때문에 src 속성을 닫아주려면 짝은 따옴표를 사용해서 열었기 때문에 작은 따옴표로 닫아주어야 하는 것이다.

function chooseTab(num) {
    // Dynamically load the appropriate image.
    var html = "Image " + parseInt(num) + "<br>";
    html += "<img src='/static/level3/cloud" + num + ".jpg' />";
    $('#tabContent').html(html);

    window.location.hash = num;

    // Select the current tab
    var tabs = document.querySelectorAll('.tab');
    for (var i = 0; i < tabs.length; i++) {
        if (tabs[i].id == "tab" + parseInt(num)) {
            tabs[i].className = "tab active";
        } else {
            tabs[i].className = "tab";
        }
    }
}

 

그렇게만 하면 3 단계도 통과가 된다.

 

 

- 끝 -

728x90
반응형
댓글