Docs

strtoupper(<ſcript>)


해당 문서는 위의 트윗을 보고 추가적인 연구를 진행해 Theori 내부 세미나에서 발표한 결과물이다.(사장님 허락받고 올린다)

(%C4%B1)
는 LATIN SMALL LETTER DOTLESS I를,

(%E2%84%AA)
KELVIN SIGN을,

(%C5%BF)
는 LATIN SMALL LETTER LONG S를,

(%C4%B0)
는 LATIN CAPITAL LETTER I WITH DOT ABOVE 를 의미한다.

그런데 자바스크립트 환경에서 %C4%B1를 touppercase() 하면 == “I”가, %c5%bf를 touppercase()하면 == “S”가 되고,
%E2%84%AA 를 tolowercase() 하면 == “k”가, %c4%b0을 tolowercase()하면 == “i” 가 되는 현상이 발생한다는 것이 해당 트윗의 요지이다.

이미 CTF에서 출제된적이 있는 트릭이지만 제대로 정리된 문서가 없는 것 같아서, 연구를 진행해 보았다.

우선은 다른 언어에서 같은 트릭이 발생하는지 여부를 확인해 보았다.

유니코드 범위 내에서 for문 오지게 돌렸다ㅡㅡ;;

그 결과는 다음과 같다.

대체로 유니코드를 제대로 지원하는 언어에서 해당 트릭이 발생하는것을 알 수 있었다.
php의 경우에는 일반 strtolower(), strtoupper() 함수에서는 발생하지 않고, 멀티바이트를 따로 지원해주는 mb_strtolower(), mb_strtoupper() 함수를 사용해야 한다.

그러면 이 트릭을 어떻게 악용할 수 있을까?

2가지 방법이 있다.

1. WAF BYPASS

라는 간단한 프로그램을 만들고 서버에 WAF를 설치한 후 /?ID=<script>VAR=1</script>URI에 접속해보면 결과는 다음과 같다.

방화벽에 탐지당한것이다.

하지만 URI를 /?ID=<%C5%BFCRIPT>VAR=1</%C5%BFCRIPT> 와 같이 해준다면?

WAF가 보기에는 <%C5%BFCRIPT> 라는 생소한 문자열이 들어왔으니 패스시켜주지만 웹어플리케이션단에서는 “%C5%BF” 문자열이 mb_strtoupper() 함수를 거치며 일반 알파벳 “S” 로 바뀌어 WAF가 우회된다.

WAF의 경우에는 설치가 까다롭고 오래걸려 ModSecurity 한가지에 대해서만 테스트 해보았다.
결과는 아래와 같다.

일부 유니코드는 통과시키고 일부 유니코드는 필터하는 모습을 볼 수 있다.

방화벽마다 필터되지 않는 유니코드가 있을 수 있다.

2. BROWSER XSS FILTER BYPASS
브라우저 XSS 필터는 사용자를 위한 강력한 XSS 방어수단이다.

보통은 위와같은 정규식을 거쳐 유저인풋과 HTTP Response 값 간에 정규식에 매칭되는 패턴이 있으면 아래처럼 작동을 중지시킨다.

하지만 WAF의 경우와 마찬가지로 유저인풋 %c5%bf 와 HTTP Response 에서의 “S” 를 XSS 필터에서 같다고 검증할 수 있을까?

테스트해본 결과는 아래와 같다.

MS 계열의 브라우저에서만 필터가 되는것을 확인할 수 있다.

다만 테스트할 때 내 Edge 브라우저가 최신버전이 아니였는데, 최신버전의 Edge 브라우저에는 XSS 필터가 제거되었다.
(https://blogs.windows.com/windowsexperience/2018/07/25/announcing-windows-10-insider-preview-build-17723-and-build-18204/)

그러므로 사실상 IE를 제외하면 해당 트릭은 모든 브라우저 XSS 필터 우회에 악용할 수 있다.

python3, js, java 로 이루어진 웹어플리케이션 상에서 문자열을 대문자 혹은 소문자로 강제로 치환하는 경우에는 해당 트릭을 시도해볼 가치가 있을것이다.

7 Comments

    • root

      많은 해커들의 제보로 지금은 비교적 안전해진걸로 알고있습니다만은… 아직은 갈 길이 멀죠..ㅎㅎ

        • root

          저는 그누보드는 각잡고 뜯어본적이 없습니다.
          하지만 그누보드 사용하느니 차라리 워드프레스나 최소한 xe정도를 사용하시는걸 권장해요

  • 질문드립니다

    좋은정보 감사합니다!
    혹시 mb_strtolower()에 관한 트릭 또한 존재하는지 여쭤봐도 될까요?
    8바이트, 12바이트 데이터를 여러 방식의 인코딩을 사용하여 찾고있는데,
    도무지 임의의 데이터 -> s, c, r, i, p, t, j, a, v 로 대응되는 케이스가 나오질 않는군요 ㅠㅠ

    • rubiya

      자료를 본 적이 있는데 찾으려니 못찾겠네요@_@ 8~12바이트짜리 문자가 1바이트로 바뀌는 경우는 없지만 2~3바이트로 바뀌는 경우는 존재했습니다. 코드를 수정해보세요!

Leave a Reply

Your email address will not be published. Required fields are marked *