关联漏洞
介绍
- [CVE-2017-9822](#cve-2017-9822)
- [Thông tin chính](#thông-tin-chính)
- [Setup environment](#setup-environment)
- [Setup debug](#setup-debug)
- [Phân tích](#phân-tích)
- [Debug](#debug)
- [XmlSerializer](#xmlserializer)
- [Gadget tấn công](#gadget-tấn-công)
- [ObjectDataProvider](#objectdataprovider)
- [ResourceDictionary](#resourcedictionary)
- [Từ xml insecure deserialization to RCE](#từ-xml-insecure-deserialization-to-rce)
# CVE-2017-9822
DNN (hay còn gọi là DotNetNuke) trước phiên bản 9.1.1 có khả năng thực thi mã từ xa thông qua cookie, hay còn gọi là "2017-08 (Quan trọng) Có thể thực thi mã từ xa trên các trang web DNN".
## Thông tin chính
- Sản phẩm ảnh hưởng: DotNetNuke (DNN Platform) – một CMS/portal .NET phổ biến.
- Ngày công bố: Tháng 7/2017.
- Mức độ: Critical (CVSS ~9.8).
- Loại lỗ hổng: XML External Entity (XXE) / Insecure Deserialization → Remote Code Execution (RCE).
- Ảnh hưởng: trước phiên bản 9.1.1 có khả năng thực thi mã từ xa thông qua cookie

**DotNetNuke là gì?**
DotNetNuke là một CMS (hệ thống quản lý nội dung) web miễn phí và mã nguồn mở được viết bằng C# và dựa trên nền tảng .NET. DotNetNuke rất phổ biến và được sử dụng rộng rãi trên Internet vì bạn có thể triển khai một phiên bản web DNN chỉ trong vài phút mà không cần nhiều kiến thức kỹ thuật. Một chức năng quan trọng khác của DotNetNuke là khả năng tạo hoặc nhập các module tùy chỉnh của bên thứ ba được xây dựng bằng VB.NET hoặc C#
Có thể cài đặt DNN trên một ngăn xếp bao gồm Windows Server, IIS, ASP.NET và SQL Server cho Windows. DNN cũng hỗ trợ đăng ký xác minh người dùng mới qua email, nhưng bạn cần cấu hình máy chủ SMTP hợp lệ để tính năng bảo mật này hoạt động.
Các tính năng chính của DNN
• ***Kiến trúc modular:*** DNN cho phép mở rộng dễ dàng bằng cách cài thêm các module (mô-đun chức năng) do cộng đồng phát triển. Người quản trị có thể tải module mới qua giao diện admin (upload gói .zip) hoặc giải nén trực tiếp vào thư mục trên máy chủ.
• ***Quản trị người dùng:*** Hệ thống cung cấp chức năng bảo mật và phân quyền chi tiết (roles/permissions) cho các portal và module. Tài khoản người dùng, vai trò và quyền hạn được quản lý tập trung trong DNN.
• ***Quản lý nội dung:*** Hỗ trợ soạn thảo WYSIWYG, quản lý bài viết, hình ảnh, tài liệu… Có hệ thống workflow/xuất bản (đăng bài theo quy trình duyệt xét) và phiên bản hóa nội dung. Nội dung được lưu trữ trên cơ sở dữ liệu (SQL Server) chung.
• ***API và tích hợp mở rộng:*** DNN cung cấp API .NET cho lập trình viên phát triển module tùy chỉnh (WebForms, MVC, Razor) và tích hợp các dịch vụ bên ngoài. Hàng loạt thư viện bên thứ ba có sẵn (chủ đề giao diện, module thương mại điện tử, diễn đàn, v.v.) cho phép mở rộng chức năng.
• ***Giao diện và chủ đề:*** Hệ thống skins (chủ đề) tách biệt nội dung – giao diện cho phép thiết kế web linh hoạt. Các trang web do DNN tạo ra có thể thay đổi giao diện bằng cách đổi skins.
• ***Cơ chế cài module:*** Các module của DNN được đóng gói trong tệp ZIP, có thể cài đặt qua giao diện quản trị hoặc bằng cách giải nén thủ công. DNN hỗ trợ cả module đã biên dịch (.NET DLL) và module Razor động; mọi module đều có thể cấp phép hoặc thu hồi truy cập thông qua cài đặt phân quyền trên từng trang .
## Setup environment
**Operating Systems:** Windows 10
**.NET Framework:** 4.5.1+
**Web Server:** Microsoft IIS 10
**Database Server:** Microsoft® SQL Server® 2019 Express, SQL Server Management Studio
Dotnetnuke version 9.1.0
Có thể sử dụng Google dorks sau đây để tìm các phiên bản Dotnetnuke triển khai khả dụng trên Internet và kiểm tra chúng dựa trên [website](https://www.cvedetails.com/cve/CVE-2017-9822/):
inurl:dnn.js
inurl:dnn.modalpopup.js
inurl:dnn.servicesframework.js
inurl:dnn.xml.js
inurl:dnncore.js
inurl:/Portals/0/
inurl:/DesktopModules/
inurl:/DNNCorp/
inurl:/DotNetNuke
inurl:/tabid/*/Default.aspx
inurl:/tabid/*/language/*/Default.aspx
intext:"by DNN Corp "
Có thể follow theo bài viết này để build môi trường [](https://www.digitalalphas.com/how-to-install-dotnetnuke-dnn/)
## Setup debug
Chỉnh lại thuộc tính của assembly về các thuộc tính "có thể debug", điều này là rất cần thiết bởi vì trong runtime, một số tối ưu hóa sẽ được áp dụng và vô tình gây cản trở chúng ta trong việc debug, vài breakpoint có thể không được hit hoặc vài biến sẽ không tồn tại.
Load DotNetNuke.dll vào dnSpy (32 bit) sau đó chọn Edit Assembly Attributes (C#)

Thay đổi dòng từ
`[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]`
Thành
`[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default |
DebuggableAttribute.DebuggingModes.DisableOptimizations |
DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints |
DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]`

Sau đó chọn Compile và Save module này vào lại vị trí cũ.
Tiếp theo, khởi chạy dnSpy với quyền admin và chọn Debug -> Attach to Process

Chọn process w3wp.exe

Lí do ta phải attach process này để bug là bởi vì các ứng dụng web trên IIS thường sử dụng worker process. Chúng có nhiệm vụ xử lí các web requests gửi đến IIS web server cho mỗi application pool, các worker process có thể có nhiều trên một máy và đều có chung tên gọi là w3wp.exe. Một lưu ý nhỏ đó là sẽ có lúc không có process w3wp nào đang chạy, IIS sẽ không start các worker process cho đến khi nhận được web request đầu tiên.

Quay trở lại với việc debug, sau khi attach process tiếp theo chọn: Debug -> Windows -> Modules

Click vào một module và chọn Open All Modules

Lúc này ở cửa sổ Assembly ta đã có thể thấy được tất cả các module liên quan

## Phân tích
Deserialization là quá trình diễn giải các luồng byte và chuyển đổi chúng thành dữ liệu có thể được ứng dụng thực thi.
Vấn đề chính với việc Deserialization là hầu hết thời gian nó có thể sử dụng dữ liệu đầu vào của người dùng. Điều này có nghĩa là bạn có thể chèn các payload độc hại vào định dạng được yêu cầu của ứng dụng và có thể thao túng logic, tiết lộ dữ liệu hoặc thậm chí thực thi mã từ xa.
DotNetNuke sử dụng cookie DNNPersonalization để lưu trữ các tùy chọn cá nhân hóa của người dùng ẩn danh (các tùy chọn dành cho người dùng đã xác thực được lưu trữ thông qua trang hồ sơ của họ). Như report, lỗ hổng xảy ra ở phần xử lý DNNPersonalization cookie, cookie này được dùng để load user profile tuy nhiên vẫn có thể trigger unauthen khi truy cập một trang không tồn tại(404 error). Entrypoint của bug này nằm ở hàm LoadProfile thuộc module DotNetNuke.dll, ta sẽ decompile module này bằng dnSpy và phân tích kĩ hơn:
Tại PersonalizationController#LoadProfile(int, int)

Nếu userId khác null thì biến text sẽ được gán giá trị của DNNPersonalization cookie từ request sau đó gọi đến Globals#DeserializeHashTableXml

Globals#DeserializeHashTableXml gọi đến XmlUtils#DeSerializeHashtable

**Quy trình xử lý như sau:**
- LoadXml từ xmlSource
- Duyệt qua từng node item trong root profile.
- Với mỗi item, lấy object type được định nghĩa dựa vào attribute type và khởi tạo XmlSerializer theo type object đó như dòng 160-161
- Deserialize item này thành một object ở dòng 163 và lưu vào hashtable
- Trả về hashtable
Ta hoàn toàn có thể kiểm soát giá trị DNNPersonalization cookie do đó có thể sửa đổi object được deserialize.
## Debug
Dùng burp để send request trigger 404 status + cookie DNNPersonalization

Ở đây có thể thấy hàm gọi để xử lí 404 là Handler404OrException đã trigger một chall chain và gọi đến Personalization.LoadProfile(int,int).

Điều đáng chú trong đoạn code trên có điều kiện if kiểm tra xem request hiện tại đã là IsAuthenticated hay chưa và rõ ràng request ta vừa thực hiện là unauthenticated đến một entrypoint không tồn tại. Vậy tại sao request hiện tại được thực hiện như một authenticated user.
Tiếp tục debug, lùi về gần cuối stack thì thấy tại AdvancedUrlRewriter#Handle404OrException có vòng else if như sau:

Ở đây nó sẽ kiểm tra request context.User hiện tại có là null, nếu đúng như vậy sẽ gán context.User là user thread hiện tại, set breakpoint có thể thấy được kết quả như sau:

Biến IsAuthenticated bây giờ có giá trị là true và user được gán chính là user chạy thread hiện tại thuộc nhóm IIS APPPOOL của IIS server do đó request được thực hiện như một authenticated user. Lý do logic này tồn tại là bởi 404 handler được invoke trước khi HttpContext.User được set và luồng xử lý tiếp dựa vào User.IsAuthenticated nên để tránh bị lỗi Null references, developers gán User object bằng WindowsPrinicipal object của thread hiện tại.
### XmlSerializer
XmlSerializer là lớp serialize của riêng Microsoft, được sử dụng để chuyển đổi giữa các chuỗi và đối tượng xml. Namespace của nó là: System.Xml.Serialization.
Ví dụ sử dụng XmlSerializer:


Điều kiện tấn công RCE thông qua XmlSerializer là bắt buộc phải điều khiển được kiểu dữ liệu truyền vào constructor của XmlSerializer. Tức là các kiểu dữ liệu dẫn đến gadget phải được truyền vào thuộc tính XmlSerializer.mapping
### Gadget tấn công
Gadget phổ biến nhất để tấn công xml deserialize là ObjectDataProvider. Gadget này có thể được tạo bởi công cụ ysoserrial .net
### ObjectDataProvider
Về cơ bản khi sử dụng lớp này, ta có thể gọi đến bất kì method nào của bất kì lớp nào.

Ví dụ chúng ta có thể gọi đến Process.Start với các tham số được truyền vào như dưới đây:
`ObjectDataProvider o = new ObjectDataProvider();
o.MethodParameters.Add("cmd.exe");
o.MethodParameters.Add("/c calc");
o.MethodName = "Start";
o.ObjectInstance = new Process();
Console.ReadKey();`
Xây dựng 1 payload xml deserialize với đoạn code trên:


### ResourceDictionary
ResourceDictionary dùng để phát triển wpf, vì là wpf nên nó phải sử dụng ngôn ngữ xaml. Trước tiên chúng ta hãy xem một payload sử dụng ResourceDictionary để thực thi các lệnh.
`<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:b="clr-namespace:System;assembly=mscorlib"
xmlns:c="clr-namespace:System.Diagnostics;assembly=system">
<ObjectDataProvider d:Key="" ObjectType="{d:Type c:Process}" MethodName="Start">
<ObjectDataProvider.MethodParameters>
<b:String>cmd</b:String>
<b:String>/c calc</b:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</ResourceDictionary>`
Giải thích xaml này:
1. xmlns:c đề cập đến namespace System.Diagnostics và đặt tên là c
2. d:Key="" tên rỗng. Trong cú pháp xaml, giá trị khóa Key phải có.
3. ObjectType đại diện cho loại đối tượng
4. d:Type tương đương với typeof()
5. MethodName là một thuộc tính của ObjectDataProvider. Việc truyền vào Start tương đương với việc gọi phương thức Start.
6. c:Process tương đương với System.Diagnostics.Process
Sau khi toàn bộ xaml được phân tích cú pháp, nó tương đương với việc tạo một đối tượng ObjectDataProvider, đối tượng này sẽ tự động gọi System.Diagnostics.Process.Start("cmd.exe","/c calc")

Việc thực thi đoạn code trên tương đương với việc ObjectDataProvider -> Person.Evil(). Nếu thực hiện tấn công RCE thông qua XmlSerializer thì flow trông sẽ như thế này ObjectDataProvider -> XamlReader.Parse() -> ObjectDataProvider -> System.Diagnostics.Process.Start("cmd.exe","/c calc")
### Từ xml insecure deserialization to RCE
Mục tiêu bây giờ là cần tìm object có thể execute code khi thực hiện deserialize. Trong POC, hàm PullFile của DotNetNuke.Common.Utilities.FileSystemUtils được sử dụng để khai thác "arbitrary file upload"


Ta được obj.xml:

Send payload


Sau khi DNN deserialize cookies, tại http server có request đến /cmd.aspx tức deser thành công, webshell đã được upload lên DN

Tương tự lợi dụng hàm WriteFile của DotNetNuke.Common.Utilities.FileSystemUtils để đọc file


文件快照
[4.0K] /data/pocs/179c46ad7bf6a5dbcaa75e0b9baf010b5b6a3f04
├── [4.0K] images
│ ├── [109K] Picture10.png
│ ├── [ 42K] Picture11.png
│ ├── [121K] Picture12.png
│ ├── [233K] Picture13.png
│ ├── [ 66K] Picture14.png
│ ├── [233K] Picture15.png
│ ├── [174K] Picture16.png
│ ├── [154K] Picture17.png
│ ├── [ 28K] Picture18.png
│ ├── [ 39K] Picture19.png
│ ├── [ 70K] Picture1.png
│ ├── [156K] Picture20.png
│ ├── [ 69K] Picture21.png
│ ├── [ 82K] Picture22.png
│ ├── [ 70K] Picture23.png
│ ├── [130K] Picture24.png
│ ├── [ 66K] Picture25.png
│ ├── [190K] Picture26.png
│ ├── [ 66K] Picture27.png
│ ├── [ 16K] Picture28.png
│ ├── [ 83K] Picture29.png
│ ├── [ 65K] Picture2.png
│ ├── [ 93K] Picture30.png
│ ├── [150K] Picture3.png
│ ├── [ 22K] Picture4.png
│ ├── [111K] Picture5.png
│ ├── [107K] Picture6.png
│ ├── [ 60K] Picture7.png
│ ├── [ 53K] Picture8.png
│ └── [126K] Picture9.png
└── [ 15K] README.md
1 directory, 31 files
备注
1. 建议优先通过来源进行访问。
2. 如果因为来源失效或无法访问,请发送邮箱到 f.jinxu#gmail.com 索取本地快照(把 # 换成 @)。
3. 神龙已为您对POC代码进行快照,为了长期维护,请考虑为本地POC付费,感谢您的支持。