[EX006] Hành trình khai thác lỗ hổng CVE-2021-22986

 

Tổng quan

Hãng F5 vừa công bố một số lỗ hổng nghiêm trọng trong ứng dụng web của sản phẩm Big IP, trong đó đáng chú ý phải kể đến CVE-2021-22986. Lỗ hổng này nằm trong giao diện quản lý iControl REST API, có thể cho phép kẻ tấn công thực thi mã từ xa mà không cần xác thực với điểm số CVSS lên đến 9.8.

Trong bài viết này chúng tôi sẽ đi vào phân tích chi tiết và cách khai thác lỗ hổng.

Giao diện iControl REST

Trước hết chúng tôi xác định handler của các API này. Thông tin trên trang web của F5 cho thấy các endpoint này đều có tiền tố là /mgmt/. Cấu hình httpd cho thấy các request này được chuyển tiếp tới một dịch vụ  lắng nghe trên localhost tại cổng 8100:

Tiến trình này là một ứng dụng java servlet, với các class tại /usr/share/java/rest:


Phân tích lỗ hổng

Chúng tôi thực hiện tải các tệp jar ở đường dẫn trên từ 2 phiên bản Big IP Virtual Edition và decompile để so sánh mã nguồn nhằm xác định lỗ hổng. Không có nhiều thay đổi trong mã nguồn, do đó có thể xác định nhanh chóng những tệp đáng chú ý:

Quan sát nhanh thay đổi class IAppBundleInstallTaskCollectionWorker, dễ dàng nhận thấy bản cập nhật đã vá lỗi command injection. Tuy nhiên sau khi debug ứng dụng này, chúng tôi nhận thấy lỗ hổng chỉ có thể tận dụng nếu request được gửi trực tiếp tới servlet trên localhost. Nếu như vậy có khá nhiều endpoint (tính năng) có thể sử dụng để RCE.

Nói qua về kiến trúc iControl, ứng dụng này sử dụng class RestServerRestWorker làm trung tâm. RestServer sẽ sử dụng các RestWorker để handle các request, bao gồm các handler như onPost, onGet, onQuery,.. tương ứng với các HTTP method và các sự kiện như onStartCompleted, onPostComplete. Các  worker khi được load sẽ đăng ký với một URI tương ứng, được lưu vào RestServer.pathToWorkerMap và sử dụng để lookup handler. Các request được đại điện bởi class RestOperation. Ngoài ra, các worker giao tiếp với nhau cũng thông qua các request. Bạn đọc cần trực tiếp debug ứng dụng để hiểu rõ hơn các khái niệm này.

Quay trở lại với cấu hình httpd (/run/conf/httpd.conf):

Lần trước, chúng tôi đã có một bài phân tích về lỗ hổng trên Big IP liên quan đến cấu hình httpd. Tuy nhiên, ứng dụng đang phân tích là một servlet đơn thuần, không phải tomcat, do đó có thể loại bỏ việc bypass cấu hình này với path parameter. Ở đây, httpd yêu cầu người dùng phải xác thực (với mod_auth_pam.so) mới có quyền truy cập các endpoint iControl REST API. Như vậy, khá chắc rằng phải có một lỗ hổng SSRF để có thể thực hiện “real” RCE.

Câu hỏi đặt ra là liệu có SSRF từ chính iControl REST hay từ TMUI hoặc các web application khác của Big IP. Tiếp tục phân tích thay đổi, chúng tôi xác định lỗ hổng SSRF trong class AuthnWorker.

Giá trị state.loginReference.link được deserialize từ json post data – dữ liệu mà người dùng có thể kiểm soát. Sau đó, một HTTP post request được gửi đến URL này:

Phân tích hook handler trong mod_auth_pam.so cho thấy endpoint /mgmt/shared/authn/login được pass lại cho chính iControl servlet xử lý tại AuthnWorker. Như vậy, đây chính là pre-auth SSRF cần thiết để khai thác lỗ hổng này.

Khai thác lỗ hổng

