티스토리 뷰

Wargame/WebGoat

Injection: Cross Site Scripting

장일영 2024. 5. 16. 17:51

 

XSS 유형

  • Reflected
  • DOM-based
  • Stored or Persistent
  • Universal

 

Reflected XSS

Reflected XSS는 웹 어플리케이션의 지정된 파라미터를 사용할 때 발생하는 취약점을 이용한 공격이다. 검색 결과, 에러 메세지 등 서버가 외부에서 입력을 받아 브라우저에 응답할 때, 파라미터에 삽입된 악성 스크립트를 사용자에게 그대로 전달하면서 발생한다.

  1. 공격자는 파라미터에 악성 스크립트가 포함된 URL을 피해자에게 전달한다(링크, 악성 메일 등).
  2. 피해자가 악성 웹 페이지를 로드하는 링크를 클릭해 서버에 요청한다.
  3. 웹 서버의 응답 페이지에 악성 스크립트 포함되고, 이는 피해자의 브라우저에서 실행된다.
  4. 스크립트가 Session ID와 같은 민감한 정보를 훔쳐서 공격자에게 전송한다.

 

DOM-based XSS

DOM을 통해 HTML, XML 등의 정적 문서의 요소에 동적으로 접근하고 업데이트 할 수 있다. DOM에 포함된 스크립트는 브라우저에서 렌더링 할 때 실행되고,  DOM 문서 내의 객체에 접근할 수 있다. 값을 읽거나 쓸 수 있으므로 웹 페이지의 컨텐츠를 동적으로 변화시킬 수 있다.

  1. 공격자는 파라미터에 악성 스크립트를 포함시킨 URL을 작성하여 피해자에게 전달한다(링크, 악성 메일 등).
  2. 피해자의 브라우저는 렌더링 중 HTML을 페이지에 추가하기 위해 `innerHTML`등의 사용자 입력을 구문 분석해 페이지를 동적으로 생성한다.

즉, 서버의 응답 내에는 악성 스크립트가 없으나 브라우저에서 스크립트가 실행되며 악성 스크립트가 추가된다. 특히 이를 예방하기 위해 웹 방화벽에 의존하거나 서버 측 코드에서 필터링하는 경우 URL의 맨 끝에 `#`(Fragment)를 두고 악성 스크립트를 위치시키면 브라우저에서 `#` 문자 뒤의 내용을 서버에 전달하지 않기 때문에 보이지 않게 우회할 수 있다.

 

Stored XSS or Persistent XSS

Stored XSS는 웹 어플리케이션 취약점이 있는 웹 서버에 악성 스크립트를 영속적으로 저장하는 방식이다. 따라서 악성 스크립트가 웹 서버 데이터베이스로부터 온다.

  1. 공격자가 웹 사이트의 입력 form을 통해 POST로 악성 스크립트를 전달하면 서버는 해당 내용을 DB에 저장한다.
  2. 피해자가 해당 페이지를 요청한다.
  3. 서버는 저장된 악성 스크립트를 포함한 응답(페이지)을 전송한다.
  4. 피해자의 브라우저에서 스크립트가 실행되어 XSS 공격이 수행된다.

 

Universal XSS

Universal XSS는 클라이언트 측 취약점으로 경우에 따라 SOP 정책의 제약을 우회할 수 있다. 브라우저 자체의 취약점이나 확장 기능, 플러그인의 취약점을 이용한다.

 

 

10

 

`GoatRouter.js` 파일을 보면 아래와 같은 내용을 찾을 수 있다.

 

`'test/:param': 'testRoute'` 부분을 확인할 수 있다. 현재 페이지의 URL은 `/WebGoat/start.mvc#lesson/CrossSiteScripting.lesson/9`이다. 따라서 테스트 페이지의 URL은 `start.mvc#test`가 된다.

 

11

 

이전 문제에서 찾아낸 경로를 이용해 루트에서 매개변수를 반영하고 인코딩 없이 WebGoat의 내부 함수를 이용할 수 있는지 확인해야 한다.

 

`#test/:param` 형태의 URL을 요청하면 다음 코드가 실행된다.

testRoute: function (param) {
    this.lessonController.testHandler(param);
    //this.menuController.updateMenu(name);
}

 

내부적으로 `lessonController.testHandler()`를 호출한다. 이 함수는 아래와 같다.

this.testHandler = function(param) {
    console.log('test handler');
    this.lessonContentView.showTestParam(param);
};

 

다시 `lessonContentView.showTestParam()` 함수를 호출한다. 이 함수는 아래와 같다.

/* for testing */
showTestParam: function (param) {
    this.$el.find('.lesson-content').html('test:' + param);
}

 

JQuery를 사용해 `$el` 요소에서 클래스 이름이 `.lesson-content`요소를 찾고 여기에 `.html()`을 이용해 타겟 요소의 내용을 제거하고 `param`을 저장한다. `el`은 상단에 정의되어 있다. (`el: '#lesson-content-wrapper'`)

 

따라서 `#test/:param` URL 접속 시 `.html()`로 인해 DOM 요소의 내용이 `param` 값으로 수정된다. 실행하려는 함수는 `webgoat.customjs.phoneHome()`이고 이 함수는 전역에서 실행되므로 `param`에 스크립트를 포함시키면 실행된다.

 

`#test/code` URL 요청 시 아래와 같이 해당 DOM 요소 내에 텍스트가 변경된 것을 확인할 수 있다.

 

바로 스크립트를 넣으면 브라우저는 동적으로 삽입된 스크립트를 실행하지 않으므로 동작하지 않는다. 따라서 이미지 태그를 넣고, `onerror` 이벤트 핸들러를 추가해 이미지 로드에 실패했을 때 스크립트를 실행하도록 한다.

<img src="nowhere" onerror="webgoat.customjs.phoneHme()">

 

 

'Wargame > WebGoat' 카테고리의 다른 글

Server-Side Request Forgery  (0) 2024.05.23
Cross-Site Request Forgery  (0) 2024.05.23
Injection: SQL Injection (intro)  (0) 2024.05.16
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/06   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함