+3

Server side request forgery vulnerabilities (SSRF) - Các lỗ hổng giả mạo yêu cầu phía máy chủ (Phần 3)

II. Phân tích và khai thác các lỗ hổng Server-side request forgery (tiếp)

5. Kiểm tra lỗ hổng SSRF

SSRF thường xuất hiện ở các chức năng có quá trình trao đổi dữ liệu với một trang web khác. Và chúng ta cũng cần có một phương pháp để kiểm tra khả năng xảy ra của lỗ hổng SSRF. Một trong những phương pháp kiểm tra phổ biến và đơn giản nhất chính là kỹ thuật out-of-band (OAST). Trong bài viết này tôi sẽ trình bày kỹ thuật với công cụ Burp Collaborator.

Nếu các bạn để ý thì trong các bài lab trước tôi cũng có sử dụng tới kỹ thuật này nhằm xác định chính xác hơn khả năng xảy ra lỗ hổng SSRF.

image.png

image.png

Một ví dụ khác cho kỹ thuật out-of-band (OAST) qua bài lab sau.

Phân tích lab Blind SSRF with out-of-band detection

image.png

Miêu tả: Trang web sử dụng một phần mềm tìm nạp và phân tích URL được xác định trong header Referer khi người dùng truy cập vào trang hiển thị chi tiết sản phẩm. Để giải quyết bài lab, chúng ta cần sử dụng chức năng này thực hiện một kịch bản DNS lookup với server Burp Collaborator.

Khi truy cập vào trang hiển thị chi tiết sản phẩm, quan sát request trong Burp Suite:

image.png

Chúng ta thấy header Referer mang giá trị địa chỉ URL của trang được truy cập ngay trước khi chúng ta truy cập tới giao diện hiển thị chi tiết sản phầm /product?productId=1

Thay đổi giá trị header Referer thành địa chỉ tới domain Burp Collaborator.

image.png

Gửi request, quan sát tại Burp Collaborator Client thu được request đến từ server trang web chứa lỗ hổng SSRF.

image.png

Như vậy chúng ta đã thực hiện DNS lookup thành công, tại header Referer có khả năng bị tấn công SSRF, bài lab được giải quyết!

image.png

Việc xác nhận lỗ hổng SSRF thông qua kỹ thuật out-of-band (OAST) không chỉ giúp chúng ta tiết kiệm thời gian, tài nguyên trong quá trình kiểm thử sản phẩm, mà còn là một bước bắt buộc trong việc khai thác lỗ hổng Server-side request forgery ở dạng blind - Một dạng lỗ hổng SSRF không trả về kết quả trong giao diện, sẽ được chúng ta bàn bạc và phân tích kỹ hơn ở phần sau.

6. SSRF và bypass white-based input filters

Bên cạnh sử dụng black list, một số trang web sử dụng white list gồm các phần tử bắt buộc phải xuất hiện trong các tham số. Việc sử dụng white list thường mang lại hiệu quả tốt hơn black list, tuy nhiên các nhà phát triển cần cập nhật white list liên tục mỗi khi có chức năng hoặc các phần tử mới cần bổ sung. Việc cài đặt cơ chế ngăn chặn dựa theo white list vẫn có khả năng bị kẻ tấn công vượt qua bởi các ký tự có chức năng đặc biệt trong URL.

6.1. Cài đặt cơ chế ngăn chặn white list dựa theo port

Một trang web có một cơ chế ngăn chặn lỗ hổng SSRF bằng cách giới hạn chỉ cho phép người dùng truy cập tới port 8080 tại local. Đoạn code vận hành với ngôn ngữ PHP như sau:

<?php
$url = 'http://' . $_GET['url'];
$parsed_url = parse_url($url);
if ($parsed_url['port'] == '80') {
    readfile($url);
} else {
    echo "SSRF attack detected!";
}

Tham số url truyền giá trị qua phương thức GET, sau đó trang web thực hiện hàm parse_url() phân tích cú pháp URL giá trị này và kiểm tra biến $parsed_url['port'] có bằng 8080 hay không, nếu có thực hiện hàm readfile() đọc giá trị từ $url. Điều này chỉ cho phép người dùng có thể truy cập tới nội dung public tại port 8080:

image.png

Đoạn code không hề có vấn đề gì? Thực tế không phải như vậy, lỗ hổng xảy ra ở cách hoạt động xung đột của hai hàm parse_url()readfile() trong PHP. Xét giá trị url=localhost:8888:80, thực tế ở đây, hai hàm readfile()parse_url() đang quan tâm hai port khác nhau!

image.png

