본문 바로가기
  • True knowledge exists in knowing that you know nothing. -Socrates-
web/웹 해킹 및 보안

Dom Clobbering (with XSS)

by intadd 2019. 11. 30.

 

 

안녕하세요. intadd 입니다.

 

 

Dom clobbering을 활용한 xss 에 대해서 포스팅하겠습니다.

작성 계기는 재밌어 보여서입니다. 

 

 

그리고 Dom Clobbering 에 대한 기술적 설명이 있는 한글 문서가 없더라구여 그래서 작성하게 되었습니다.

(있으면 링크좀 부탁드리겠습니다,,, ㅎ)

 

+

 

최근에 발생한(2019년 8월) GMaill xss 가 Dom Clobbering 기반으로 익스 되었다고 함

(이 내용도 뒤에 다루겠습니다.)

 

 

Dom Clobbering에 대해서 처음알았기도 하고 너무 신기하고 재밌습니다.

이 기술이 나온지는 조금 오래 됐다고 합니다. 

(저만 늦게 안거 같네요,, 근데 진짜 신기합니다.)

 

또한 이 글은 

https://research.securitum.com/xss-in-amp4email-dom-clobbering/

https://www.netsparker.com.tr/blog/web-guvenligi/dom-clobbering/

https://medium.com/@terjanq/dom-clobbering-techniques-8443547ebe94

 

위 세개의 글을 번역 + 정리+추가 하여 작성한 글입니다.

더 자세하게 알고 싶으신 분은 원본 글을 읽는 것을 추천드립니다.

 

 

 

DoM이란 무엇인가?

https://wit.nts-corp.com/2019/02/14/5522

위 블로그 글에서 "요약정리" 에서 말하는 Dom의 사용 이유중 1

"페이지의 콘텐츠 및 구조, 그리고 스타일이 자바스크립트 프로그램에 의해 수정되기 위해 사용됩니다."

라고 합니다. 한번 읽어 보시면 좋을 것 같습니다. ㅎㅎ

(안읽어 봐도 DOM 이 뭔지 알면 좋을 것 같습니다.)

 

 

Dom Clobbering 이란

 

클로버링 (Clobbering)은

(처음 papago에 처보니까 두두려 패다? 라고 나오길래 아니 어떻게 해야 Dom을 두두려 패버리는 것인가. 라고 생각했습니다. ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ)

 

 

진짜 정의 : 파일 또는 데이터의 우연적인 삭제 또는 겹쳐 씀을 말한다. 라고 합니다.

 

예를 들어

<a id="CONFIG"></a>

이 태그가 있다고 가정합시다.

 

일반적으로는 해당 태그에 접근하기 위해서는

javasciprt 방법

document.getElementById('CONFIG')

을 많이 사용합니다.

하지만 

window object를 통해서 

document.getElementById와 동일 하게 사용할 수 있습니다.

window.CONFIG

 

이를(window.name)통해 global 변수를 존재 여부로 판단하는 코드에서

문제가 발생합니다.

 

어떻게 문제를 발생 시킬지는 아래에서 다루겠습니다.

 

이를 이용한 취약점을 Dom Clobbering이라고 합니다.

 

 

자 그러면 dom 을 어떻게 겹치고 사용하는지 보겠습니다.

 

브라우저는 FORM의 elements 중 name 과 id 를 Form 의 property으로 처리합니다.

 만약에 "FORM에 동일한 property 이름이있는 경우 FORM의 element(id,name)가 property으로 대체됩니다."

 

즉 form.propertyname 이 이미 있는 상태에서

form 의 id나 name에 propertyname 이 들어가게 되면

 

form.propertyname 은 기존에 있던 

propertyname이 아닌 

 getElementid (id,name) 처럼 사용된다는 것입니다

(property 란?)

 

 

 

잘 이해가 안가시면 아래 test를 봅시다. 

 

 

Dom Clobbering Test1

 

test1.

test.html  (A)

위는 특이한 점이 없는 단순한 form 태그와 input 태그입니다.

8~10 라인은 forms[0] 의 submit 을 실행하는 js 입니다.

(forms[0] = form 태그들 중에 0번째)

 