Việc khai thác lỗ hổng gặp khá nhiều khó khăn do việc dữ liệu gửi đi trong SSRF request bị giới hạn bởi các trường trong AuthProviderLoginState.

Lần thử đầu tiên

Chúng tôi thực hiện exploit bằng cách lợi dụng SSRF để gửi request trực tiếp tới endpoint IappBundleInstallTaskCollectionWorker tại /tm/access/bundle-install-tasks nhưng không thành công do không thể control được filePath. Sau khi tìm kiếm với hi vọng có magic nào đó trong lib gson thất bại, chúng tôi chuyển qua ý định RCE nếu có thể có một lỗi upload nào đó và ghi file vào /var/apm/f5-iappslx-agc-usecase-pack/ với nội dung bất kỳ. validateGzipBundle() sẽ tìm kiếm và lấy file đầu tiên trong thư mục này để gán giá trị cho cho filePath. Trong linux hoàn toàn có thể tạo file name chứa các ký tự `, | hay & vốn có thể dùng để khai thác OS command injection.

Với nhận định này, chúng tôi tập trung vào phân tích sự thay đổi liên quan đến AsmFileTransferWorker. Worker này cho phép upload file lên /ts/var/rest và mới thêm một số validator liên quan đến user cũng như filename:

Tuy nhiên, sau nhiều lần thử và thất bại, chúng tôi vẫn chưa thể khai thác theo hướng này, bao gồm cả việc tìm kiếm endpoint mới tương tự để lợi dụng.

Khai thác thành công

Trong khi tiếp tục tìm kiếm các endpoint có thể khai thác với các trường dữ liệu có thể kiểm soát, chúng tôi thấy một tweet của researcher Rich Warren (@buffaloverflow) tại đây. Theo hình ảnh trong bài đăng này, có thể thấy được rằng tác giả đã tạo và leak được token của user có quyền cao, đây là một hint rất lớn để chúng tôi follow.

Chúng tôi tiến hành phân tích xoay quanh AuthTokenWorker – là worker đảm nhận vai trò xác thực và sinh token.

Cơ bản, token được sinh ra và lưu vào tokenCache trước khi lưu trữ với StorageWorker. Có 3 ý tưởng có thể thực hiện token:

  • Gửi request trực tiếp tới AuthTokenWorker để sinh token. Với cách này, cần kiểm soát được giá trị user trong AuthTokenItemState, do đó không thể sử dụng.
  • Gửi request tới StorageWorker để lưu token tùy ý. Tuy nhiên, khi token được lấy ra để validate thì trong json cũng yêu cầu giá trị user.
  • Hijack một luồng thực thi nào đó để sinh token. Chúng tôi đã khai thác thành công với ý tưởng này.
Quay lại với chức năng đăng nhập tại AuthnWorker

Khi request checkAuth thành công, tức đã xác thực được người dùng, worker này sẽ gọi hàm generateToken, hàm này thực hiện request đến AuthTokenWorker để sinh token và trả về cho người dùng đúng như tính năng của nó.

Bạn có thể nhận ra ý tưởng? Ở đây, request tới AuthTokenWorker được thiết lập giá trị state.user bằng với loginState.userReference (loginState được deserialize từ response của checkAuth) đúng như tính năng vốn có của nó. Vậy nếu chúng ta có thể tìm được một endpoint nào đó sao cho request checkAuth (SSRF) trả về dữ liệu json chứa key userReference có thể kiểm soát thì hoàn toàn có thể sinh token cho user bất kỳ. Điều này là hoàn toàn hợp lý và khả thi vì chúng ta có thể kiểm soát trường userReference.

Sau khi review tất cả worker implement phương thức onPost (ưu tiên review các worker sử dụng state class tương ứng có khai báo “RestReference userReference”), chúng tôi tìm thấy một class có thể sự dụng là GossipWorker.

Sau khi tạo và leak được token, việc còn lại là sử dụng token này để thực thi mã từ xa.


Cảm ơn các bạn đã đọc bài!


Researcher: Tạ Quang Khánh
VinCSS (a member of Vingroup)



No comments:

Post a Comment