Theo cách định nghĩa trong ngôn ngữ PHP thì: readfile() sẽ mặc định chọn port xuất hiện đầu tiên (sau dấu hai chấm), còn parse_url() sẽ chọn port xuất hiện cuối cùng!

Và hình ảnh phía trên cũng chính là cách vượt qua cơ chế ngăn chặn tấn công trong đoạn code chúng ta đang xét:

image.png

6.2. Cài đặt cơ chế ngăn chặn white list dựa theo host

Chúng ta sẽ tiếp cận với cơ chế ngăn chặn đơn giản bằng cách kiểm tra các phần tử trong danh sách white list có xuất hiện trong chuỗi URL hay không. Từ đó thực hiện ngăn chặn các hành vi tấn công SSRF.

Xem xét đoạn code viết bằng ngôn ngữ Python sau:

from flask import *
import requests

app = Flask(__name__)

@app.route('/ssrf')
def follow_url():
    url = request.args.get('url', '')
    whitelist = ['google.com', 'youtube.com']
    check = 0
    for i in whitelist:
        if i in url:
            check = 1
    if check:
        return (requests.get(url).text)
    else:
        return ("SSRF Attack detected!")

if __name__ == '__main__':
    app.run(host = "0.0.0.0", port = 1234)

Đoạn code trên chứa một white list kiểm tra biến url cần chứa một trong các phần tử google.com hoặc youtube.com, với mong muốn sẽ ngăn chặn kẻ tấn công thực hiện khai thác lỗ hổng SSRF vào các trang web khác, chỉ cho phép hai trang web trên trong white list.

image.png

Điều này có nghĩa rằng, để khai thác được lỗ hổng SSRF thì trong tham số url luôn cần chứa giá trị google.com hoặc youtube.com. Ý tưởng để vượt qua cơ chế ngăn chặn này là chúng ta có thể "nhúng" địa chỉ vào URL này. Thực hiện bằng các ký tự đặc biệt như @, #, &, .. Kết quả sau đúng với phần lớn các ứng dụng web:

  • https://expected-host@evil-host
  • https://evil-host#expected-host
  • https://expected-host.evil-host

Ngoài ra có thể sử dụng kỹ thuật URL encode và kết hợp khéo léo các kỹ thuật trên với nhau.

Quay lại ví dụ phía trên, chúng ta có thể "nhúng" địa chỉ localhost:8888 vào tham số url vượt qua cơ chế white list bằng một vài cách như sau:

  • Cách 11: Sử dụng ký tự @, payload: url=http://google.com@localhost:8888

image.png

  • Cách 22: Sử dụng ký tự #. Nếu trực tiếp truyền giá trị url=http://localhost:8888#google.com thì khi thực thi request.args.get('url', '') trang web chỉ nhận được giá trị url=http://localhost:8888 do ký tự # lúc này được hiểu với vai trò anchor link. Bởi vậy cần thực hiện URL encode ký tự # thành %23 để khi URL decode tự động ký tự # được hiểu là một fragment, payload: url=http://localhost:8888%23google.com

image.png

Xem xét một trường hợp khác, sử dụng white list thực hiện ngăn chặn tấn công SSRF với đoạn mã nguồn viết bằng PHP như sau:

<?php
$url = 'http://' . $_GET['url'];
$parsed_url = parse_url($url);
if ($parsed_url['host'] == 'google.com') {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_exec($ch);
} else {
    echo "SSRF attack detected!";
}

Đoạn code sử dụng hàm parse_url() trong PHP phân tích cú pháp URL đầu vào, kiểm tra giá trị host $parsed_url['host'] bắt buộc phải là google.com, tiếp theo sử dụng hàm curl_exec() của thư viện cURL hiển thị nội dung trang web.

Mục đích của kẻ tấn công là đọc nội dung tại http://11.0.0.1:1234 là một địa chỉ chỉ có thể truy cập từ mạng nội bộ. Chắc hẳn qua ví dụ cài đặt white list với port ở phía trên các bạn cũng đã đoán ra vấn đề ở đây rồi phải không? Đúng vậy, lỗ hổng SSRF xảy ra do định nghĩa về giá trị host của hàm parse_url() và thư viện cURL không đồng nhất. Chẳng hạn với URL http://viblo@evil.com@google.com (chuỗi viblo ở đầu có thể thay bằng bất kỳ giá trị khác):

image.png

Như trong hình vẽ, thư viện cURL sẽ ưu tiên host là evil.com, đối với hàm parse_url() lại lựa chọn google.com. Bởi vậy, chúng ta có thể xây dựng payload tấn công như sau: url=viblo@11.0.0.1:1234@google.com

image.png

Các tải liệu tham khảo


©️ Tác giả: Lê Ngọc Hoa từ Viblo


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.