Khai thác lỗ hổng để lấy được source code của dịch vụ Y của platform X

Intro

Bug đã được fix nên giờ mới được publish bài viết. Tất cả nội dung dưới đây chỉ còn tính tham khảo ⚠️

Trong một ngày đẹp trời, thấy platform X thông báo về một dịch vụ mới mang tên Y tại địa chỉ: https://subdomainy.sitex.com. Cảm thấy bị lôi cuối với những lời lẽ "có cánh" mà X quảng cáo, tôi cũng dành chút thời gian vào dùng thử xem sao. Nhìn chung dịch vụ có nhiều chức năng rất hay, thú vị, và tiện lợi, các bạn cũng nên thử qua 😀. Tuy nhiên, đối với một người có sẵn tính tò mò như tôi thì điều tôi luôn quan tâm là liệu một dịch vụ mới như vậy, liệu nó có lỗ hổng gì không. Và thế là tôi cũng như nhiều bạn khác trong team Cyber Security Research, thuộc R&D Lab của Sun* đã cùng ngồi với nhau thử pentest dịch vụ Y xem sao. Sau một vài ngày thử nghiệm, cuối cùng chúng tôi cũng có chút ít thành quả. Đó là tận dụng lỗi Self-XSS và Local File Inclusion để xem được toàn bộ source code của Y 😳

Các lỗi phát hiện

Lỗi XSS

  • Ở các vị trí của phần nhập thông tin Profile:
    • Phía frontend đã validation thay thế <> bằng escaped HTML entities tương ứng.
    • Tuy nhiên, phía backend không có validation dẫn đến người dùng có chèn vào các tag tuỳ ý như <script>, <a>, <img> bằng cách thay đổi trực tiếp vào dữ liệu được post lên.
  • VD chèn payload
<img src=x onerror='alert(document.domain)' />

vào mục "Career Goal":

  • Dữ liệu trả về chưa được escape, vào trang tạo profile mới sẽ trigger javascript và hiện ra pop-up:

  • Tuy nhiên, lỗi chỉ dừng ở mức Self-XSS do sau khi convert sang PDF để chia sẻ cho người khác thì javascript sẽ không được thực thi nữa.

Lỗi Local File Inclusion (LFI)

<script>document.write(document.location.pathname)</script>

vào mục "Career Goal", ta được:

Code Javascript đã được thực thi, vậy dịch vụ Y có thể đang sử dụng KnpSnappy để thực hiện render PDF bằng webkit. Thử ghi file bằng fs của NodeJS và một số hàm JSON thì không thành công.

  • Thử sử dụng XMLHttpRequest để thực hiện lấy local file bằng protocol file:/// với payload
<script>x = new XMLHttpRequest; x.onload = function () { document.write(this.responseText + document.location.pathname) }; x.open('GET', 'file:///etc/passwd'); x.send();</script>

ta đọc được nội dung file:

Sau quá trình fuzzing, phát hiện thêm một số điểm sau:

  • Dịch vụ Y được deploy trong docker
  • thư mục gốc của project đặt tại /
  • framework sử dụng là Laravel, từ đó có thể tiếp tục đọc các file config, seed, controller, để kiểm tra các bug logic. VD: nội dung file config/database.php

  • Các config kết nối đến DB đều được lưu trong biến môi trường, tạm thời mình chưa tìm ra được cách đọc.

Timeline

  • 30-05-2019: Tìm thấy bug, viết report và liên hệ với dev team của dịch vụ Y.
  • ??-??-2020: dịch vụ Y đã được đập đi xây lại hoàn toàn (tất nhiên lý do không phải do bug này đâu nhé 😂). Hura !!!!

Phiên bản mới, ngon hơn, đẹp hơn, và KHÔNG còn lỗi nữa. Anh em cứ yên tâm mà dùng cho cuộc đời đỡ khổ nhé 😄

Bài học rút ra

  • Nhớ thực hiện input validation ở cả client và server và output encoding tất cả các ký tự nguy hiểm nha.

Thanks

All Rights Reserved