+32

Redteam 0x02: Tôi đã compromise hạ tầng của một ngân hàng trong tháng cô hồn như thế nào

*/ Lưu ý: Tất cả những gì mình làm và ghi lại trong bài post này đều đã được đơn vị chủ quản đồng ý và fix các lỗ hổng trước khi bài viết được public.

Mục tiêu cuối cùng của redteam không gì khác ngoài việc kiểm tra khả năng phòng thủ của hệ thống, chứng minh cấu hình dịch vụ hiện tại có thể dẫn đến rủi ro về mất mát tài sản hoặc dữ liệu khách hàng, nhân viên của một công ty nói chung. Trong quá trình redteam, ta cần phải che giấu bản thân, cố gắng tìm kiếm các lỗ hổng bảo mật web, ứng dụng, hạ tầng, thậm chí là phishing để đạt được mục đích ấy.

Nhớ lại lần đầu tiên mình làm redteam, khi đó mình có ít kinh nghiệm và kĩ năng, lúc nào cũng dùng máy cá nhân, IP cá nhân trong nội bộ, shell thì up vô tội vạ, RCE được là whoami, uname, cat /etc/passwd ngay mà không hề suy nghĩ. Lúc RCE được thì cũng không biết làm gì tiếp. Thậm chí hồi đó không có khái niệm về EDR, cũng không trong các kênh Incident của công ty nên có alert cũng chẳng biết, vẫn hồn nhiên whoami tiếp.

Rút kinh nghiệm từ những bài học đó, lần này mình quyết định phải compromise hạ tầng của mục tiêu mà không bị ai phát hiện.

Bối cảnh

Bối cảnh của lần này sẽ dễ hơn một chút, khi mình đóng vai trò là một nhân viên bình thường bên trong hệ thống. Các nhân viên sẽ join Active Directory (AD), mỗi máy sẽ được cung cấp 1 IP mapping với username đó. Trên máy nhân viên có cài Symantec để bảo vệ.

Hệ thống mục tiêu được chia các dải VLAN. Nhân viên có thể kết nối tới VLAN DEV, UAT tùy thích, nhưng không truy cập trực tiếp được vào PRODUCTION. Đây cũng là cấu hình cơ bản của hầu hết các công ty hiện nay.

Ẩn mình

Bước đầu tiên là vẫn phải tìm cách điều khiển một máy bên trong nội bộ, biến nó thành trung gian để khai thác hệ thống khác, tránh bản thân bị phát hiện.

Cách đầu tiên mình nghĩ đến là scan Nmap dải mạng của nhân viên, tìm xem biết đâu có nhân viên nào đang test một sản phẩm có 1day gì đó thì mình dùng nó để khai thác. Nhưng nhanh chóng mình nhận ra cách này không khả thi, vì máy nào cũng được cài Symantec để bảo vệ và nhảy cảnh báo khi scan Nmap. Vẫn có cách dùng Nmap không bị Symantec bắt được nhưng kết quả trả về không đầy đủ để biết service + version.

Trong một buổi tối đang nằm suy nghĩ, mình chợt nảy ra một ý tưởng hơi loằng ngoằng nhưng lại hợp lý.

Ngân hàng này có một số hệ thống public ra internet đăng nhập bằng tài khoản nhân viên xác thực LDAP tới AD. Mà mình bên trong hệ thống có thể query từ AD ra danh sách nhân viên, sau đó cho chạy brute force với mật khẩu phổ biến với tất cả nhân viên, dạng như Admin@123 Password@123, tất nhiên từ public nên có thể dùng VPN để khai thác mà không sợ lộ.

Trong 2 hệ thống này, 1 cái là Exchange, hệ thống còn lại thì thoạt nhìn có token dùng 1 lần, nhưng thực tế không hề check token đó và mình brute force bình thường.

Trong một lúc, mình chỉ có thể chạy với 2 password vì chỉ cần sai vài lần là tài khoản đó sẽ bị khóa trong AD 30 phút. Nếu để khóa toàn bộ nhân viên như thế thì không ổn.

Mình đã nghĩ quá trình bruteforce sẽ diễn ra lâu, nhưng không ngờ đến ngày thứ 3 là đã có kết quả. Một user giấu tên X đã để password yếu, và bằng vài biện pháp nghiệp vụ để biết IP (do đóng vai làm người trong hệ thống nên mình có thể access đến các máy nhân viên khác), mình cũng đã remote được vào con máy đấy. Sau khi cài backdoor, setup shell để có thể ssh gõ cmd như Linux, mình dùng nó để khai thác tiếp hệ thống.

Compromise hạ tầng

Trong đợt Redteam trước, mình có lấy được username/password của một số con quan trọng trong hệ thống production, tuy nhiên vì đã được chia VLAN khá kĩ, không có cách nào truy cập trực tiếp từ máy nhân viên đến đó nữa.

Nhưng thực tế mối nguy hiểm thì vẫn còn. Vì vậy để bảo vệ nó, mình cần tiếp tục khai thác để tìm thêm lỗ hổng.

Sau một thời gian recon, mình phát hiện trên dải production có 1 con GlassFish (tạm gọi là con GlassFish 40 vì nó có IP là x.x.x.40) có thể truy cập được.

Không có nhiều CVE liên quan đến con này, trong đó có 1 CVE là credential mặc định admin / admin. Mình không nghĩ là nó sẽ dính, nhưng không:

Đây là lần đầu tiên trong đời mình sử dụng GlassFish. Lúc mới đầu nhìn giao diện thấy có chức năng JDBCJNDI thì mình đã mừng thầm, chắc là chuẩn bị có easy RCE. Nhưng nó không dễ dàng như vậy, đây mới chỉ là mở đầu cho chuỗi ngày sắp tới. 2 chức năng này như để cho có, mình không tìm được cách nào để chèn payload kiểu ldap://server:1389/Object xong test connection để RCE.

