<시작하며..>
(2011-2012) 작년 연말/올해 연초 부터 hash dos 공격에 대한 보안 취약성에 대한 얘기가 있었다. 관련 내용을 정리해서 올려본다.
<시작>
12월 29일 한 통의 메일을 톰캣 리더 개발자인 Mark Thomas로부터 메일을 받았다. dos 공격을 당할 수 있는 내용에 대해서 oracle은 패치를 하지 않을 것이고, tomcat은 maxParameterCount의 값을 디폴트로 10000개로 지정하는 패치를 내어놓겠다고 했다. 톰캣 5 는 더이상 패치하겠다고 발표한 생태였지만, 패치를 하겠다고 얘기가 있었다.
[SECURITY] Apache Tomcat and the hashtable collision DoS vulnerability11-12-29 (목) 07:28
You may have read about a recently announced vulnerability rooted in the |
자세한 정보는 메일의 아래 문서에서 확인할 수 있다. http://www.nruns.com/_downloads/advisory28122011.pdf
<간략하게 소개하는 취약점과 테스트 자료>
대부분의 언어에서는 Hash table을 많이 사용하고 있다. 특히 웹 서비스의 경우는 hash table로 데이터를 매핑해서 쓴다. 특히 post 방식일 때는 hash table을 파라미터 값으로 자동으로 매핑한다. get 방식일 때는 파라미터의 길이에 대해서 이미 브라우져단/서버단에서 기본적으로 제한을 가져서 문제가 없다. 그러나 post 방식일 때는 파라미터 개수 제한이 없다. (물론 서버 설정에서 이를 설정상으로 막을 수 있다.)
이를 악용하여 공격자가 조작된 값(colliding keys)을 파라미터로 전달하여 cpu 를 소진시킬 수 있다. hash contension이 일어나도록 동일한 string key값을 보내서 서버에 부담을 준다. (multi-collisions)
또는 randomized hash function이 없는 경우에도 활용될 수 있다.
hash table의 약점을 노린 것으로 hash table에 파라미터 입력시 O(n**2)으로 complexity가 높아지면서 cpu를 소진시켜 서버가 서비스를 못하게 한다. 하나의 요청만으로 웹 서버의 서비스를 못하게 할 수 있다.
hashtable에 존재하는 값과 입력된 값이 다를 경우 충돌이 일어나고, 그 충돌되는 값이 많아지면서 해당 값들을 계속 비교하는 경우를 multi-collision이라고 한다.
You tube에는 이런 취약점을 이용해서 간단하게 테스트한 자료가 있다.
<
<자바 패치 >
2003년부터 이 부분이 알려져 있다. Rice 대학의 Crosby, Wallach 가 발표한 논문에 비슷한 논문이 있다.
http://www.cs.rice.edu/~scrosby/hash/CrosbyWallach_UsenixSec2003.pdf
Perl와 CRuby는 고쳐졌지만 php 4/5, V8, 자바, asp.net, Python, Ruby에 보안 취약이 있었다.
자바의 경우는 String.hasCode() 메서드를 이용한 HashMap, HashTable 클래스를 사용하고 있다. DJBX33A 알고리즘을 사용하는데. 이슈가 있다. 2011년 11월 1일 레드햇 버그질라에 이 문제에 대한 이슈가 올라왔었지만, 오라클은 이 부분에 대해서 자바 hashmap 구현을 바꾸지 않겠다고 했다. 즉 자바 언어의 hash 구현의 이슈가 아니라고 답변하였고 웹 서버(tomcat, jbossweb, flassfish)에서 처리되는 것으로 되었다. (개인적인 의견으로는 참 애매한 이슈인 것 같다. 원래 그렇게 최악의 상황을 감안하고 구현되었을 수도 있고, 이거 고쳐서 backward compatibility를 잃어버리는 것보다는 나을 수 있다는 생각도 든다. 굳이 고쳐서 탈나는 것보다는 이게 나을 수도 ^^;;;)
https://bugzilla.redhat.com/show_bug.cgi?id=750533
그래서 12월 29일 close가 되었고, tomcat 리더 개발자인 mark tomas는 메일을 보낸 것이었다.
<톰캣 패치>
6.0.35, 7.0.23이 바로 패치되었고, 5.5.35는 늦게 패치가 되었다.
위에서 얘기한 Connector의 필드값으로 maxParameterCount 개수를 지정하면 문제를 해결하면 된다.
http://tomcat.apache.org/tomcat-6.0-doc/config/ajp.html
패치 할 수 없는 상황에서는 maxPostSize 를 이용할 수도 있다.
핵심 코드가 바뀌었는지 간단히 살펴본다.
http://www.mail-archive.com/dev@tomcat.apache.org/msg57020.html
Connector.java
maxParameterCount 파라미터를 읽는다.
tomcat/trunk/java/org/apache/catalina/connector/Connector.java /** + /** + * Return the maximum number of parameters (GET plus POST) that will be + * automatically parsed by the container. A value of less than 0 means no + * limit. + */ + public int getMaxParameterCount() { + return maxParameterCount; + } + + + /** + * Set the maximum number of parameters (GET plus POST) that will be + * automatically parsed by the container. A value of less than 0 means no + * limit. + * + * @param maxParameterCount The new setting + */ + public void setMaxParameterCount(int maxParameterCount) { + this.maxParameterCount = maxParameterCount; + } |
tomcat/trunk/java/org/apache/tomcat/util/http/Parameters.java
기존에는 간단하게 Hashtable<String,String[]>의 값을 저장했지만, 새로 바뀐 버전에는 Hashtable<String,ArrayList<String>> 타입으로 바꾸었다.
- private final Hashtable<String,String[]> paramHashStringArray = ==> + private final Hashtable<String,ArrayList<String>> paramHashValues = |
구버전까지는 key값에 대한 value값을 array list로 해서 계속 추가되는 형태이다. 반면 신버전에서는 Capacity의 크기를 체크한 후 값을 저장하는 코드로 바뀌었다. 이 값은
- String values[]; ==> + ArrayList<String> values; |
<아파치 해결>
LimitRequestBody 값으로 개수를 지정한다. 디폴트값은 1000000(백만)이라서 조절이 필요할 수 있다.
http://httpd.apache.org/docs/2.0/mod/core.html
<Directory "/home/www/web"> LimitRequestBody 102400 </Directory>
* 참고 사항
이 메일의 배경은 12월 28일 독일에서 열린 Chaos Communication Congress의 Julian zeri Walde가 발표로 인해서 알려졌다. 자세한 내용은 아래와 같다. 원리에 대한 설명이 있다.
간단하게 이 자료를 소개하면서 자바의 소스를 분석해본다.
일반적으로 hash table은 O(n) 방식으로 내용을 검색하거나 추가할 수 있다.
그러나 하나의 키에 계속 값이 붙는 screwed 상황이 일어날 수 있다. 이 때는 O(n**2)가 되어서 속도가 저하되는 이슈가 있다.
만약 10bytes 짜리 20만개를 최악의 케이스로 넣는 다면, 40,000,000,000 번의 string 비교가 일어나고 40초가 걸릴 수 있다. (참고로 String intern, String compare는 비싼 자원이다..)
자바의 내부는 String hash값은 어떻게 되어 있을까?
public final class String /** Cache the hash code for the string */ /** for (int i = 0; i < len; i++) { } |
결국 hash code 공식은 다음 공식을 따른다.
hash code = s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
위키에 좀더 멋진 공식 표현이 있다. (http://en.wikipedia.org/wiki/Java_hashCode())
멋진 공식이라 하더라도. hash value는 int 라는 제한적인 값(min<int<max) 범위에 있기 때문에 중복될 수 있다. 또한 아래와 같이 동일한 hashcode를 생성할 수 있다. 이런 것을 악용한다면, 웹 서버들을 장애를 일으킬 수 있을 것이다.
public class a1 { #결과 |
생각해보면, hashcode는 unique한 값이 아닌 적당하게 써서 관리하기 위한 목표를 가지고 있다. 취약점을 어쩔 수 없으니. 적당하게 크기 제한하는 것이 좋은 사례인 것 같다..
PS
2012년 1월 17일 Mark Tomas는 정식으로 메일을 보냈다.
http://mail-archives.apache.org/mod_mbox/tomcat-announce/201201.mbox/%3C4F155CE2.3060301%40apache.org%3E
CVE-2012-0022 Apache Tomcat Denial of Service Severity: Important Vendor: The Apache Software Foundation Versions Affected: - Tomcat 7.0.0 to 7.0.22 - Tomcat 6.0.0 to 6.0.33 - Tomcat 5.5.0 to 5.5.34 - Earlier, unsupported versions may also be affected Description: Analysis of the recent hash collision vulnerability identified unrelated inefficiencies with Apache Tomcat's handling of large numbers of parameters and parameter values. These inefficiencies could allow an attacker, via a specially crafted request, to cause large amounts of CPU to be used which in turn could create a denial of service. The issue was addressed by modifying the Tomcat parameter handling code to efficiently process large numbers of parameters and parameter values. Mitigation: Users of affected versions should apply one of the following mitigations: - Tomcat 7.0.x users should upgrade to 7.0.23 or later - Tomcat 6.0.x users should upgrade to 6.0.35 or later - Tomcat 5.5.x users should upgrade to 5.5.35 or later Credit: The inefficiencies in handling large numbers of parameters were identified by the Apache Tomcat security team. References: http://tomcat.apache.org/security.html http://tomcat.apache.org/security-7.html http://tomcat.apache.org/security-6.html http://tomcat.apache.org/security-5.html
'Web service' 카테고리의 다른 글
Apache Http 서버의 ListenBackLog 지시자 (0) | 2012.01.17 |
---|---|
Https 서버를 개발환경에 구축 & 10년짜리 사실 인증서 만들기 & 적용 (0) | 2012.01.17 |
2012년 초 Webwork / struts2 보안 이슈 (0) | 2012.01.16 |
카산드라(Cassandra)가 ivy에서 maven으로 바꾼 이유 (0) | 2011.12.15 |
Webwork(Strust2), OGNL, Sitemesh (0) | 2011.12.13 |