Post

CVE-2021-34520 Microsoft Sharepoint RCE

Phân tích lỗi CVE-2021-34520

Sharepoint Workflow

Chúng ta có thể phân tách nghĩa của từ Workflow là làm 2 phần bao gồm “Work” nghĩa là công việc, “flow” nghĩa là dòng chảy. Flow đi chung với Work nghĩa là dòng chảy công việc, luồng công việc hay gọi là quy trình công việc. Workflow được hiểu là một quy trình lặp lại, bao gồm các nhiệm vụ cần phải hoàn thành theo một quy trình cụ thể.

image

Một workflow bao gồm một hoặc nhiều step, trong mỗi step lại chứa một hay nhiều activity (workflow action).

Trong Sharepoint có 2 kiểu workflow

  1. Built-in workflow: Đây là các workflow được xây dựng sẵn như template của sharepoint
  2. Custom workflow: Sharepoint cho phép xây dựng các workflow theo ý của người dùng. Có hai cách để tạo ra một custom workflow là sử dụng công cụ Sharepoint Designer hoặc tạo từ custom code sử dụng Visual Studio 2012 trở về sau.

Sử dụng workflow trong sharepoint?

Trước khi được sử dụng, các workflow sau khi được tạo sẽ được add cho một list, library hoặc content type để khiến nó khả dụng cho các documents hoặc items trong danh sách đấy. Sau đó, các workflow này có thể chạy theo các option như sau

  • Chạy thủ công
  • Chạy khi có thay đổi về item (thêm, xóa, sửa thông tin …)

Workflow Designer

SharePoint Designer 2013 là một chương trình thiết kế web và ứng dụng được sử dụng để xây dựng và tùy chỉnh các trang web và ứng dụng trên SharePoint. Sharepoint Designer giúp bạn tạo ra các trang web giàu dữ liệu, xây dựng các workflow mạnh mẽ, hay tạo ra các giao diện đẹp và dễ chịu cho trang web.

Mô tả về lỗi

Tài liệu của ZDI mô tả về CVE-2021-34520 như sau:

Lỗ hổng tồn tại trong lớp Microsoft.SharePoint.WorkflowActions.SetVariableActivity. Một thành phần SetVariableActivity được tạo thủ công có thể dẫn đến việc khởi tạo một kiểu .NET tùy ý. Attacker có thể lợi dụng lỗ hổng này để thực thi mã từ xa.

SetVariableActivity là một workflow action, vậy khả năng cao lỗ hổng này liên quan đến việc tạo và sử dụng workflow.

Diff code

Cài đặt bản lỗi của Sharepoint Enterprise Server 2016, lỗi tồn tại ở phiên bản sharepoint này cho đến bản patch KB5001946 và được vá ở bản KB5001976. Tiến hành cài đặt hai bản và sử dụng 7zip để gom các file dll cần thiết cho việc diff.

7z.exe a dll.7z -r .\Microsoft.Sharepoint.*.dll

Tiến hành gom ở 3 thư mục

  • C:\Windows\Microsoft.NET\assembly\GAC_MSIL
  • C:\Program Files\Common Files\microsoft shared
  • C:\inetpub\wwwroot\wss

Kết quả diff sử dụng WinMerge. Quan sát thấy có sự khác biệt khi có một hàm mới trong bản vá liên quan đến SetVariableActivity tồn tại ở lớp Microsoft.SharePoint.Workflow.SPNoCodeXomlCompiler

image

Nhìn tên hàm hiểu ngay vấn đề, hàm này dùng để vá lỗi cụ thể là validate thuộc tính ValueType của lớp SetVariableActivity. Hàm này được gọi bên trong hàm IsGoodWorkflow

image

Hàm IsGoodWorkflow lại được gọi trong hàm CompileBytes

image

Tiến hành phân tích hàm CompileBytes để xem nó được gọi từ đâu

image