브라우저를 통해서 열어보면 계속 정상적으로 action="" 값으로 submit() 함수를 실행할 것입니다.

(아마 계속 반복하겠죠? 중요한거 아닙니다.)

 

자여기서 Dom Clobbering  을 살짝 사용해보면 아래와 같습니다.

test.html (B)

5번 라인만 변경했습니다. name="submit"  (input 태그의 name 을 submit으로 지정)

 

 브라우저를 통해서 확인해보면

대충 forms[0] 에 submit 은 함수가 아닌데 왜 함수로 썼냐고 화내는 브라우저 모습

 

!!!!!!????????????
!!!!!!???????????

 

너무 신기하지 않나요?

 

 자 그러면 관리자 도구로 값을 확인해보겠습니다.

첫번 째 (그림 A) 는 아래와 같이 정상적으로 submit() function 을 리턴하고 있습니다.

 

두번 째 (그림 B Dom clobbering) 는 아래와 같이 function 이 아닌 input Code를 리턴하고있습니다.

 

자 위의 실습을 정리를 해보면 

 

원래 정상적으로는 document.forms[0].submit 의 값이 submit() fuction(함수)가 되는 것이 맞습니다.

하지만 name의 값을 submit 으로 지정해주므로써 (dom clobbering)

(Property(submit()) 가 덮어씌어짐)

document.forms[0].submit 이 코드가  

submit 함수가 아닌 , forms[0] 의 "name이 submit"인 값을 찾게 되는거죠.

 

이거 저만 신기하나요? ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

 

(cf. window 안썼는데 저게 왜 전역이야 ? ㅡㅡ,

--> document == window.document)

 

또한

 

 

문서 개체(document object)의 property 와 동일한 이름을 가지고 있거나

같은 이름의 변수가 global scope에 있을 경우에 곂침이 발생하여 

Overwrite(덮어씌어짐)가 발생합니다.

 

test1.html

자 위의 소스코드를 보시면 <div> 태그가 있고,

아래에 js를 통해서 intadd 라는 Elementid를 갖고 오겠다 뭐이런 의미입니다.

추가적으로 변수나 다른 작업을 안해서 가지고만 오는 코드입니다.

 

Hackhi 는 <div> 안에 텍스트가 출력된겁니다. line 2

 

콘솔에 에러도 안뜨고 모두가 평화롭고 정상적으로 작동하네요

대충 document.getElementById 는 함수고 잘 작동한다는 크롬 console 내용 

 

매우 잘 작동하죠?

document.getElementById 함수가 매우 잘 작동합니다. 

 

 

여기서 Dom Clobbering 한번 넣어보겠습니다.

form 태그의 name을 getElementById 로 지정한 모습 line3

 

동일한 소스코드에 3~4 라인만 추가되었습니다.

form 태그의 name이 getElementById 가 되었네요

 

브라우저를 통한 콘솔을 확인해보면

 

대충 getElementById 는 함수가 아닌데 왜 함수로 쓰냐고 화내는 크롬 에러 내용 

(코알라 짤 + 고양이 짤) 한번더 쓰겠습니다. 

 

여기까지가 Dom Clobbering 에대한 설명과 예시입니다.

이해가 가시나요? 

이해가 안가시면 제가 설명을 잘 못한것 같습니다,, ㅜㅜ

 

 

 

 이제 실제 Dom Clobbering 을 이용한 XSS 에 대해서 알아보겠습니다.

 

여기까지만 보시면,

음 아 대충 dom clobbering 이 이런거구나,,

의심의 눈초리

,,,,,,,,

근데 ?

이걸로 뭐할건데?

뭐지,,,?

잉?

라는 결론에 도출합니다.

 

 

이제 xss 에 활용해보겠습니다.

 

조건.

1. HTML injection 이 가능해야한다.

2. 1번을 통해 작성되는 html  tag가 js 가 해당 object 에 접근 하기 전에 선언 되어 있어야한다.

 

간단하게 2개정도가 되겠네요

 

 

 

1번은 뭐,, 단순한 xss의 선행 조건이기도 하니까요

 

 

