XXEと.NET Framework

# XXEと.NET Framework

## XXEとは

XXE(XML External Entity)とは、XMLの外部参照機能を利用して、サーバ内部のファイル内容を取得(漏えい)したり、内部ネットワーク上のファイルにアクセスしたりする不正行為

XXEは、XMLを扱うアプリケーションで発現する可能性があるので、XML文書を取り扱う際には注意する必要がある。

## .NET FrameworkとXML

.NET FrameworkでXMLを扱うには、[Sytem.Xml名前空間](https://docs.microsoft.com/ja-jp/dotnet/api/system.xml?view=netframework-4.7.2)を利用が考えられる。

よって、以降は、[System.Xml.XmlDocumentクラス](https://docs.microsoft.com/ja-jp/dotnet/api/system.xml.xmldocument?view=netframework-4.7.2)を使って、再現させたり、対策を考えてみたりしよう。

## 結論

手っ取り早くXXEを予防したければ、[System.Xml.XmlDocument#XmlResolver プロパティ](https://docs.microsoft.com/ja-jp/dotnet/api/system.xml.xmldocument.xmlresolver?view=netframework-4.7.2#System_Xml_XmlDocument_XmlResolver)を「**NULL**」にする。

## .NET FrameworkでXXEを発現させる

下記のソースコードのプログラムは、第一引数にXMLファイル、第二引数に外部参照の動作モードを指定するようになっているので、既定の動作モードで、XMLファイル([C:\z\xmlxxe\in1.xml](https://qiita.com/tomoki0sanaki/items/015b6e8b807ed256a6e4#xml%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB--in1xml))を読んでみる。

こんな感じ。

![xxe-cs-defo.png](https://qiita-image-store.s3.amazonaws.com/0/182822/6099a1bd-2b09-65d0-323b-4ebd6ddcdbf2.png)

.NET Framework の場合は、既定ではXXE攻撃を受けてしまうということになる。

## 外部参照のオブジェクトをNULLにする

次は[System.Xml.XmlDocument#XmlResolver プロパティ](https://docs.microsoft.com/ja-jp/dotnet/api/system.xml.xmldocument.xmlresolver?view=netframework-4.7.2#System_Xml_XmlDocument_XmlResolver)を「NULL」にしてみる

![xxe-cs-null.png](https://qiita-image-store.s3.amazonaws.com/0/182822/e967e576-2b9c-c66e-b9ac-fd392cc55db2.png)

つまり、手っ取り早くXXEを予防したければ、[System.Xml.XmlDocument#XmlResolver プロパティ](https://docs.microsoft.com/ja-jp/dotnet/api/system.xml.xmldocument.xmlresolver?view=netframework-4.7.2#System_Xml_XmlDocument_XmlResolver)を「**NULL**」にする。

## 外部参照のオブジェクトを自作する

次は「**外部参照機能を限定的に使いたいけど、XXEを防ぎたい**」という場合は、リゾルバを自作すればいい。

つまり、[System.Xml.XmlDocument#XmlResolver プロパティ](https://docs.microsoft.com/ja-jp/dotnet/api/system.xml.xmldocument.xmlresolver?view=netframework-4.7.2#System_Xml_XmlDocument_XmlResolver)は「[System.Xml.XmlResolver](https://docs.microsoft.com/ja-jp/dotnet/api/system.xml.xmlresolver?view=netframework-4.7.2)」型なので、それを継承したクラスを自作して、それを[System.Xml.XmlDocument#XmlResolver プロパティ](https://docs.microsoft.com/ja-jp/dotnet/api/system.xml.xmldocument.xmlresolver?view=netframework-4.7.2#System_Xml_XmlDocument_XmlResolver)に割り当てれば、外部参照を自由に制御する事ができる。

上書き必須のメソッドは、「[object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)](https://docs.microsoft.com/ja-jp/dotnet/api/system.xml.xmlresolver.getentity?view=netframework-4.7.2#System_Xml_XmlResolver_GetEntity_System_Uri_System_String_System_Type_)」メソッドだけ。
これの肝になる部分は、第一引数に外部参照のURLを示すUri型が来るので、それに応じた「[System.IO.Stream](https://docs.microsoft.com/ja-jp/dotnet/api/system.io.stream?view=netframework-4.7.2)」型を返せばいいだけ。

例えば、認証が必要だったり、特定のURIだけ許可したり、というような個別カスタマイズが可能。

ソースコードの「exXmlResolver.cs」の「exXmlResolverクラス」は、全ての[System.Uri](https://docs.microsoft.com/ja-jp/dotnet/api/system.uri?view=netframework-4.7.2)に対して、空の[System.IO.MemoryStrem](https://docs.microsoft.com/ja-jp/dotnet/api/system.io.memorystream?view=netframework-4.7.2)を返すだけとした。
これは、実質的に[System.Xml.XmlDocument#XmlResolver プロパティ](https://docs.microsoft.com/ja-jp/dotnet/api/system.xml.xmldocument.xmlresolver?view=netframework-4.7.2#System_Xml_XmlDocument_XmlResolver)を「NULL」にした時と同じような挙動になると思う。

こんな感じになる。

![xxe-cs-cust.png](https://qiita-image-store.s3.amazonaws.com/0/182822/d4309dcb-d13e-7816-ee3d-e599e910c506.png)

## 外部参照のオブジェクトを自作するための子クラス

.NET Frameworkの場合、[System.Xml.XmlResolver](https://docs.microsoft.com/ja-jp/dotnet/api/system.xml.xmlresolver?view=netframework-4.7.2)を直接継承しなくても、以下のクラスがあるので、自分の仕様に適合した既存クラスを使ってもよいだろう。

- .NET Framework [System.Xml.XmlSecureResolver](https://docs.microsoft.com/ja-jp/dotnet/api/system.xml.xmlsecureresolver?view=netframework-4.7.2)
- .NET Framework [System.Xml.XmlUrlResolver](https://docs.microsoft.com/ja-jp/dotnet/api/system.xml.xmlurlresolver?view=netframework-4.7.2)
- .NET Framework [System.Xml.XmlXapResolver](https://docs.microsoft.com/ja-jp/dotnet/api/system.xml.xmlxapresolver?view=netframework-4.7.2)
- .NET Framework [System.Xml.XmlPreloadedResolver](https://docs.microsoft.com/ja-jp/dotnet/api/system.xml.resolvers.xmlpreloadedresolver?view=netframework-4.7.2)

# ソースコード(Program.cs)

```csharp:Program.cs
using System;
using System.IO;
using System.Xml;

namespace XMLandXXEtest{
    class Program{
        static void Main(string[] args){
            Boolean Isresolve = true;
            exXmlResolver myExXmlResolver = null;
            if (1 < args.Length) {
                if (args[1].ToLower() == "null"){
                    Isresolve = false;
                }else {
                    myExXmlResolver = new exXmlResolver();
                }
            }
            if (0 == args.Length) {
                Console.WriteLine("usage: XMLandXXEtest.exe <<xmlFile>> [NotResolve]");
            }else{
                StreamReader sr = new StreamReader(new FileStream(args[0], FileMode.Open, FileAccess.Read));
                String str = sr.ReadToEnd();
                sr.Close();
                XmlDocument tempXmlDocument = new XmlDocument();
                if (Isresolve == false){
                    tempXmlDocument.XmlResolver = null;
                }else if (myExXmlResolver != null){
                    tempXmlDocument.XmlResolver = myExXmlResolver;
                }
                tempXmlDocument.LoadXml(str);
                Console.WriteLine("after XML Resolve is (OuterXml)");
                Console.WriteLine(tempXmlDocument.OuterXml);
                Console.WriteLine("----------------------------------");
                Console.WriteLine("after XML Resolve is (InnerXml)");
                Console.WriteLine(tempXmlDocument.InnerXml);
                Console.WriteLine("----------------------------------");
                Console.WriteLine("after XML Resolve is (InnerText)");
                Console.WriteLine(tempXmlDocument.InnerText);
                Console.WriteLine("----------Detail------------------");
                foreach (XmlNode x in tempXmlDocument.ChildNodes){
                    WroteXMLnode(x, "");
                }
            }
        }
        static void WroteXMLnode(XmlNode node, String spaceStr) {
            Console.WriteLine(spaceStr + "name=" + node.Name + ", type=" + node.NodeType.ToString());
            Console.WriteLine(spaceStr + "valT=" + node.InnerText);
            Console.WriteLine(spaceStr + "valX=" + node.InnerXml);
            if (node.HasChildNodes == true){
                foreach (XmlNode x in node.ChildNodes){
                    WroteXMLnode(x, spaceStr + " ");
                }
            }
        }
    }
}
```

# ソースコード(exXmlResolver.cs)

空の MemoryStream を返すだけのリゾルバ

```csharp:exXmlResolver.cs
using System;
using System.IO;
using System.Xml;

namespace XMLandXXEtest{
    public class exXmlResolver : XmlResolver{
        /// <summary>
        /// コンストラクタ
        /// </summary>
        public exXmlResolver() { }
        /// <summary>
        /// 唯一、実装する必要のあるメソッド
        /// </summary>
        /// <param name="absoluteUri"></param>
        /// <param name="role"></param>
        /// <param name="ofObjectToReturn"></param>
        /// <returns></returns>
        public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn){
            if (absoluteUri == null){
                Console.WriteLine("Uri: null");
            }else {
                Console.WriteLine("Uri: " + absoluteUri.ToString());
            }
            if (role == null) {
                Console.WriteLine("Role: null");
            }else if (role == String.Empty){
                Console.WriteLine("Role: ");
            }else{
                Console.WriteLine("Role: " + role);
            }
            if (ofObjectToReturn == null){
                Console.WriteLine("Type: null");
            }else{
                Console.WriteLine("Type: " + ofObjectToReturn.ToString());
            }
            MemoryStream mem = new MemoryStream();
            return mem;
        }
        /// <summary>
        /// 
        /// </summary>
        public override System.Net.ICredentials Credentials{
            set {  }
        }
    }
}
```

## 戻る

[XXE基本編へ戻る](https://qiita.com/tomoki0sanaki/items/015b6e8b807ed256a6e4)