Kaito KID
VIP Members
-
02/07/2013
-
23
-
41 bài viết
Cross-site History Manipulation (XSHM)
[h=4]1. Tổng quan[/h][h=5]1.1 Same Origin Policy (SOP)[/h]SOP là cơ chế của các ngôn ngữ client-script (như Javascript) chỉ cho phép các trang trên một site truy cập đến nội dung của những trang khác trên cùng site đó. Những nội dung này có thể là mã HTML, cookie, history,…Cơ chế này cho phép một trang web có thể gửi các request đến các trang khác không cùng site đó nhưng không thể nhận được kết quả trả về. Ví dụ trang http://bkav.com.vn/a.aspx có thể chèn iframe: nhưng không thể biết nội dung bên trong của iframe này: document.getElementById(“google”).innerHTML là không thể.
Một số kỹ thuật khai thác client-side, điển hình là XSS giúp hacker vượt qua cơ chế này và lấy được cookie của người dùng.
[h=5]1.2 Browser History Object[/h]Cross-site History Manipulation dựa trên một đối tượng trong Javascript là history object. History object chứa thông tin về các trang web đã duyệt qua trong một browser tab. Mỗi browser tab là một đối tượng history riêng biệt.
Cơ chế SOP không cho ta biết được danh sách các URL trong history object, tuy vậy nó không chặn:
[h=4]2. Khai thác XSHM[/h][h=5]2.1 Khai thác XSHM sử dụng history.length[/h][h=6]2.1.1 Điều kiện[/h]Do cơ chế thực thi Javascript ở mỗi trình duyệt là khác nhau nên không phải tất cả các trình duyệt đều có thể bị khai thác XSHM. Để khai thác được XSHM dựa trên history.length, trình duyệt phải thỏa mãn 3 điều kiện cơ bản sau:
i. Cơ chế redirect: Nếu trang A chứa một redirect đến trang B thì chỉ trang B được lưu trong history object.
ii. Giả sử trình duyệt đang ở trang A (tức là A đang ở đầu danh sách trong history object), ta request đến A một lần nữa thì A không được lưu thêm vào history object.
iii. Nếu trang A chứa một iframe đến trang B thì B cũng được lưu trong history object.
Qua thử nghiệm trên một số các trình duyệt phổ biến thì chỉ có IE thỏa mãn cả ba điều kiện này. Do đó khai thác XSHM dựa trên history.length chỉ thực hiện trên IE.
[h=6]2.1.2 Kỹ thuật khai thác[/h]Nếu một trang web có điều kiện rẽ nhánh như sau:
Page A: If (CONDITION)
Redirect(Page B)
thì ta có thể kiểm tra được giá trị của CONDITION dựa vào history.length. Thuật toán như sau:
If (!isAuthenticated()) then
Redirect(“login.php”);
Kịch bản kiểm tra xem người dùng đã đăng nhập hay chưa như sau:
[h=5]2.2 Khai thác XSHM sử dụng history.go()[/h]Kỹ thuật này được sử dụng để kiểm tra xem người dùng đã duyệt qua những trang web nào. Hàm history.go(URL) chuyển hướng đến URL nếu nó đã tồn tại trong history object. Đoạn mã sau kiểm tra người dùng đã vào http://www.google.com.vn/ chưa dựa vào sự kiện onunload():
[h=4]3. Giải pháp[/h][h=5]3.1 Khắc phục cơ chế SOP ở các trình duyệt[/h]
if (!isAuthenticated())
Header(“Location: login.php?token=” + randomToken());
Kiểm tra token, nếu không hợp lệ thì redirect đến một trang khác
if(!isValid($_REQUEST[“token”]))
Header(“Location: home.php”);
Một số kỹ thuật khai thác client-side, điển hình là XSS giúp hacker vượt qua cơ chế này và lấy được cookie của người dùng.
[h=5]1.2 Browser History Object[/h]Cross-site History Manipulation dựa trên một đối tượng trong Javascript là history object. History object chứa thông tin về các trang web đã duyệt qua trong một browser tab. Mỗi browser tab là một đối tượng history riêng biệt.
Cơ chế SOP không cho ta biết được danh sách các URL trong history object, tuy vậy nó không chặn:
- Thuộc tính history.length: số các URL trong history object
- Phương thức history.go(URL): chuyển hướng đến URL nếu nó tồn tại trong history object
[h=4]2. Khai thác XSHM[/h][h=5]2.1 Khai thác XSHM sử dụng history.length[/h][h=6]2.1.1 Điều kiện[/h]Do cơ chế thực thi Javascript ở mỗi trình duyệt là khác nhau nên không phải tất cả các trình duyệt đều có thể bị khai thác XSHM. Để khai thác được XSHM dựa trên history.length, trình duyệt phải thỏa mãn 3 điều kiện cơ bản sau:
i. Cơ chế redirect: Nếu trang A chứa một redirect đến trang B thì chỉ trang B được lưu trong history object.
ii. Giả sử trình duyệt đang ở trang A (tức là A đang ở đầu danh sách trong history object), ta request đến A một lần nữa thì A không được lưu thêm vào history object.
iii. Nếu trang A chứa một iframe đến trang B thì B cũng được lưu trong history object.
Qua thử nghiệm trên một số các trình duyệt phổ biến thì chỉ có IE thỏa mãn cả ba điều kiện này. Do đó khai thác XSHM dựa trên history.length chỉ thực hiện trên IE.
Internet Explorer8.0 | Firefox3.5.9 | Chrome5.0.375.55 | Opera10.53 | Safari4.0.5 | |
i | √ | √ | √ | √ | √ |
ii | √ | √ | √ | √ | |
iii | √ | √ |
[h=6]2.1.2 Kỹ thuật khai thác[/h]Nếu một trang web có điều kiện rẽ nhánh như sau:
Page A: If (CONDITION)
Redirect(Page B)
thì ta có thể kiểm tra được giá trị của CONDITION dựa vào history.length. Thuật toán như sau:
- Tạo một iframe với giá trị src=Page B
- Thay đổi giá trị src của iframe thành Page A
- Nếu giá trị history.length trước và sau khi thay đổi src của iframe là như nhau à CONDITION = true
- Nếu CONDITION = false, điều kiện rẽ nhánh không được thực hiện, do vậy Page A sẽ được lưu vào history object, history.length tăng thêm 1
- Nếu CONDITION = true, điều kiện rẽ nhánh được thực hiện và trình duyệt sẽ chuyển đến Page B, bình thường do B trong iframe nên nó cũng được lưu vào history object nhưng lúc này, Page B đã ở trên đỉnh của history object nên nó không lưu thêm nữa. Biến history.length không đổi.
If (!isAuthenticated()) then
Redirect(“login.php”);
Kịch bản kiểm tra xem người dùng đã đăng nhập hay chưa như sau:
- Tạo một iframe với src = “login.php”
- Thay đổi src của iframe thành protected.php
- Nếu history.length không đổi, người dùng chưa đăng nhập
Cross-Site Login Detection var check = -1; function checkHistory() { if (check == -1) { check = history.length; document.getElementById(‘myframe’).src=’http://www.facebook.com/home.php’; } else { if (check == history.length) { alert(“Not authenticated!”); } else { alert(“Authenticated”); } } } |
[h=5]2.2 Khai thác XSHM sử dụng history.go()[/h]Kỹ thuật này được sử dụng để kiểm tra xem người dùng đã duyệt qua những trang web nào. Hàm history.go(URL) chuyển hướng đến URL nếu nó đã tồn tại trong history object. Đoạn mã sau kiểm tra người dùng đã vào http://www.google.com.vn/ chưa dựa vào sự kiện onunload():
onunload test function fnunload(){ alert(“unload”); } function check(){ history.go(‘http://www.google.com.vn/’) } setTimeout(“check()”, 1000); |
[h=4]3. Giải pháp[/h][h=5]3.1 Khắc phục cơ chế SOP ở các trình duyệt[/h]
- Biến history.length chỉ là số các URL đã duyệt qua trên cùng một site
- Phương thức history.go(URL) chỉ chuyển hướng đến URL cùng site
if (!isAuthenticated())
Header(“Location: login.php?token=” + randomToken());
Kiểm tra token, nếu không hợp lệ thì redirect đến một trang khác
if(!isValid($_REQUEST[“token”]))
Header(“Location: home.php”);