Sử dụng dnspy, tìm ra được hàm ValidateWorkflowMarkupAndCreateSupportObjects. Theo tài liệu của Microsoft, khi các file workflow được tải lên, nội dung bên trong sẽ đi qua hàm này để validate và biên dịch. Như vậy để có được một kiểu .NET tùy ý ở đây chính là tạo một workflow, bên trong có action SetVariableActivity với giá trị thuộc tính ValueType được tùy chỉnh bởi User.

Tạo thành công một Crafted SetVariableActivity

Sử dụng giao diện trên Workflow Designer, tạo một workflow, thêm một action là Set Workflow Variable vào, như vậy có thể tạo được một SetVariableActivity. Sau khi tạo xong workflow sẽ có hai file được hình thành (Khi publish thì sẽ có thêm một file .xsn hoặc .aspx). Ví dụ ở đây workflow có tên là test

image

File test.xoml là file markup của workflow dùng để biểu diễn các step và action. Còn file test.xoml.wfconfig.xml là file cấu hình của workflow. Ở đây mình dành sự quan tâm cho file test.xoml

240272937_934578590739127_77488628058177475_n

Ngoài ValueType thì SetVariableActivity có hai thuộc tính khác là Value và Variable. Variable sẽ trỏ đến biến cần được set giá trị, biến này được khai báo ở phần RootWorkflowActivityWithData.WorkflowFields. Value là giá trị để set cho biến này.

Có thể thấy ngay phần SetVariableActivity đã được tạo, tuy nhiên thuộc tính ValueType vẫn không thể control được hoàn toàn bằng việc sử dụng giao diện. Để hoàn toàn tùy chỉnh ValueType, cần tạo hai file markup và config hợp lệ ở bên ngoài (hai file markup và config có thể copy từ việc tạo 1 flow giả sau đó edit lại) và upload thẳng lên thư mục workflow của Sharepoint Designer, sau đó sử dụng công cụ này publish workflow lên sharepoint site để có thể sử dụng. Theo cách này đã có thể tạo một Crafted SetVariableActivity. Lưu ý rằng không phải thay đổi kiểu gì cũng có thể publish được mà Sharepoint Designer sẽ validate nó hợp lệ xong mới cho phép Publish. Thực nghiệm thấy rằng thay đổi giá trị thuộc tính ValueType vẫn có thể publish được.

Tạo kiểu .NET nào cho RCE ?

Quan sát lớp Microsoft.SharePoint.WorkflowActions.SetVariableActivity

130595758-86fa3659-c515-4c19-a8de-10536f6a9dbd

Theo tài liệu của Microsoft, hàm Execute sẽ được gọi khi chạy activity. Biến type được tạo thành từ thuộc tính ValueType. Hai vị trí khoanh đỏ sẽ là đoạn code tiềm năng để tạo object. Ở khoanh đỏ đầu tiên, sử dụng converter được lấy từ type của obj. Giá trị của biến obj được lấy từ thuộc tính Value và được convert thành type của biến cần thay đổi giá trị.

240272937_934578590739127_77488628058177475_n

Do type của biến này không thể tùy chỉnh được, vì vậy type của obj bị giới hạn ở các type cơ bản như String, Int32, … và converter của các type này sẽ không thể convert obj thành kiểu ValueType tùy ý được. Do đó suy nghĩ về khoanh đỏ thứ 2. Ở đây sẽ tạo ra một constructor của ValueType nhận một tham số đầu vào dưới dạng String. Qua một số tìm hiểu và các bài PoC được public, tìm ra được một class phù hợp chính là System.Resources.ResourceSet có constructor cần thiết.

// ResourceSet Constructor

130601221-3dea4966-a3e9-4b25-8aac-55fed1d1e3ff

Constructor này nhận đầu vào là đường dẫn đến file .resource, tạo một ResourceHeader và gọi hàm ReadResource. Quan sát constructor của ResourceHeader

// ResourceHeader Constructor

130640521-6bccfb75-e68a-4957-9299-2aa42afe9873

