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
, dept
는 Number
형으로 변수를 받고 있어 구분자를 사용할 필요가 없다.
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() 등을 사용할 수 없다.
eval
함수는 우회할 수는 있지만 조건이 있다. 예로 들어 서버에서 사용자 입력 값에 document라는 문자열이 들어올 경우 공백으로 치환하는 필터링이 적용되어 있다면 evdcoumental
를 입력할 시 서버에서 공백처리하고 최종적으로 응답 값으로 넘어올 때는 eval
이므로 함수를 사용할 수 있다. 하지만 공백 치환 필터링은 구현해두지 않았다.
이렇게 꽤나 빡빡하게 필터링되어 있으나 우회가 가능하다.
아래 우회 방법을 적어두었지만 보기 전에 한번 스스로 고민해봐도 좋을 듯 하다.
2. 우회
해당 우회에는 조건이 있다.
1. 사용자 입력 값이 반영되는 Number
형 변수와 String
형 변수가 존재할 것
2. String
형 변수는 반드시 Number
형 변수보다 위에 선언될 것.
위 페이지는 2가지 조건을 만족하는 value
파라미터와 count
파라미터를 이용한다.
value
파라미터는 더블쿼터 밖으로 나가 원하는 스크립트를 실행할 수 없다. 스크립트를 실행하는 구문은 count
파라미터에 입력해야한다. ;
를 사용할 수 없으므로 count
변수 선언 시 스크립트가 실행될 수 있어야 한다.
그래서 location
을 사용한다.
href
, .
, [
, ]
가 필터링되어 있지만 location.href='a'
와 location='a'
는 동일한 동작을 한다.
만약에 필터링이 없다 가정하고 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)
을 입력한다. script
와 alert
, (
, )
의 경우 필터링 되어 있으므로 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 파라미터에 숫자만 받는다던지)은 반드시 필요하겠다.
'Web,Mobile > Tech' 카테고리의 다른 글
eval()과 Function 생성자의 Scope (0) | 2024.01.12 |
---|---|
JSFuck과 Function 객체 생성자를 이용한 XSS Bypass (0) | 2023.07.19 |
XSS Bypass in window.location (0) | 2022.05.03 |
Log4shell(CVE-2021-44228) + JNDI Injection (0) | 2021.12.17 |
Unicode upper/lower Trick (0) | 2019.04.08 |