Với một vài dòng code đơn giản, tôi đã tìm CVE của Joomla như thế nào?
Sau một thời gian nghiên cứu và tìm lỗ hổng về framework Joomla và tìm được vài CVEs. Sau đây mình sẽ write up về 3 lỗ hổng và phương pháp tìm.
- CVE-2019-19845
Lỗi được phát hiện trong quá trình tìm chain dựa vào CVE-2019-18650 để tìm WEBROOT, tuy nhiên lại chỉ khai thác được nếu máy chủ chưa tắt thông báo lỗi.
Như vậy, ý tưởng để tìm lỗi này sẽ như sau:
- Bật chế độ thông báo lỗi của máy chủ.
- Tìm toàn bộ các file thỏa điều kiện sau:
- Sử dụng các hàm gọi thư viện như use, include, include_once, require, require_once
- Không sử dụng _JEXEC , là cơ chế ngăn chặn truy cập trực tiếp vào file của Joomla.
- Tại mỗi file thỏa mãn điều kiện, tạo http request truy cập đến file sau đó kiểm tra nội dung trả của trang có chứa địa chỉ WEBROOT hay không.
Viết script để thực hiện ý tưởng trên:
https://gist.github.com/komang4130/8d2ac0f2b503dfb6945182f5f041670c
Kết quả:
2. CVE-2019-18650
Joomla sử dụng component com_template cho phép người dùng có thể thêm/xóa/sửa code của template trực tiếp từ giao diện web và thư mục template này được đặt ở WEBROOT.
Các chức năng template đều được hardening, để truy cập phải thông qua quá trình routing của Joomla bao gồm kiểm tra quyền, session của người dùng như vậy ta rất khó để tìm ra lỗi nào cho phép ta thực hiện các chức năng template mà không qua xác thực. Lúc này mình nghĩ đến lỗi CSRF.
Sau khi tìm hiểu, Joomla sử dụng JSession::checkToken hoặc JRequest::checkToken để phòng chống lỗi CSRF. Ví dụ:
Như vậy ý tưởng tìm lỗi CSRF của như sau:
- Duyệt toàn bộ file controller vì joomla hoạt động theo mô hình MVC, từ controller có thể call được action trong controller đó. Ví dụ
http://your_joomla/index.php?option=[component_name]&task=[controller_name].[action] - Tại mỗi file controller, kiểm tra các chức năng có sử dụng code kiểm tra token hay không, nếu không tiếp tục kiểm tra xem có cho nhận input từ người dùng hay không.
Script mình sử dụng: https://gist.github.com/komang4130/d0516194e22a77882f845fd4324f07a6
Kết quả:
Có khá nhiều chức năng ở component com_template không kiểm tra CSRF, trong đó mình khoanh vùng 2 file này và tiến hành phân tích.
Phân tích chức năng overrides()
Chức năng nhận vào 3 tham số:
- $file: file cần ghi
- $override: thư mục chứa file template để ghi vào thư mục template tương ứng với $id
- $id: id của template ( giá trị mặc định tương ứng với từng template )
Joomla sử dụng JInput để xử lý các kiểu dữ liệu khác nhau từ người dùng, để phòng chống các lỗi nguy hiểm như XSS, SQLi, Path traversal, …. ví dụ:
Và ở $override ta thấy đây là nhận dữ liệu folder của người dùng, Joomla sẽ xử lý dữ liệu về folder như sau:
Tuy nhiên, biến $override được nhận theo kiểu base64
Nếu trong luồng nghiệp vụ của chức năng không kiểm tra lại $override sau khi giải mã base64 sẽ xảy ra lỗi Path traversal, cho phép kẻ tấn công có thể gọi đến các thư mục ngoài WEBROOT.
Theo luồng nghiệp vụ, phân tích hàm createOverride($override) với tham số truyền vào là $override.
Như đã phân tích ở trên, dữ liệu $override tiếp tục không được kiểm tra để chống lỗi Path traversal.
Tiếp tục phân tích hàm createTemplateOverride($override, $htmlPath). Trong đó $htmlPath là thư mục tương ứng với $id, có thể truy cập từ WEBROOT.
Chức năng sẽ lấy toàn bộ file có định dạng đuôi ‘php’ từ thư mục $override để ghi vào $htmlPath. Và vẫn không có kiểm tra phòng chống lỗi Path traversal.
Như vậy, chức năng này bị hai lỗi đó là CSRF và Path traversal. Tao chain khai thác lỗi:
- Upload file mã độc php lên nơi nào đó trong máy chủ. (ftp-anon, local attack, … ).
- Tìm WEBROOT. (path disclosure, directory listing, enable error page.. ).Lừa admin ấn vào liên kết mã độc. ( XSS, Phishing )
- Mã khai thác: http://victim/joomla_path/administrator/index.php?option=com_templates&view=template&task=template.overrides&folder=base64(folder_of_malicious_php_code)&id=506&file=base64(foo_any)
Nếu kẻ tấn công có quyền quản lí thư mục template, thì kẻ tấn công có thể liệt kê các các file php trên server thư mục template và từ đó lấy thông tin các ứng dụng php có trên máy chủ. Có thể Dos hoặc ghi tràn Disk.
Mã khai thác:
http://victim/joomla_path/administrator/index.php?option=com_templates&view=template&task=template.overrides&folder=base64([WEBROOT/../../../../])&id=506&file=base64(foo_any)
trong đó
WEBROOT: path_to_joomla\components..\..\..\[to_your_malicious_folder_to_RCE]
Và với trường hợp enum thì chỉ cần đặt nhiều “..\”
Tùy target là Windows hay Linux mà ta sử dụng “../” hoặc “..\”
Minh họa lỗi:
- Ta đã upload được lên server file mã độc php. Ở mức demo dùng chức năng CSRF Generate PoC của Burp Suite để tạo trang phishing:
- Khi Admin click submit, mã độc được đã được thực thi.
Mã độc liệt kê toàn bộ file php trong thư mục:
Mã khai thác trong trường hợp máy local:
WEBROOT: D:\xampp\htdocs\joomla_3.9.12
Liệt kê toàn bộ thư mục ở thư htdocs: D:\xampp\htdocs\joomla_3.9.12\components..\..\..
http://victim/joomla_path/administrator/index.php?option=com_templates&view=template&task=template.overrides&folder=base64(“D:\xampp\htdocs\joomla_3.9.12\components..\..\..\
”)&id=506&file=XZXZ
Kết quả:
3. CVE-2020-8420: 1-click RCE
Phân tích hàm less():
Chức năng này nhận vào các tham số:
- $id : id của template ( protostar hoặc beez, hoặc tự custom )
- $file : file mà ta cần xử lý.
Chức năng dùng xem nội dung của $file. Nếu kết hợp với lỗi CSRF thì rất khó để có thể khai thác vì nội dung của $file chỉ hiển thị ở trang của admin. Tiếp tục phân tích hàm compileLess($file):
Tham số $file truyền vào được kiểm tra nếu có kí tự “/” thì sẽ cắt $file thành mảng dựa theo "/" và lấy giá trị cuối của mảng , như vậy có thể chống được Path Traversal ở máy chủ chạy hệ điều hành Linux. Tuy nhiên với máy chủ chạy hệ điều hành Windows có thể bypass với kí tự “\”. Như vậy chức năng bị lỗi Path Traversal nhưng chỉ áp dụng với hệ điều hành Windows.
Phân tích hàm compileFile($fname,$outFname) trong đó có tham số $fname được tạo từ phép cộng chuỗi $path và $infile , trong đó:
- $path thư mục của template tương ứng với $id.
- $infile là $file sau khi giải mã base64.
Hàm kiểm tra nếu như $fname truyền vào tồn tại trên máy chủ, nếu không sẽ raise exception “load error: failed to find.”$fname.
Do hàm compileLess($input) dùng try catch để handle exception nên sẽ gọi đến hàm enqueueMessage() khi có exception xảy ra.
Thông báo lỗi không được escape, như vậy với $file = base64_encode(“<script>alert(1)”), mã độc javascript được hiển thị trực tiếp ra màn hình dẫn đến lỗi XSS.
Mã khai thác:
Ngoài ra khi phát hiện lỗi Path traversal ở Windows như trên, thử thêm kịch bản là đã upload được file chứa mã độc javascript lên máy chủ là payload.js
Biến $string là nội dung của file payload.js.
Hàm parse() sẽ gọi đến một parser trong core ở file JOOMLA_PATH\libraries\vendor\leafo\lessphp\lessc.inc.php. Tương tự trả về thông báo lỗi chứa nội dung là mã độc javascript.
Từ những kịch bản như trên, có 2 cách để ta khai thác chiếm quyền máy chủ:
- Cách 1:
Ø Upload mã độc javascript lên server thông qua local attack hoặc ftp-anon.
Ø Dùng path traversal gọi mã độc (Chỉ áp dụng cho Windows).
Ø Lừa admin truy cập liên kết chứa mã độc ( Open redirect, Phishing).
- Cách 2:
Ø Lừa admin truy cập liên kết chứa mã độc ( Open redirect , Phishing).
Cách 1 thực hiện khai thác tương tự như bài viết ở phần 2. Ở đây định dạng file không quan trọng, chỉ cần upload được file chứa mã độc lên server ( pdf , txt , .... ).
Demo khai thác theo cách 2
Chức năng template cho phép sửa nội dung của file bất kì ở template với request như sau
Để thực hiện ta cần csrf.token.
csrf.token nằm ở nội dung trang html của admin ở file hợp lệ thuộc đường dẫn http://victim/administrator/* ( Ví dụ index.php ).
Viết mã độc javascript ghi mã độc php thực hiện lệnh whoami lên file error.php ở template protostar dựa vào request ghi file ở hình 32: https://gist.github.com/komang4130/0ed6f8cffd3e57d20cfd6052f6db2e8c
Mã khai thác:
Minh họa lỗi:
Dựa theo kết quả của script csrf_check ở phần 2.
Lỗi CSRF xảy ra ở controller Redirect, action purge() ở file administrator\components\com_redirect\controllers\links.php do không có kiểm tra CSRF token ở chức năng của admin.
Tương tự, mình tìm được thêm 3 chỗ lỗi tương tự
Action purge() ở administrator\components\com_languages\controllers\overrides.php
Action purge() và clean() ở administrator\components\com_associations\controllers\associations.php
Mã khai thác action clean():
Như vậy để khai thác lỗ hổng này, ta phải lừa được người quản trị click vào liên kết độc hại, tuy nhiên không phải lúc nào ta cũng có thể làm được nếu người quản trị viên có kiến thức về security. Vậy liệu có cách nào đó làm cho họ phải click mà không nghi ngờ gì không? Lúc này mình nghĩ đến chức năng check-in của admin.
Chức năng này tựa như là thông báo khi có bài viết mới và người quản trị viên thường sẽ click vào đọc mà không nghi ngờ gì.
Như vậy ta cần một tài khoản có quyền tạo bài viết, ở chức năng tạo bài viết của Joomla cho phép ta chèn image và sửa css ở thẻ style tuy nhiên lại không kiểm tra dữ liệu người dùng dẫn đến bị lỗi CSS Injection và có thể dẫn đến account takeover để đánh cắp số lượng lớn tài khoản người dùng nếu như server joomla đã bị kẻ tấn công chiếm quyền.
Ví dụ:
Mỗi khi người dùng truy cập vào bài viết thì kẻ tấn công có thể lấy được phiên làm việc của người dùng và đăng nhập.
Tương tự khi admin thấy thông báo có bài viết mới và check in thì phiên làm việc của admin cũng bị lộ.
Tuy nhiên lỗi này chỉ khai thác dẫn đến lỗi Account takeover với các điều kiện:
- Kẻ tấn công đã chiếm quyền máy chủ Joomla từ trước ( thông qua local-attack , …. )
- Kẻ tấn công có tài khoản với quyền tạo bài viết.
Nhưng mà không phải lúc nào ta cũng chiếm quyền được máy chủ từ trước, vì khi đã chiếm quyền được máy chủ ta có thể làm nhiều việc khác thay vì chỉ takeover account. Tuy nhiên với các lỗi CSRF và ở phương thức GET, ta có thể kết hợp với CSS Injection để khai thác và chỉ cần điều kiện cần tài khoản với quyền tạo bài viết.
Như vậy, ví dụ trường hợp cụ thể , ta muốn xóa TOÀN BỘ bài viết được associations sang ngôn ngữ khác của người dùng. Ta sẽ tạo bài viết mới, chèn thẻ image và ở thẻ style chèn mã khai thác css injection.
Ví dụ hiện tại ta thấy có 3 bài viết tiếng Việt được associations sang tiếng Anh , có 2 public và 1 chưa public:
Để khai thác, tạo bài viết chứa mã độc:
Admin khi online sẽ nhận được thông báo có bài viết mới:
Khi admin click vào check in, ta thấy sẽ có request đến action purge.
Lỗi này còn có có thể được chain với CVE-2019-18650 hoặc bất cứ lỗ hổng có thể được khai thác ở phương thức GET ( trừ các lỗ hổng cần hiển thị nội dung trang html như XSS ) và để khai thác kẻ tấn công chỉ cần quyền người dùng có thể tạo bài viết.