본문 바로가기

Webhacking/WebGoat

[WebGoat] Injection-Cross Site Scripting 풀이

728x90
반응형

이번챕터는 XSS에 대한 내용을 담고있다. 원래 XSS는 Injection과 별개로 OWASP에서 항목이 있었는데, 2021 항목에서 Injection에 포함되었다. XSS도 어찌보면 클라이언트사이드 코드 인젝션처럼 볼 수 있으니, 이해가 된다. 

문제 풀어보자. (첫번째 문제는 그냥 체크박스 클릭만 하면 되기때문에, 그냥 넘어가고 다음문제부터 풀이하겠다)

Reflected XSS 문제이다. alert나 console.log를 실행시키면 되는 문제인데, 일단 지금 당장은 공격을 할 부분이 마땅히 보이지 않으니, Purchase를 눌러보자.

Purchase 버튼을 누르니, 추가 정보가 서버로부터 응답되었다. 응답된 정보를 살펴보다보니, 입력되어있던 credit card number가 응답값에 노출됨을 확인할 수 있다. 정리하면 Purchase를 누를때 발생한 Request에 포함된 credit card number 입력값이, 서버를 통해 그대로 응답되고 있음을 알 수 있다. 여기가 공격 포인트다.

개발자도구를 통해 코드를 보니, 응답값은 <p> 태그 내부에 존재하는 텍스트 형태의 데이터임을 알 수 있었다.
그래서 Payload는 정상적으로 <p>태그를 닫고 <script>태그를 이용하여 alert(document.domain)을 실행시킨뒤 다시 <p>태그를 작성하여 뒤에 남은 코드들에 문제가 없도록 작성하였다.
Payload : </p><script>alert(document.domain)</script><p>

alert 함수가 정상적으로 실행되고, 확인버튼을 누르면 문제가 풀이됨을 확인할 수 있다.
다음 문제로 넘어가자.

DOM-based XSS 문제다. 
특이한건, 문제 페이지 자체에서 트리거해서 푸는형태가 아니라, DOM-Based XSS를 지닌 페이지를 JS 코드분석을 통해 찾으라고 하고있다. 이때 test 코드가 있으니, 이를 찾으면 된다고까지도 설명해주고 있다. 
WebGoat는 JS코드를 통해 URI 기반으로 페이지 라우팅을 제공하고있다. 문제에서도 start.mvc#lesson 이 예시임을 설명해주고 있다. 우선 예시를 기반으로 개발자도구에서 코드 검색을 진행해보자.

검색해보니 라우팅을 담당하는듯 하는 GoatRouter.js를 찾을수 있었다. 코드를 보자.

코드를 보면 라우팅 관련한 정보들이 있는데, 이중 test관련한 것이 눈에띈다. 그리고 예시로 준 lesson도 눈에 보인다.
예시가 strat.mvc#lesson 이었으니 테스트 route는 start.mvc#test가 된다. 
그대로 넣고 인증해보자.

다음 문제로 가자.

이번문제는 진짜 DOM-Based XSS이다. webgoat.customjs.phoneHome 함수를 실행시켜 결과를 얻으면 되는데, 물론 콘솔에서 그냥 실행시켜도 보이겠지만, 이전에 찾아낸 test route를 이용하라고 한다. 위에서 본 코드에 의하면 start.mvc#test/:param 이런식으로 URI에 입력하면 testRoute에 의한 행동이 일어난다고 한다. 그렇다면 testRoute에 대한 코드를 한번 보자.

코드가 별게없고... testHandler에 내가 입력한 데이터를 보낸다고 한다. 그러면 testHandler를 살펴보자.
(Search 기능을 이용하면 찾기 수월하다.)

testHandler 역시 코드가 딱히 길지않다. console log하나를 찍고, 이번엔 showTestparam을 호출한다. 다시한번 코드를 따라가보자.

드디어 나왔다. lesson-content 부분에 html코드로서 추가한다는 것을 알 수 있다. jQuery .html() 함수를 이용고 있다.
여기서 jQuery .html 함수는 브라우저의 기본 javascript의 innerhtml을 이용하기 때문에 기본적으로 <script> 태그가 실행되지 않는다. (참고 : http://api.jquery.com/html/) 그렇기때문에 <img>태그의 onerror 이벤트 핸들러를 이용하여 실행시켜보도록 하겠다.

URI에 start.mvc#test/1234라고 입력하자, 화면에 test:1234라고 데이터가 나타남을 확인할 수 있다.
그럼이제 1234대신 '<img src="asdf" onerror="console.log(webgoat.customjs.phoneHome())">' 를 넣고 실행해보자.

console에 뭔가 데이터가 나타나며 공격에 성공함을 알 수 있다. 나타난 숫자를 이용하여 문제에 인증해보자.

문제가 풀렸다.
마지막 문제는 문제가아닌 퀴즈라... 따로 풀이를 하지 않는다.

Reflected, DOM-Based, Stored 어떤 방식이던간에 XSS에 대한 대응방안은 사실 똑같다. 특수문자 필터링이다.
꼭 HTML 태그를 사용해야하는 에디터와 같은 경우가 아니라면 HTML Entity encoding을 수행하면 대부분의 XSS 문제는 해소할 수 있다. 하지만 사용할 수 없는경우, 반드시 사용해야하는 HTML태그와 Attribute들을 화이트리스트로 필터링하는 로직이 필요하다.

아까 푼 Reflected XSS 문제에 HTML Entity encoding을 적용하여 취약점을 조치해보면서 실습해보자.

CrossSiteScriptingLesson5a.java에 보면 Reflected XSS 문제에 대한 코드가 있다.
여기서 취약점을 발생시키는 코드가 바로 드래그된 cart.append 구문이다. 파라미터를 통해 전달된 값 그대로 저장한 field1을 그냥 html코드에 이어붙였기때문에 취약점이 발생하고 있다.
위에서 말한 HTML Entity encoding을 적용하여 조치해보도록 하자.
(이때 org.springframework.web.util.HtmlUtils를 추가로 import 해주어야하니 상단 import 부분에 추가해주도록 하자)

field1을 HtmlUtils.htmlEscape(field1)으로 변경해주면 된다.
이제 빌드하고 다시 실행시킨 뒤, 풀었을때 처럼 공격해보자.

문제가 풀렸다고는 나오지만, 실질적으로 아까처럼 alert가 발생하지는 않는다. 왜냐하면 실제로는 조치되었기 때문이다.
드래그한곳을 보면 아까 공격에 성공했을때는 아무것도 나타나지 않았는데, 지금은 내가 입력한 값 그대로 응답되고 있음을 알 수 있다. 코드로 한번 살펴보자.

이렇게만 봤을때는, 조치가 된건지 안된건지 모르겠다. 코드 위에서 오른쪽 마우스를 클릭하여 Edit as HTML을 선택해보자.

보면 실제로 내가 넣었던 특수문자들이 다 HTML Entity로 변화되어 응답되고있음을 확인할 수 있다.
그래서 화면으로 보기에는 내가 입력한 값이 그대로 응답된 것 같지만, 실제로 HTML 코드처럼 동작하지 않아 Reflected XSS 공격에 실패한 것이다.

이렇게 HTML Entity encoding만 넣어도 쉽게 XSS로부터 안전해 질 수 있다.


728x90
반응형