다른 사이트들에서 사용한 예시를 약간 수정해서 사용하겠습니다.

이러한 js 가 있습니다. 

 

위의 소스코드만 보면 8~15 line 까지 CONFIG (object)를 정의해줍니다.

8 line : window.CONFIG 가 없을 경우 {..} 값을 지정 

13 line: CONFIG.test 가 false 가 아닐 때 document.write를 통해서

"A" 를 작성할 겁니다.

 

정상적이라면 이 8~15라인을 수정하지 않는 한 

14라인을 실행시킬 수 없습니다. 

 

위를 브라우저를 통해 열어보면 당연히 "A" 는 출력 되지 않고, 

CONFIG.test 도 false 입니다. 

여기서 위에서 다룬 DOM Clobbering 을 적용하면

위 5 line에 입력 하겠습니다.

 

5~7 라인을 추가했습니다.

 

위를 브라우저로 올려보면 

 

그림99

 

 

자 이렇게 DOM Clobbering 을 통해서

간단한 js 우회? 를 해봤습니다.

 

원리는 생략해도 될까요? 하하 ...

 

이 우회가 가능헀던 이유 1번 째는  10 라인입니다.

window.CONFIG = window. CONFIG || { .. 이하 생략 ..}

이 구문에서 window.CONFIG 가 존재하면

그대로 사용하고, 아니면 { 이하 생략 } 으로 대체한다 라는 구문입니다.

 

정상적이라면 window.CONFIG 가 undefined 이겠지만,

Dom clobbering을 통해서 <input >로 대체 된겁니다.

 

그러므로 15 라인을 통과한 것이지요 

 

 

자 그러면 XSS 를 하는 방법에 대해서 보겠습니다. 

 

원하는 값을 쓰기 위해서는 return 값이 object 가 아닌

저희가 조작할 수 있는 데이터가 들어가야합니다.

 

어떠한 함수를 사용하는지에 따라서 데이터를 넣을 수 있는지 없는지가 나누어집니다.

 

출처: https://www.slideshare.net/x00mario/in-the-dom-no-one-will-hear-you-scream

위의 table 에 적혀있는 것들이 ToString을 사용하는 것들이네요 

 

 

태그 중 ToString 방법이 Object.prototype으로 부터 계승 되는지 

아니면 다른 방식으로 정의 되는지 확인하여야 합니다.

 

이게 무슨 말이냐면,

객체들이 가지고 있는 ToString 이라는 function 이

어떠한 방법으로 구현?(계승) 되는지를 판단하는 겁니다.

 

 

 확인하는 js 코드입니다.

Elements 를 포함하는 개체들 중 prototype.toString 과

Object.prototype.toString 이 이 다른 것을 찾아라 하는 코드입니다.

결과는 <a> 태그와 <area> 태그가 있네요

 

어떻게 다른지 확인해보겠습니다.

 

 

자 위의 코드가 있습니다.

해당 태그들의 toString 값을 확인해 볼까요?

 

 

자 그러면 A Tag의 (object , HTMLAnchorElement) 의 toString은 어디서 값을 가져오는 걸까요?

 

https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/toString

위의 보시면 "href" 값을 반환한다고 되어 있습니다.

 

 

이를 이용해서 값을 변조하는 예시를 보겠습니다.

이러한 소스코드가 있다고 가정합시다.

 

13 라인을 보시면

CONFIG.KeyValue 값이 false가 아닐경우

CONFIG 의 ToLocation 으로 이동 시킵니다. (14 line )

 

false일 경우

CONFIG 의 DefaultLocation 으로 이동시킨다고 합니다.(17 line)

 

저의의 목표는 Dom Clobbering 을 적용하여 alert를 발생시키는 것입니다.

 

 

조건 1. CONFIG 가 False 아니여야 한다.

조건 2. window.CONFIG.Location 이 js alert를 가르켜야한다.

 

조건 1번은 이미 했기 때문에 넘어가겠습니다.

 

저희는 a Tag의 toString이 href 라는 것을 알고 있습니다.

 

window.CONFIG.ToLocation을 변경하기 위해서는 

