DOM-based XSS
Khái niệm
DOM-based XSS vulnerabilities thường xuất hiện khi JavaScript lấy dữ liệu từ một nguồn mà kẻ tấn công có thể kiểm soát, như URL, và truyền nó đến một "sink" hỗ trợ thực thi mã động, như eval()
hoặc innerHTML
. Điều này cho phép kẻ tấn công thực thi mã JavaScript độc hại, thường cho phép chúng chiếm quyền kiểm soát tài khoản của người dùng khác.
Để thực hiện một cuộc tấn công DOM-based XSS, kẻ tấn công cần đưa dữ liệu vào một "source" sao cho nó được lan truyền đến "sink" và gây ra việc thực thi mã JavaScript tùy ý.
Nguồn phổ biến nhất cho DOM XSS là URL, thường được truy cập bằng đối tượng window.location
. Kẻ tấn công có thể tạo một liên kết để gửi nạn nhân đến trang dễ bị tấn công với payload nằm trong chuỗi truy vấn (query string) và phần đoạn (fragment) của URL. Trong một số trường hợp, như khi tấn công trang 404 hoặc trang web chạy PHP, payload cũng có thể được đặt trong đường dẫn (path).
Cách kiểm tra
Dưới đây là các bước kiểm tra thủ công:
Kiểm tra các "sinks" HTML
Đặt dữ liệu vào nguồn: Sử dụng một chuỗi alphanumeric ngẫu nhiên vào nguồn (như
location.search
).Kiểm tra HTML: Sử dụng công cụ phát triển của trình duyệt (ví dụ: Chrome Developer Tools) để kiểm tra HTML và tìm nơi chuỗi xuất hiện. Lưu ý rằng tùy chọn "View source" của trình duyệt không làm việc cho kiểm tra DOM XSS vì nó không tính đến các thay đổi HTML do JavaScript thực hiện. Trong Chrome, có thể sử dụng Control+F (hoặc Command+F trên MacOS) để tìm chuỗi trong DOM.
Xác định ngữ cảnh: Xác định ngữ cảnh nơi chuỗi xuất hiện trong DOM. Dựa trên ngữ cảnh này, tinh chỉnh đầu vào để xem cách nó được xử lý. Ví dụ, nếu chuỗi xuất hiện trong thuộc tính có dấu ngoặc kép, thử chèn dấu ngoặc kép vào chuỗi để xem liệu có thể thoát ra khỏi thuộc tính đó không.
URL-encoding: Các trình duyệt xử lý URL-encoding khác nhau. Chrome, Firefox và Safari sẽ URL-encode
location.search
vàlocation.hash
, trong khi IE11 và Microsoft Edge (trước khi chuyển sang Chromium) không URL-encode các nguồn này. Nếu dữ liệu được URL-encode trước khi xử lý, cuộc tấn công XSS có thể không hoạt động.
Kiểm tra các "sinks" thực thi JavaScript
Tìm kiếm trong mã JavaScript: Xác định các trường hợp trong mã JavaScript của trang mà nguồn được tham chiếu. Trong Chrome Developer Tools, có thể sử dụng Control+Shift+F (hoặc Command+Alt+F trên MacOS) để tìm kiếm toàn bộ mã JavaScript của trang.
Sử dụng Debugger: Sử dụng công cụ gỡ lỗi để thêm điểm dừng và theo dõi cách giá trị của nguồn được sử dụng. Có thể thấy rằng nguồn được gán cho các biến khác. Nếu vậy, sử dụng chức năng tìm kiếm để theo dõi các biến này và xem chúng có được truyền đến một sink không. Khi tìm thấy một sink nhận dữ liệu từ nguồn, có thể sử dụng công cụ gỡ lỗi để kiểm tra giá trị của biến trước khi nó được gửi đến sink. Sau đó, tinh chỉnh đầu vào để xem liệu có thể thực hiện thành công cuộc tấn công XSS không.
Sử dụng DOM Invader
DOM Invader: Để đơn giản hóa việc phát hiện và khai thác DOM XSS, có thể sử dụng tiện ích mở rộng DOM Invader của Burp Suite.
Khai thác
Một web site có thể bị tấn công DOM-based XSS nếu có một đường dẫn thực thi mà dữ liệu có thể truyền từ nguồn (source) đến đích (sink). Trong thực tế, các nguồn và đích khác nhau có tính chất và hành vi khác nhau, ảnh hưởng đến khả năng khai thác và kỹ thuật cần thiết. Ngoài ra, các script của website có thể thực hiện việc xác thực hoặc việc xử lý dữ liệu khác phải được đáp ứng khi cố gắng khai thác lỗ hổng.
Các sink có thể dẫn đến lỗ hổng DOMXSS
HTML sink
document.write
sink có thể hoạt động vớiscript
Giải pháp:
Nhập vào thanh tìm kiếm chuỗi bất kì
Chuột phải và Inspect element này, chú ý đến nơi chuỗi tìm kiếm được đặt
Được đặt trong img src
attribute, theo sau đó là một chuỗi ngẫu nhiên. Có thể thoát khỏi img
attribute bằng ">
Nhập vào thành tìm kiếm hoặc URL
"><svg onload=alert(1)>
Trong một số trường hợp nội dung được viết bởi document.write bao gồm ngữ cảnh xung quan mà cần phải tính đến trong khai thác. Ví dụ, cần đóng một vài element đang tồn tại trước khi sử dụng JavaScript payload
Giải pháp:
Thực hiện chức năng stock checker với mặt hàng và địa điểm bất kỳ, Inspect kết quả trả về
Nhận thấy rằng rằng đoạn script trích xuất tham số storeId
tham số từ location.search
. Sau đó, nó được sử dụng document.write
để tạo option mới trong phần tử select cho chức năng stock checker.
Thêm tham số storeId vào sau URL với giá trị bất kỳ: &storeId=loilt8
Kết quả giá trị này đã được trả về như một option trong droplist.
Inspect phần tử này, xác nhận rằng giá trị này đã được đặt bên trong phần tử select
Sửa tham số storeId để khai thác XSS: &storeId=<svg%20onload=alert(1)>
innerHTML
sink không chấp nhậnscript
element cũng nhưsvg onload
events . Biện pháp thay thế là sử dụngimg
hoặciframe
. Event handler nhưonload
vàonerror
có thể được sử dụng kết hợp với các yếu tố này. Ví dụ:
Giải pháp:
Inspect chức năng tìm kiếm blog.
Nhận thấy có innerHTML
sink. Khai thác XSS bằng payload sau, nhập vào thanh tìm kiếm:
Giá trị cảu src
attribute không hợp lệ và throw error. Điều này kích hoạt onerror
event handler, sẽ gọi hàm alert()
Sources và sinks trong các dependency bên thứ ba
Các ứng dụng web hiện đại thường sử dụng nhiều thư viện và framework bên thứ ba, cung cấp nhiều tính năng và tiện ích. Tuy nhiên, một số chúng cũng có thể là nguồn và điểm đích cho lỗ hổng DOM-XSS
DOM XSS trong JQuery
attr() Function: Thay đổi thuộc tính của các phần tử DOM. Nếu dữ liệu từ nguồn do người dùng kiểm soát (như URL) được truyền vào hàm
attr()
, có thể có khả năng gây ra XSS. Ví dụ dưới đây thay đổi thuộc tínhhref
của một phần tử liên kết:
Kẻ tấn công có thể lợi dụng điều này bằng cách thay đổi URL để location.search
chứa một URL JavaScript độc hại. Khi trang áp dụng URL độc hại này cho thuộc tính href
, việc nhấp vào liên kết sẽ thực thi mã độc:
Giải pháp:
Inpect chức năng "Back" ở trang Submit feedback
Theo như thông tin được cho biêt, trang này sử dụng sử dụng selector $ của thư viện jQuery để tìm phần tử neo và thay đổi thuộc tính href của nó bằng cách sử dụng dữ liệu từ location.search.
URL lúc này sẽ là /feedback?returnPath=/
, nghĩa là sẽ trẻ về trang gốc khi nhân.
Thử với giá trị bất kỳ của returnPath trong URL
Chuỗi này đã được đặt trong thuộc tính href, chứng tỏ nhân định trên là đúng
Sửa giá trị returnPath = javascript:alert(document.cookie)
trên URL
Nhấn nút Back
$() Selector Function: Hàm
$()
của jQuery cũng có thể là một điểm đích tiềm ẩn, cho phép tiêm các đối tượng độc hại vào DOM. Một lỗ hổng cổ điển là khi các trang web sử dụng selector này kết hợp với nguồnlocation.hash
để thực hiện các hoạt động như hoạt ảnh hoặc cuộn tự động đến một phần tử trên trang. Ví dụ:
Vì hash có thể được kiểm soát bởi người dùng, kẻ tấn công có thể tiêm một vector XSS vào selector của $(). Các phiên bản mới của JQuery đã vá lỗ hổng này bằng cách ngăn chặn việc tiêm HTML vào selector khi đầu vào bắt đầu bằng ký tự hash (#). Tuy nhiên, mã lỗi vẫn có thể tồn tại, bằng cách trigger hashchange
event mà không cần sự tương tác của người dùng.
Thuộc tính src sẽ trỏ đến trang mục tiêu với giá trị hash rông. Khi iframe được tải, một vector XSS được thêm vào hash, trigger hashchange
event
$(window).on('hashchange', function(){...
phần này lắng nghe sự kiện hashchange. In other words, when the location hash(#) in the URL is triggered, this code will be executed.
decodeURIComponent(window.location.hash.slice(1)):
decodeURIComponent được sử dụng để decode. slice(1) xóa ký tự # khỏi string.
var post = $('section.blog-list h2:contains(...)')
Trong phần này, tìm kiếm được thực hiện trong trang HTML. Các phần có thẻ h2 trong lớp “section.blog-list” được xác định và gán cho biến “post”. Ký hiệu # đã được xóa và nội dung được mã hóa URL đã được giải mã. Nội dung được tìm kiếm được tìm thấy và gán cho biến post x
if (post) post.get(0).scrollIntoView():
nếu biến post không trống, nghĩa là từ được tìm kiếm được tìm thấy, hàm scrollIntoView được sử dụng để đưa trang đến vị trí tìm thấy từ đó.
Có thể triggeer XSS với việc thêm vào sau URL (Bỏ /): #<img src=x onerror=alert(1)>
Payload trên sẽ kích hoạt alert vì trình chọn jquery $()
trước tiên sẽ cố gắng chọn (tìm) mục trên trang và khi không thành công (chuỗi không tồn tại trong ví dụ này), nó sẽ thêm phần tử.
Payload để giải quyết bài toán như sau (đặt trên exploit server và gửi tới victim):
DOM XSS trong AngularJS
Trong framework AngularJS, có thể thực thi JS mà không cần dấu ngoặc nhọn hoặc sự kiện. Khi trang web sử dụng thuộc tính ng-app
trong HTML element, nó sẽ được thực thi bởi AngularJS. AngularJS sẽ thực thi JavaScript trong {{}}
, điều này có thể xảy ra trực tiếp trong HTML hoặc bên trong các thuộc tính.
Giải pháp:
Điều tra mục tiêu bằng cách inspect từng trang
Có thể lợi dụng cơ chế phạm vi angularJS bằng cách sử dụng các đối tượng mặc định như , và để thực thi alert()
DOM XSS kết hợp với dữ liệu được reflect và lưu trữ
Một số lỗ hổng chỉ dựa trên DOM có thể chỉ xảy ra trong một trang duy nhất. Nếu một script đọc dữ liệu từ URL và ghi nó vào một điểm đến(sink) nguy hiểm, thì lỗ hổng đó hoàn toàn nằm phía client
Tuy nhiên, source không chỉ giới hạn ở dữ liệu mà trình duyệt cung cấp - chúng cũng có thể xuất phát từ trang web. Ví dụ, các trang web thường reflect các tham số URL trong HTML response, nguy cơ gây XSS/ DOM XSS
Trong một lõ hổng reflected DOM XSS, máy chủ xử lý dữ liệu từ request và phản hồi dữ liệu vào response. Dữ liệu đó có thể được đặng trong một duyệt chuỗi JS, hoặc một mục dữ liệu trong DOM (như trường form). Một script trên trang sau đó xử lý dữ liệu phản hồi này theo cách không an toàn, cuối cùng ghi nó vào một điểm đến(sink) nguy hiểm
Giải pháp:
Tìm kiếm với chuỗi bất kỳ, và chuỗi đã reflect trên tiêu đề trang kết quả
Inspect thành phần này.
Thẻ <h1> hiển thị chuỗi tìm kiếm được xử lý bởi <script> phía trên, đó là /resources/js/searchResults.js
Có thể xem file này qua Burp Proxy
Nhìn qua, có thể thấy script sử dụng eval(‘var searchResultsObj = ‘ + this.responseText) nhằm tạo một biến có tên searchResultsObj và gán cho nó giá trị của response
Khai thác hàm này bằng Burp Repeater với request GET /seach-results....
Vì kết quả ‘searchTerm’ nằm trong ngoặc kép, thử thêm dấu ngoặc kép vào cuối chuỗi cùng với hàm alert(): "-alert(1) (sử dụng "-" thay "+" vì "+" thường bị URL encode)
Trong response phần searchTerm hiển thị \ là ký tự thoát nhằm bỏ qua ký tự tiếp theo nhưng không chấm dứt searchTerm.
Nhưng khi sửa lại thành \"-alert(1)
Giờ " chèn vào đã chấm dứt chuỗi tìm kiếm và payload vẫn không hoạt động vì thừ dấu ". Cần đóng JavaScript thử công và comment phần còn lại bằng //
Payload sẽ là \"-alert(1)}//
Website cũng có thể chứa dữ liệu trên server và reflect nó đến nơi khác. Trong lỗ hổng store DOM XSS, server nhận dữ liệu từ request, lưu trữ dữ liệu đó và sau đó đưa dữ liệu vào response sau đó. Một script trong response chưa một sink xử lý dữ liệu theo cách không an toàn
Inspect phần comments của một bài đăng bất kỳ
Qua network, có thể xem nội dung file js đó
Chú ý có comment.author dữ liệu không bị xử lý , đông thời có sink là innerHTML
Tuy nhiên website có sử dụng hàm escapeHTML nhằm thay thế các ký tự '<' , '>' nhằm chống XSS
Tuy nhiên khi đối số đầu tiên là một chuỗi thì hàm chỉ thay thế làn xuất hiện đầu tiên. Payload sau hoạt động
Ngăn chặn
Tránh dữ liệu không đáng tin cậy: Không cho phép dữ liệu từ bất kỳ nguồn không đáng tin cậy nào được viết động vào tài liệu HTML.
Xác thực dữ liệu: Nếu không thể tránh khỏi việc xử lý dữ liệu từ nguồn không đáng tin cậy, hãy xác thực dữ liệu bằng cách sử dụng whilelist. Chỉ cho phép những dữ liệu đã được xác nhận là an toàn.
Làm sạch dữ liệu: Thực hiện việc làm sạch hoặc mã hóa dữ liệu trước khi chèn nó vào tài liệu HTML. Các phương pháp làm sạch có thể bao gồm:
Escaping JavaScript: Đối với dữ liệu được sử dụng trong các đoạn mã JavaScript, cần phải escaping các ký tự đặc biệt để ngăn chặn việc thực thi mã độc.
Mã hóa HTML: Mã hóa dữ liệu trước khi chèn vào nội dung HTML để tránh việc chèn mã JavaScript độc hại.
Mã hóa URL: Nếu dữ liệu được chèn vào URL, cần mã hóa URL để ngăn chặn việc tiêm mã độc qua các tham số URL.
Sử dụng các thư viện an toàn: Sử dụng các thư viện và công cụ JavaScript được thiết kế để bảo vệ chống lại các cuộc tấn công DOM-XSS, như các thư viện mã hóa và escaping nổi tiếng.
Rà soát mã nguồn: Thực hiện rà soát mã nguồn để phát hiện và khắc phục các điểm yếu trong việc xử lý dữ liệu, đặc biệt là những phần liên quan đến việc truyền dữ liệu từ nguồn không đáng tin cậy đến các hàm nguy hiểm.
Last updated