Web,Mobile/Tech

String, Number형 변수를 이용한 XSS Bypass

LimeLee 2023. 8. 8. 11:05

1. 문제

사용자의 입력 값을 script 태그 안의 변수에 선언하는 경우가 있다.

// Request https://test_page.xyz/test?code=CODE&mode=ACD&value=test&count=1&dept=0&name=%ED%85%8C%EC%8A%A4%ED%8A%B8

// Response
<html>
    <body>
<script>
var code = "CODE";
var mode = "ACD";
var value = "test";
var count = 1;
var dept = 0;
var name = "테스트";
</script>
    </body>
</html>

필터링이 미흡할 경우 사용자 입력 값에 악의적인 스크립트를 넣어 실행할 수 있다.

그래서 필터링을 적용해보았다. 탐지하는 문자는 다음과 같고 탐지하는 문자를 사용 시 페이지 자체가 차단되도록 했다.

' " `
%0d %0a ; %20
() [] {} . < >
+ - 
string href concat document script
alert confirm prompt console.log 
eval

URL Encoding 우회 불가 
ex) ev%61l ev%2561l 등등

구분자가 필터링되어 있으므로 code, mode, value, name는 더블 쿼터를 나갈 수 없다.


count, deptNumber형으로 변수를 받고 있어 구분자를 사용할 필요가 없다.

 

count, dept 파라미터에 스크립트를 삽입하면 가능성이 있어보이지만 여러 함수들이 막혀있다. alert 및 alert를 대체할 수 있는 함수 모두 사용할 수 없다.

 

문자열을 스크립트로 실행할 수 있다면 alert 함수에 대한 필터링을 우회할 수 있다. Unicode escape sequence나 문자열 합치기 등이 있다. +concat이 필터링되어있어 문자열 합치기는 힘들 수 있지만 \xZZ 인코딩 형태를 사용함으로써 우회가 가능해보인다. 다만 어느 형태의 변수이건 구분자는 차단되어 있다.

 

=> 문자열 합치기
var a="al";var b="ert(1)";
"a".concat("lert(1)");
"al"+"ert(1)";

=> Unicode escape sequence
"ale\x72t(1)"

 

또한 문자열로 스크립트를 만들었다해도 문자열을 스크립트로 실행해야 하는 문제가 남아있다.

 

eval 함수는 차단되어 있고 이전 게시물에서 썼던 페이로드도 사용할 수 없다. 점 표기법, 대괄호 표기법으로 constructor에 접근하지 못하고, 소괄호가 막혀있어 생성자의 다른 문법 Function() 등을 사용할 수 없다.

 

 

JSFuck과 Function 객체 생성자를 이용한 XSS Bypass

0. 서론 스크립트 태그 영역 안에서 별도의 태그나 이벤트 핸들러를 사용하지 않고 XSS 취약점을 터트리는 경우 서버에서 XSS 스크립트 실행에 사용해야 할 함수(여기서는 'alert' 를 예시로 든다.)

blog.limelee.xyz

 

eval 함수는 우회할 수는 있지만 조건이 있다. 예로 들어 서버에서 사용자 입력 값에 document라는 문자열이 들어올 경우 공백으로 치환하는 필터링이 적용되어 있다면 evdcoumental 를 입력할 시 서버에서 공백처리하고 최종적으로 응답 값으로 넘어올 때는 eval이므로 함수를 사용할 수 있다. 하지만 공백 치환 필터링은 구현해두지 않았다.

 

이렇게 꽤나 빡빡하게 필터링되어 있으나 우회가 가능하다.

아래 우회 방법을 적어두었지만 보기 전에 한번 스스로 고민해봐도 좋을 듯 하다.

 



 

2. 우회

해당 우회에는 조건이 있다.

 

1. 사용자 입력 값이 반영되는 Number 형 변수와 String형 변수가 존재할 것

2. String형 변수는 반드시 Number 형 변수보다 위에 선언될 것.

 

위 페이지는 2가지 조건을 만족하는 value 파라미터와 count 파라미터를 이용한다.

 

value 파라미터는 더블쿼터 밖으로 나가 원하는 스크립트를 실행할 수 없다. 스크립트를 실행하는 구문은 count 파라미터에 입력해야한다. ; 를 사용할 수 없으므로 count 변수 선언 시 스크립트가 실행될 수 있어야 한다.

그래서 location을 사용한다.

 

href, ., [, ] 가 필터링되어 있지만 location.href='a'location='a' 는 동일한 동작을 한다.

 

 

XSS Bypass in window.location

사용자의 입력 값이 window.location의 속성이나 메소드에 반영되는 서비스들이 종종 있다. 보통 XSS가 발생하는 공격 벡터인데 XSS 방지를 위해 싱글쿼터 또는 더블쿼터를 escape 처리를 해두기도 한다

blog.limelee.xyz

 

만약에 필터링이 없다 가정하고 count 파라미터에 location='javascript:alert(1)' 을 삽입하면

응답 값에는 var count = location='javascript:alert(1)' 이런 식으로 반영이 될 것이다.

 

그렇게 되면 count 변수에 location='javascript:alert(1)'의 결과 값인 'javascript:alert(1)'를 저장하기 위해 location='javascript:alert(1)'를 실행할 수 있게 된다.

 

하지만 구분자를 사용할 수 없다. 이 점을 String 형 변수 value를 이용해 우회한다.

 

value 파라미터에 javascript:alert(1)을 입력한다. scriptalert, (, ) 의 경우 필터링 되어 있으므로 Unicode escape sequence를 이용하여 우회한다.

응답 값에는 var value = "javasc\x72ipt:ale\x72t\x281\x29" 가 되어 value 변수에는 실행하고픈 스크립트가 선언된다.

 

그리고 count 파라미터에서 value 변수를 호출함으로 구분자를 사용하지 않고 스크립트를 사용할 수 있게된다.

이를 종합하여 다음과 같은 페이로드를 만든다.

value=javasc\x72ipt:ale\x72t\x281\x29&count=location=value

 

사용자 입력 값이 반영되는 Number 형 변수가 드물긴 하지만 사용할 시에는 유효성 검증(count 파라미터에 숫자만 받는다던지)은 반드시 필요하겠다.