Constructor này đọc file từ đường dẫn fileName lưu vào thuộc tính _store, gọi hàm ReadResource()

// ResourceHeader.ReadResource()

image

Hàm này tạo một BinaryFormatter và lưu vào thuộc tính _objFormatter. Bây giờ quay lại hàm ReadResource của ResourceSet

// ResourceSet.ReadResource()

image

Hàm này tạo biến enum từ lớp ResourceEnumerator bên trong lớp ResourceReader image

Sau đó sử dụng biến này để duyệt và gọi thuộc tính Value để lấy giá trị. Kiểm tra phương thức get của thuộc tính Value bên trong ResourceEnumerator

// ResourceHeader.ResourceEnumerator.Value

image

// ResourceHeader.GetValueForNameIndex()

image

// ResourceHeader.LoadObjectV2()

image

// ResourceHeader.DeserializeObject()

image

Ở đây ResourceHeader sử dụng thuộc tính _objFormatter để deserialize thuộc tính _store. Trong đó _objFormatter là một BinaryFormatter, _store là nội dung bên trong file .resources => Lỗi deserialize .NET

Tạo file .resources chứa payload

Visual studio sử dụng Resource File Generator (Resgen.exe) để convert file .resx thành một binary resource (.resources).

Tạo file .resx sử dụng chức năng add file của Visual Studio. Để thêm payload vào, chúng ta thêm node data vào trong root trong file .resx như sau

image

Phần payload được tạo bằng cách sử dụng công cụ ysoserial

.\ysoserial.exe -o base64 -c "calc" -f BinaryFormatter -g TypeConfuseDelegate

Cuối cùng là dùng resgen để generate ra file .resources

Sau khi đã đủ lông đủ cánh, thực hiện mô phỏng CVE này.

Proof of Concept

Tạo một site trên sharepoint theo tutorial. Sau đó tạo một tài khoản attacker. Attacker cần có quyền tạo workflow trên site, điều khiển một máy tính có liên kết với server sharepoint.

Tạo một file .resources với payload thực hiện command đơn giản là bật calculator (Resource1.resources)

image

Tạo một SMB server đơn giản theo hướng dẫn này để tạo một folder shared cho phép quyền anonymous đọc các file bên trong, yêu cầu máy attacker có kết nối với server sharepoint. Mục đích là để tạo đường dẫn đến file .resources sử dụng cho lớp ResourceSet. Sau đó đưa file .resources đã tạo vào đây, như vậy đường dẫn được tạo có dạng //DESKTOP-9GA3D02/shared/Resource1.resources

Bước tiếp theo là tạo hai file markup và config cho workflow, phần SetVariableActivity có dạng sau (phần value để giá trị là đường dẫn đến .resources)

image

Upload hai file lên thư mục workflow của Sharepoint Designer và publish workflow này.

Untitled

Kết quả sau khi workflow này được chạy là một process Calculator được tạo ra

image

Kết luận

Tồn tại một số lớp có gadget chain ẩn chứa bên trong các constructor. Và các constructor được sinh ra đều có lí do, nếu có thể tìm ra các lớp như vậy thì có thể nghiên cứu việc kiểm soát các param của constructor và tìm kiếm cơ hội RCE xung quanh các lớp này.

REFERENCES

https://www.zerodayinitiative.com/advisories/ZDI-21-828/

https://support.microsoft.com/en-us/office/introduction-to-sharepoint-workflow-07982276-54e8-4e17-8699-5056eff4d9e3

https://www.youtube.com/watch?v=JQYrqwgpAFY

https://blog.virtosoftware.com/how-to-create-sharepoint-designer-2013-workflow/

https://www.zerodayinitiative.com/blog/2020/4/28/cve-2020-0932-remote-code-execution-on-microsoft-sharepoint-using-typeconverters

http://nikolar.com/2015/03/10/creating-network-share-with-anonymous-access/

This post is licensed under CC BY 4.0 by the author.