-
[Portswigger Top 10 web hacking techniques of 2021] - 10 Fuzzing for XSS via netsted parsers 리뷰Web Vulnerability 2022. 3. 7. 02:19
Refer :
Portswigger Top 10 web hacking techniques of 2021
https://swarm.ptsecurity.com/fuzzing-for-xss-via-nested-parsers-condition/
2022년 2월 9일에 burp suite를 개발한 portswigger에서 정리한 2021년도 web hacking 기술 top 10 글이 올라오게 되었다.
봐야겠다는 생각만 하고 실제로 보지는 않아서 이번 기회에서 top 10 기술을 하나씩 공부해보며 흥미있었던 점을 중심으로 리뷰를 적어보려고 한다.
Fuzzing for Xss via netsted parsers 는 top 10에 선정된 취약점으로
각각의 parser 자체는 안전하다고 하더라도 , parser가 함께 적용되었을 때 예상치 못하게 XSS가 발생할 수 있다는 내용이 핵심이다.
보고서에 나온 것처럼
1. parser가 무엇인지
2. 취약한 parser 코드 사례
3. 취약점을 찾는 방법
4. 패치방법
에 관해서 간단하게 얘기해보면 좋을 것 같다.
1. paserer란?
parsing은 입력값을 특정 문법(규칙)에 따라서 해석하는 행위
*이번의 경우 텍스트를 => html으로 변환하는 것을 의미한다.parser는 parsing을 해주는 어플리케이션이라고 생각하면 될 것 같다.
2. 취약한 parser 코드 사례
https://swarm.ptsecurity.com/fuzzing-for-xss-via-nested-parsers-condition/
에서 예제코드를 확인 할 수 있는데
직접 php 환경을 구성해서 테스트 해보면 좋겠지만 , 아래 두 웹 사이트에서도 간단하게 테스트 해볼 수 있다.
https://extendsclass.com/php.html
이중 extendsclass 를 활용해서 테스트를 해보았다.
request로의 입력은 받을 수 없기에, $msg 변수에 테스트 해볼 payload를 넣어서 php 코드를 간단히 수정하였다. 오른쪽 상단의 Run을 누르면 php 코드를 간단히 실행 시킬 수 있다.
실제 마우스 코드를 result에 가져다 보면 xss가 발생하는 것을 확인 할 수 있는데
오른쪽에서
<a href="http://google.com/<a href=" mailto:user@gmail.com?subject="qwe" onmouseover="alert(1)" "="">http://google.com/user@gmail.com?subject='qwe'onmouseover='alert(1)'</a>">user@gmail.com?subject='qwe'onmouseover='alert(1)'">http://google.com/user@gmail.com?subject='qwe'onmouseover='alert(1)'
<a href="http://google.com/<a href=" mailto:user@gmail.com?subject="qwe" onmouseover="alert(1)" "="">http://google.com/user@gmail.com?subject='qwe'onmouseover='alert(1)'</a>">user@gmail.com?subject='qwe'onmouseover='alert(1)'">http://google.com/user@gmail.com?subject='qwe'onmouseover='alert(1)'
변환과정은 간단히 생각해보면 다음과 같다.
[INPUT]은 이번 게시물에서는 편의상 입력값 중 정규식에 걸리는 부분이라고 생각하면 좋을 것 같다.
#parser1 $input = preg_replace('/(http|https|files):\/\/[^\s]*/', '<a href="${0}">${0}</a>', $input);
parser1는 주소를 입력받으면
https://www.google.com => <a href="[INPUT]"> [INPUT] </a> 로 변환#parser2 $input = preg_replace('/([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)(\?\w*=[^\s]*|)/', '<a href="mailto:${0}">${0}</a>', $input);
parser2는 문제구성을 위해 조작한것 같지만
ex) test@gmail.com?아무거나1=아무거나2 => <a href="malito:[INPUT]">[INPUT]</a>로 바뀐다고 생각하면 될 것 같다. pre_replace안에 있는 구문은 정규식이니 , 정규식에 익숙하지 않다면 따로 검색해보는것도 좋을 것 같다!
간단히만 짚어보자면
( ) : 그룹 => 결과가 나오면 결과[0] , 결과[1] 이런식으로 인덱스로 참고 할 수 있다.
[ ] : [ ]안에 나열되는 문자열중 하나에 해당되기만 하면 된다. ex) [a-z] 는 알파벳 a,b,c,...z 중 하나이면 된다.
* : * 앞에 있는 부분이 0번 이상 반복
+ : + 앞에 있는 부분이 1번 이상 반복
\w : 문자 한글자
\s : 공백류 (공백, 줄 바꿈 , 탭 등등) http://www.w3bai.com/ko/jsref/jsref_regexp_whitespace.html
조합해보면 \w* 이면 문자가 0번 이상 반복되면 정규식에 걸린다.
http://google.com/user@gmail.com?subject='qwe'onmouseover='alert(1)' => 첫번째 파서에 의해서 1.<a href="http://google.com/user@gmail.com?subject='qwe'onmouseover='alert(1)'">http://google.com/user@gmail.com?subject='qwe'onmouseover='alert(1)'</a> 로 변환 이어서 2번째 parser에서는 user@gmail.com?subject='qwe'onmouseover='alert(1)'">http://google.com/user@gmail.com?subject='qwe'onmouseover='alert(1)'</a> 가 정규식에 걸리기 떄문에 해당 부분이 <a href="malito:user@gmail.com?subject='qwe'onmouseover='alert(1)'">http://google.com/user@gmail.com?subject='qwe'onmouseover='alert(1)'</a>">user@gmail.com?subject='qwe'onmouseover='alert(1)'">http://google.com/user@gmail.com?subject='qwe'onmouseover='alert(1)'</a></a> 로 바뀌어야 되기때문에 변환된 값을 1. 에 다시 대입하면 <a href="http://google.com/<a href="malito:user@gmail.com?subject='qwe'onmouseover='alert(1)'">http://google.com/user@gmail.com?subject='qwe'onmouseover='alert(1)'</a>">user@gmail.com?subject='qwe'onmouseover='alert(1)'">http://google.com/user@gmail.com?subject='qwe'onmouseover='alert(1)'</a></a>
php 코드 실행 결과 : <a href="http://google.com/<a href=" mailto:user@gmail.com?subject="qwe" onmouseover="alert(1)" "="">http://google.com/user@gmail.com?subject='qwe'onmouseover='alert(1)'</a>">user@gmail.com?subject='qwe'onmouseover='alert(1)'">http://google.com/user@gmail.com?subject='qwe'onmouseover='alert(1)' 직접 해본 결과 : <a href="http://google.com/<a href="malito:user@gmail.com?subject='qwe'onmouseover='alert(1)'">http://google.com/user@gmail.com?subject='qwe'onmouseover='alert(1)'</a>">user@gmail.com?subject='qwe'onmouseover='alert(1)'">http://google.com/user@gmail.com?subject='qwe'onmouseover='alert(1)'</a></a>
실행결과와 직접 해본 결과가 다른 걸 볼 수 있을 텐데
이는 브라우저 단에서 아래와 같은 경우 재해석이 일어났기 때문이다.
열린태그없이 닫힌 태그만 있으면 그냥 제거 , < , > 가 태그로 완벽하게 들어가지 않고 따로 들어가게 되면 < >로 자동 치환 , html 태그에서 attribute를 ' '로 감싸준다면 싱글 쿼터를(') 더블쿼터(")로 자동변환 php 실행결과 기준으로 읽어보면
<a href="http://google.com/<a href=" mailto:user@gmail.com?subject="qwe" onmouseover="alert(1)"
에서 메일 형태 때문에 들어갔던 <a href=" 가 <a href=" 로 시작하는 " 를 닫아줌으로써 html attribute를 탈출하여
onmouseover가 attribute로 들어가게 되서 xss가 실행됐었던 것이다.
xss를 공부해봤다면 알겠지만 html attribute에서 " 로 문자열이 시작하게 되면 attribute를 탈출하기 위해서는 반드시 " 로 탈출해야 되는데 , php 코드에서 htmlspeicalchars(https://www.php.net/manual/en/function.htmlspecialchars.php) 를 통해서 " 를 html entity인 "로 치환하기 때문에 탈출이 불가능하다...
하지만 parser 1과 , parser2가 차례로 적용되면서 , parser2의 " 가 들어가게 되면서 html 태그가 깨지고 xss가 발현됐다.
*payload에 '가 들어가는데 이건 왜 필터링이 처음에 안되었는지 궁금했는데
문서를 찾아보니 ' 의 경우 php htmlspecialchars에서 기본으로 ' 로 치환하지 않고
ENT_QUOTES 옵션이 set 될때만 적용이 된다고 한다.
3. 취약점을 찾는 방법
이외에도 markup langage , 이외 html 로 변환해주는 여러 parser들이 존재하고 보고서를 올린 작성자는
간단하게 퍼징을 통해 많은 취약점을 실제로 찾았었는데
방법은 간단했다.
일단 변환이 되는 형태를 모은 후
각자리에 서로 번갈아 가면서 대입을 해서 payload를 구성하고
취약점이 발현됐는지 유무는 실제 웹페이지를 보면서 태그가 깨진 것을 확인하거나
arachni에서도 실제 취약점을 검증할때 썼던 방식인데 , payload를 날린 후에
필터링에 걸린다면 < , > 가 사라지거나 < > 등으로 치환되서 response body에 포함되어 오기 때문에
request로 날렸던 payload의 < , > 가 response body에 살아있는지 확인하는 방식으로 취약점을 확인 할 수 있다.
4. 패치방법
패치방법은 간단했다.
물론 sanitizer를 parser마다 한번씩 더 넣거나 , 제일 마지막에 검증하는 방법도 쓰일 수 있다고 생각되지만
보고서에서 제안한 방식은 attribute에 들어가는 값은 전부 html entity로 치환하자는 것이었다.
html entity ex) < > = 등등
을 적용하게 되면
브라우저에서는 html entity를 해석해서 보여주기 때문에 사용자가 보는데도 지장 없고
html 태그 attribute안에서 html entity 사용이 가능한데 " 의 html entity인 " 가 들어가게 되면
attribute도 탈출할수 없기 에 안전하고 , < . > 도 < > 로 바뀌면 태그로 쓰이는 문자로서 기능을 못하기에 안전하기 때문이다.
html entity로 변환하는 사이트는 인코딩 목적으로 많이 애용하는 사이트가 있는데https://dencode.com/ 을 이용하면 편하게 변환이 가능하다!
markup 이랑 markdown 을 아무 생각없이 혼용해서 쓰고 있었는데 ㅎㅎ
markup이 더 큰 범주이고 markdown은 markup언어중 하나였다.