annyoung

XSS와 꿀팁(?)에 대해서 본문

모의해킹

XSS와 꿀팁(?)에 대해서

nopsled 2022. 6. 30. 13:24

시간이 지나면서 해킹에 있어 XSS는 가지각색의 케이스가 있으며 다양한 이름으로 불린다.

 

대부분 서버에 저장되어 발생하는 저장형(Stored XSS)과 저장되지 않고 클라이언트 HTML에만 반영되는 반사형(Reflected XSS)으로 나눌 수 있으며, 여기서 더 상세하게 나눠보면 파라미터 입력값 파싱을 위해 클라이언트 JS에서 반영되어 발생하는 DomXSS, 더 나아가서 XSS가 발생했는지 여부를 모르는 경우 Blind XSS라 칭한다.

 

이를 방어하기 위해서는 필자가 생각하기엔 다음과 같은 두가지 방법이 있다.

 

1) 애초 당시에 XSS를 방지하기 위해서 입력되는 모든 값에 대해 HTML이 반영되지 않도록 Entity Character로 변환하는 과정을 거쳐야 한다. <은 &It; >는 &gt;로 치환하여 클라이언트 사이드에서 HTML 태그가 반영되지 않도록 한다.

2) HTML이 반영되어야 할때가 있는데, 이는 HTML 에디터가 들어가는 블로그의 글 쓰기 기능 같은 부분들은 HTML이 반영되어야 한다. 따라서 HTML이 반영되어야 할때는 무조건 이벤트 태그들을 모두 빈 값으로 치환해야한다.

 

사이트가 많이 레거시하고 매우 여기저기 복잡하게 기능이 얽혀 있는 경우 1번 방법을 사용하지 않고 2번을 사용하는 경우가 수두룩하다. 문제는 이 2번 방법이 때와 장소를 가리지 않고 언제 어디서나 사용하고 있다는 점이다.

 

그래서 꿀팁은?

필자는 가끔 ?query= 파라미터를 만나는 경우 "><img>를 넣어보고, img 태그가 클라이언트에 랜더링되는 경우 이벤트 속성들을 대입하여 찾아본다. 하지만, 입력한 img 태그가 반영되지만 onerror는 치환이 되는 경우 onerror를 우회하거나 이벤트 태그들에 대해 전수조사를 해야되는 경우가 있는데, 필자는 다음과 같이 전수조사를 했다.

자바스크립트로 이벤트 태그 파싱

 

약간의 JS 코딩을 통해 w3schools(링크)에 나오는 모든 HTML 이벤트 속성 값들을 파싱하고, 이를 파이썬에 넣어서 HTML에 반영되는 값들을 확인하는 방법이다. 입력했을때 클라이언트에서 <!--onbeforeprint-->처럼 필터링 해준다면 python selenium 없이 그냥 requests를 사용해서 클라이언트에 온전히 반영된 이벤트 태그만 확인하면 된다.

 

[...document.querySelectorAll('table td:first-child')].map(({innerText}) => `<img src ${innerText}=alert(1)>`);

onerror, onbeforeprint만 입력했을땐 필터링이 되지 않고, 온전하게 HTML 태그 안에 속성 값으로 들어가는 경우만 필터링 되는 경우엔 위와 같은 방법을 사용하면 된다.

 

만약, 여기서 필터링하지 않는 속성들을 찾았다면 그에 상응하는 HTML element를 찾아서 클라이언트에 반영하는 스크립트를 짜면 된다.

 

예를 들어서 oncanplay를 필터링하지 않는다면, <audio src="http://example.com/sample.mp4" oncanplay=alert`1`> 처럼 대입하여 파라미터에 반영시켜서 트리거 해주면 된다.

 

 

React는?

가끔 클라이언트에서 React나 Vue를 심심찮게 만날 수 있는데, 아직까지 이런 케이스는 보지는 못했으나, 이론상은 가능한 방법이라 적겠다. (Vue는 상상을 안해봐서 모르겠다.)

const getFromServer = () => {
  return {
    dangerouslySetInnerHTML: {__html: "<img src onerror=alert`1`"}
  }
}

const MainPage = () => {
  return (
    <React.Fragment ...getFromServer()/>
  )
}

MainPage();

공격자가 CRUD API를 통해 서버에 {dangrouslySetInnerHTML: {__html: '<img src onerror=alert`1`'}}을 저장했다면, ...getFromServer()에 의해 dangrouslySetInnerHTML이 props로 전달되어 HTML이 반영되어 저장형 XSS가 발생하기 때문에 조심해야 한다. (아직 이런 케이스는 보진 못했다..)

 

그렇다면 방어는?

그냥 간단하게 서버에서 Entity character로 변환하는 함수를 만들어 글로벌하게 사용하면 된다. 대부분 프레임워크에서 존재할테니 그걸 사용하면 될 것이다.

사이트가 레거시 하다면.. 모든 페이지 내 파라미터를 전수조사를 하는 방법 밖에 없다고 생각한다.

 

 

Comments