Điều này khiến mình phải đọc thêm document và cách dùng của GlassFish.

GlassFish là server như Tomcat, Weblogic,... là nơi sẽ host các dịch vụ. Admin có thể RCE theo mặc định, bằng cách deploy 1 dịch vụ chạy reverse TCP connect là được. Vào phần Application → Deploy... → Add file war → Deploy

Sau đó chỉ cần truy cập đến IP:8080/shell/ thì sẽ access tới dịch vụ đó, easy RCE. Nhưng đấy là mình đang nói trên local của mình, còn thực tế không dễ dàng đến thế.

Con GlashFish sẽ có 4 cổng chính, 4848 là giao diện Admin, 7676 là giao diện quản trị JMX mà cũng có thể đạt được RCE như mình đã trình bày trong loạt bài về RMI, cổng 8080 là nơi host các dịch vụ và cổng 8181 cũng truy cập tới các dịch vụ đó nhưng với giao thức HTTPS.

Tuy nhiên con GlassFish này được cấu hình rất lạ. Nó được chạy trên docker, với nginx ingress đứng trước. Nó chỉ forward port 4848 với dải nhân viên, còn port 7676,8080,8181 không kết nối được

Mình đã tốn 2 ngày để download source code và tìm 0day trên con hàng cổ chục năm tuổi này để rồi ngộ ra 1 điều.

Vậy thì những job được cài đặt bên trong nó sẽ truy cập như thế nào? Giả thuyết của mình là nó sẽ thông đối với các con trong cùng VLAN, ví dụ con 41 có thể gọi đến con 40 port 8080 này.

Trong quá trình làm, mình cũng tìm được 1 con GlassFish trong dải UAT cấu hình tương tự, gọi nó là con 73

Để verify giả thuyết, mình cố gắng RCE một con ngang hàng với nó trong cùng VLAN. May mắn thay, sau một vài phút brute force thì mình tìm được 1 con server để pass SSH yếu. Từ con đó, thực hiện HTTP request đến IP:8080/shell/ thì mình đã có được 1 reverse shell.

Đến đây thì mình hơi thỏa mãn, nhưng cũng chỉ là UAT thôi. Mục tiêu của mình là PROD cơ mà.

Lại quay lại con GlassFish 40 trên PROD. Mình tiếp tục một công việc nhàm chán là đi recon hệ thống PROD, xem có con nào có thể access từ máy nhân viên không. Và cuối cùng, 1 giao diện quen thuộc hiện ra

Con này dính CVE-2023-38646. Nghĩ lại vẫn còn bồi hồi (cay) vì lúc CVE này mới ra, mình thức đêm thức hôm để phân tích, cuối cùng vẫn không làm kịp trước khi có nhiều người tung POC ra.

Có nhiều cách để POC con CVE này. Nhưng cái mình cần lại không phải RCE, mình chỉ cần tạo 1 HTTP Request đến con GlassFish kia thôi. Thế nên mình đã sử dụng POC từ blog của Calif. POC này sẽ gọi tới 1 HTTP endpoint, trích xuất ra câu lệnh SQL trong đó và thực thi, dạng http://attacker:port/poc.sql.

Và mình để endpoint đó là 73:4848/shell/. Kết quả khá khả quan, RCE được thành công con GlassFish.

Phải nói thêm về con Metabase kia. Đây là một giải pháp Visualize data trong database. Nên mình đã nghĩ có thể nào nó cũng connect tới nhiều con DB nhạy kãm.

Đến lúc phải thể hiện kĩ năng Post-RCE. Khá khó hiểu với metabase chạy docker thì mặc định có netcat ở trong. Con metabase này trên prod nên không dùng H2, mà thay vào đó là Postgresql. Dùng gì thì cũng phải lưu file db lại, nên mình lấy về rồi đọc, phát hiện tài khoản email admin là <user>@<redacted.domain>.

Để chiếm được quyền điều khiển của email này, ta cần chạy lệnh

java -jar metabase.jar reset-password <user>@<redacted.domain>

Lúc đó, server sẽ trả lại cho mình 1 token

Dùng nó để truy cập tới endpoint /auth/reset_password/<token> ta sẽ reset được pass của user đó

Sau khi xem toàn bộ các argument và đọc docs thì dường như đây là cách duy nhất để lấy được tài khoản admin. Nếu có chuyên gia nào đọc đến đây và có cách hay hơn, rất mong nhận được sự đóng góp ở phần comment.

Kết quả cuối cùng không tệ. Trong con metabase này link tới các DB với data cực kì nhạy cảm, bao gồm toàn bộ user, tài liệu, session tới các hệ thống, ...

Từ 2 con production này mình có thể truy cập tới nhiều con production khác với credential đã có.

Nhiệm vụ của mình cũng đã hoàn thành. Một đợt khai thác diễn ra thành công tốt đẹp, quan trọng nhất là không bị detect.

Bài học

Với bản thân

  • Một vài trick để không bị phát hiện,

  • Thêm kiến thức về network + java + một chút bypass AV

Với đội SOC / Vận hành

  • Tất cả các con server đều cần để mật khẩu mạnh,

  • Cài EDR cho toàn bộ endpoint, bao gồm các con trong docker, k8s các kiểu,

  • Xác thực, bảo vệ lẫn nhau giữa các con máy chủ rất yếu, cần triển khai các giải pháp management hiệu quả.

Xem thêm các bài viết mới nhất tại: https://shfsec.com/


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí