Phân tích bản vá tháng 11 của Microsoft Exchange

Buổi chiều thứ 3 ngày mùng 9 tháng 11 năm 2021, khi những cơn gió đầu đông ùa về, lòng tôi man mác nhớ một hình bóng đã xa. Chìm đắm trong những suy nghĩ miên man, tôi nhận được thông tin từ đồng nghiệp về một lỗ hổng thực thi mã từ xa của máy chủ Microsoft Exchange (CVE-2021-42321) sẽ được vá trong bản patch tháng này của M$. Ồ là em, exchange, người đã làm tôi mất ngủ nhiều đêm tháng 4.

Năm bảy tuổi, bắt được ve sầu, cứ tưởng có cả mùa hè trong tay. Năm 20 reproduce được cái bug, cứ ngỡ sắp đi P2O.

dieulink

Gần đây mới diễn ra cuộc thi Tianfu Cup, nghe đồn có RCE nên tôi đoán là bug này.

Do đó, chúng tôi dự định sẽ đợi đến đêm ngày thứ 3 khi Microsoft phát hành bản vá sẽ bắt tay ngay vào phân tích.

Đầu tiên tôi cài phiên bản Exchange Server 2019 CU11. Phiên bản này bao gồm tất cả các bản patch từ tháng 9 trở về trước. Vì vậy tôi chỉ cần cài thêm bản vá tháng 10, đợi M$ ra bản vá tháng 11 và diff 2 phiên bản với nhau.

Sau khi phát hành bản vá lỗ hổng thì Microsoft cũng đã đưa thông tin mô tả về CVE này https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2021-42321. Từ các thông tin có được, chúng tôi nhận định đây là một lỗ hổng Post-auth RCE.

Tôi sử dụng Uninstalltool để kiểm tra các file thay đổi khi cài đặt bản vá tháng 11. Số lượng file thay đổi lên đến hơn 1000 file, bao gồm gần 800 file dll, số còn lại bao gồm các file config, js và một số file data.

Tôi tập trung phân tích các file dll vì đây là các file chứa mã lệnh chạy trên server, các lỗ hổng liên quan đến server chủ yếu sẽ khai thác các đoạn code trong các file dll này. Để có thể diff các file dll thì cần phải dịch ngược chúng ra file source code và sử dụng phần mềm Winmerge so sánh với nhau. Tôi mất gần 3 tiếng để có thể export toàn bộ số dll với một server 12 core 64 GB ram.

Sau khi export xong thì tôi dùng phần mềm Winmerge để diff 2 folder chứa source code với nhau. Kết quả có quá nhiều vị trí khác nhau, nhiều vị trí gây nhiễu và tôi phải tiến hành tự chỉnh sửa, tiếp tục mất thêm một tiếng nữa. Quá trình này chủ yếu đòi hỏi sự kiên trì và thao tác tay nhanh nhẹn.

Sau khi đã loại bỏ các vị trí gây nhiễu, số vị trí có thay đổi của bản vá lần này vẫn là khá nhiều và chủ yếu liên quan đến lỗ hổng deserialize bằng BinaryFormatter. Đây là formatter có lợi cho người tấn công vì thường không có cơ chế kiểm soát type của dữ liệu được xử lý. Có thể nói Microsoft muốn xử lý toàn bộ các vị trí có nguy cơ trong bản vá lần này.

Do có quá nhiều vị trí patch nên bài toán lớn nhất để có thể reproduce được lỗ hổng này đó là tìm ra vị trí có thể trigger được và ta có thể control được input.

Hết ngày thứ 4 (10/11)

Thứ 5 (11/11), sau khi phân tích qua các vị trí thì tôi nhận thấy class TypedBinaryFormatter đã bị xóa.

Tại class này, hàm Deserialize nhận tham số binder, thường có tác dụng kiểm soát type để ngăn chặn tấn công deserialize, được truyền vào nhưng lại không được sử dụng. Thật sự tôi chỉ biết thốt lên ảo ma canada.

Tôi thử nghiệm khai thác Deser class Type sau đó test poc thì xác nhận là có thể bypass check type bằng gadget TypeConfuseDelegate.

Kể từ sau đó thì quá trình đi vào bế tắc. Chúng tôi chia nhau phân tích các hướng khác nhau, bao gồm từ RPC, Powershell nhưng không có kết quả. Đến mức tôi phát hiện ra một lỗ hổng self RCE.

Mọi thứ tưởng như đã kết thúc thì đến tối ngày 17/11, người em Q của tôi sau khi trace hết các đoạn code đã phát hiện ra một file ini bị bỏ sót.

Class ClientExtensionCollectionFormatter được thêm vào EnableStrictLocation, chính class này cũng gọi đến TypedBinaryFormatter. Từ đó, mọi người bắt đầu trace theo các class, interface có liên quan đến nó.

Sử dụng chức năng quản lý add-ins ở /ecp để có thể gọi được đến quá trình deserialize.

Dữ liệu đưa vào deserialize được lấy từ userConfiguration.GetStream()

Vậy vấn đề cần giải quyết là làm sao để có thể control được được userconfiguration.GetStream. Thực sự tôi đã xem qua đoạn này nhưng vì không thể tìm được input của dữ liệu nên đã đi theo các hướng khác.

Nếu như trace theo đúng các hàm override ở class thì dnSpy không thể tìm được caller, vì vậy phải trace theo các hàm ở interface.

Như vậy luồng xử lý liên quan đến dữ liệu từ UserConfiguration. Search trên mạng tôi tìm thấy tài liệu của Microsoft về cách thay đổi UserConfiguration thông qua service EWS.

Như vậy tôi có thể control được dữ liệu trong Stream của UserConfiguration. Tiếp theo là tìm đúng định danh của configuration được sử dụng. Các giá trị này được lấy từ hàm LoadMasterTable (đã biết trong quá trình trace).

Tiến hành set giá trị tạo từ payload ysoserial.net

Kết quả: https://youtu.be/HTsr0WaLfW0

Không có mô tả ảnh.

Credit: @_q5ca, @vudq16, @dieulink81

Leave a Reply

Your email address will not be published. Required fields are marked *