이러한 HTML 이 있으면 되겠죠?

 

 

위의 코드로 테스트를 해보면

undefined으로 가게된니다.

 

왜일까요?

 

input 태그는 form 태그의 속성값으로 사용 할 수 있지만,

a 태그는 form 태그의 속성값으로 사용 할 수 없습니다.

 

그러면 다른 방법을 사용하여야 합니다.

 

HTML Collections에 대한 활용 

 

 

'

이러한 동일한 id를 갖는 a tag 가 있습니다.

우리가 window.hello 를 출력하면

< a id ="hello">1</a>

(동일 속성값의 첫번 째)

가 나올 것으로 예상 할 수 있습니다.

하지만 값을 확인해보면,

 

자 이렇게 보시면 HTMLCollection이 반환되는 것을 확인 할 수 있습니다.

 

또한 저희는 HTMLCollection을 index(0,1) 와 id로 접근 할 수 있는 것을 알고있습니다.

 

window.hello.hello 로 접근을 하면 첫 번 째  element을 반환하네요

 

name을 통해서 HTMLCollection에 새로운 속성도 생성 할 수 있습니다.

 

 

자 이걸 정리해보면

동일한 id를 만들어 HTMLCollection을 만든 후

id 중 하나를 name 을 통해 새로운 속성으로 만들어주는 겁니다.

 

 

다시 저희가 문제를 보겠습니다.

 

조건 2. window.CONFIG.Location 이 js alert를 가르켜야한다.

를 구현한다면,

이렇게 되겠죠?

 

브라우저를 통해서 확인해보면 

 

짠 이렇게 alert가 정상 작동합니다.

 

값을 확인해보겠습니다.

 

이해가 가시나요?

 

 

 

자 그러면 구글 GMAIL의 AMP4EMAIL 케이스를 보겠습니다.

 

 

문제점이 발생한 소스코드를 보기 쉽게 정리하면 아래와 같습니다.

 

 

출처: https://research.securitum.com/xss-in-amp4email-dom-clobbering/

자 위에서 Dom Clobbering 을 공부했으니 취약점이 보이시나요?

5 line:

AMP_MODE.test (window.AMP_MODE.test) 와 window.testLocation 존재 여부를 검사하네요

True 일 경우 window.testLocation을 사용한다고 합니다.

또한

11 line:

AMP.localDev 가 False 이면 loc를 cdn.. 으로 넣기 때문에

payload가 성립이 안됩니다.

 

근데 이 값들은 다 저희가 만들어줄 수 있죠!

Dom Clobbering을 통해서 ㅎㅎ 

 

 

그러므로 다시 필요 없는 코드를 다 제거하면,

(b 는 line 1~2 의 script 입니다.)

 

출처 : https://research.securitum.com/xss-in-amp4email-dom-clobbering/

위와 같이 되겠네요

 

원하는 js 주소를 를 script(b)의 src로 지정하기 위해서는 

출처 : https://research.securitum.com/xss-in-amp4email-dom-clobbering/

위와 같은 페이로드가 나오네요

주석도 잘 달려 있어서 따로 설명은 안해도 될꺼 같은데 ㅎㅎ

 

Payload를 완성하기 위한 조건.

1.AMP_MODE.localDev 와 AMP_MODE.test 가 False 이면 안됩니다.

이를 충족하기 위해서 2~4 line이 있는 겁니다.

 

 2. testLocation.protocol 의 값을 원하는 값으로 변경하여야 한다.

7~9 line이 있는 겁니다.

 

이렇게 하면 pastebin/생략.js으로 <script src= 가 되겠네요

!!!!!!

 

 

이걸로 Dom Clobbering  포스팅을 마무리 할려고 합니다...

아 그전에 잠깐,

방금 봤던 Gmail Xss 는 결론적으로 CSP 때문에 

완벽하게 동작하지 못했다고 하네요 

(What is CSP? )

 

 

 

하하 아무튼 포스팅은 여기까지 하겠습니다.

너무 오래 걸렸네요... 힘들다..

 

보안 기법도 해야하는데,,

 

 

다음에 뵙겠습니다.

피곤한 곰방와

안녕~

댓글