#Blog_mùa_dịch
Lời đầu tiên vẫn là câu chào quen thuộc: "Chào tất cả các bạn đang đọc blog của mình, mình đã quay trở lại để viết bài rồi đây". Sau một thời gian lặn hơi sâu vì thực sự là dạo này đâu ra cái tính lười, rất lười viết blog, không được như những ngày nào năng nổ viết các thứ các thứ nữa, thì hôm nay mình quay lại viết một bài chia sẻ một chút ít kiến thức bé bỏng của mình để mùa dịch này mọi người ở nhà chống dịch đọc cho vui.
Ở NHÀ CHỐNG DỊCH, VIẾT BLOG DẬP DỊCH
Dịch mà như này mãi là tới công chuyện luôn đó các bạn.
I. Giới thiệu
Dạo này dịch dã quá ở nhà nhiều thời gian rảnh nên mình tham gia mấy chương trình bug bounty chơi cho vui, thì vô tình tìm được lỗi mà mình nghĩ là ở thời điểm hiện tại cũng đã ít ứng dụng có thể mắc phải. Cụ thể về lỗi như thế nào thì các bạn cùng đọc tiếp ngay dưới đây mình sẽ trình bày chi tiết rõ ràng nha.
Có thể tóm tắt qua các ý chính sau:
- Ứng dụng tồn tại lỗ hổng Stored XSS
- Ứng dụng lưu trữ jwt token không an toàn
=> Từ vấn đề trên có thể tạo một cuộc tấn công leo thang đặc quyền từ một tài khoản hạn chế quyền lên tài khoản admin full quyền.
II. Một số khái niệm
Trước tiên là về lỗ hổng XSS - đây là một lỗ hổng web phổ biến, thực sự là có rất nhiều tài liệu trên google nói về lỗ hổng này rồi nên mình sẽ không muốn nói dài dòng trong bài viết này nữa, nếu bạn chưa biết có thể tham khảo một số link như sau:
Access token
Access token là một chuỗi có thể là ngẫu nhiên, hoặc JWT token, ... dùng để xác thực người dùng và truy cập vào các API của một ứng dụng. Trong đây có một khái niệm là JWT token thì các bạn xem luôn khái niệm nhé.
JWT token
“A JSON Web Token (JWT) is a JSON object that is defined in RFC 7519 as a safe way to represent a set of information between two parties. The token is composed of a header, a payload, and a signature.”
— Mình tạm dịch: —
“JWT là một JSON object được định nghĩa trong chuẩn RFC 7519 như là một cách an toàn để trao đổi thông tin giữa hai bên. Và Token thì bao gồm một header, một payload và một chữ ký.”
=> Đoạn này mình trích từ blog của một người anh Trung Quan Dev, các bạn có thể vào đây để đọc và hiểu rõ hơn JWT. Hoặc có thể xem tài liệu trực tiếp tại trang chủ JWT.IO
JWT là viết tắt của JSON Web Tokens. JWT không khác gì so một chuỗi mã hóa base64. Bằng cách signing token, chúng đảm bảo rằng nội dung dữ liệu được mã hoá không bị thay đổi bởi bất kỳ cách nào. Để thực hiện điều này bằng cách xác minh secret key, và một thuật toán mã hoá. Trong trường hợp signature cung cấp không khớp với thông tin token đã tạo, chúng sẽ được xem như không hợp lệ
Mã JWT token gồm có ba phần, tất cả đều dưới dạng base64:
- HEADER: Thường chứa thời gian hết hạn của mã, thuật toán sử dụng và dữ liệu bổ sung.
- PAYLOAD: Chứa dữ liệu dưới dạng JSON
- VERTIFY SIGNATURE: Được tạo từ header và payload
header và payload được lưu trự ở dạng JSON trước khi sign. Mã xác thực cuối cùng là sự kết hợp của 2 đối tượng trên dưới dạng base64, được phân tách với nhau bằng dấu chấm. Vì vậy, mã JWT token sẽ có dạng:
header.payload.signature
Được rồi, sau khi đọc và tìm hiểu khái niệm về Acess token thì chúng ta đã biết là Access token dùng để xác thực - Authenticate các API đúng không nào?
Vậy câu hỏi đặt ra là access token phía client sẽ được lưu trữ ở đâu cho hiệu quả và an toàn. Có 3 cách thường dùng để lưu trữ JWT Tokens là LocalStorage, SessionStorage và Cookies, vậy thì trong 3 cách này chúng ta nên dùng cách nào để an toàn và cách nào thì sẽ không an toàn.
LocalStorage
Rất nhiều lập trình viên thường có xu hướng lưu trữ mã access token ở LocalStorage trên trình duyệt (browser).
Ưu điểm: Tiện lợi, vì đây là một tính năng hầu hết các trình duyệt đều hỗ trợ. Nếu ứng dụng web sử dụng API của bên thứ 3 thì không thể đặt Cookies cụ thể cho website của mình mà phải dùng tới LocalStorage.
Nhược điểm: Dễ bị tấn công XSS, chỉ cần một đoạn mã localStorage.get('token')
là có thể lấy được token đang lưu trữ trong LocalStorage rồi. Nếu ứng dụng tồn tại lỗ hổng XSS, kẻ tấn công sẽ lợi dụng để ăn cắp mã xác thực được lưu trữ tại LocalStorage và truy cập vào các API để chỉnh sửa, ăn cắp, ... các thông tin của kẻ bị tấn công.
SessionStorage
Giống LocalStorage, SessionStorage được truy cập bởi bất kì mã JavaScript nào được chạy trên cùng một domain của ứng dụng đó. Vì vậy, điều duy nhất thay đổi ở đây là, khi người dùng tắt trình duyệt, mã JWT cũng sẽ bị xoá và người dùng phải đăng nhập lại sau đó để tiếp tục sử dụng ứng dụng web/app của bạn.
Cookies
Ưu điểm: Nếu các flag httpOnly và secure được bật thì không thể truy cập cookie qua JavaScript, do đó nó không dễ bị tấn công XSS như localStorage. Điều này có nghĩa là, ngay cả khi hacker có thể chạy javascript (Có thể là từ một lỗ hổng XSS, ...) trên trang web của bạn, thì cũng không thể đọc các Access Token của bạn từ cookie.
Cookies tự động được gửi trong mọi yêu cầu HTTP đến máy chủ của ứng dụng web.
Nhược điểm: Có một số trường hợp cụ thể mà có thể không lưu trữ được access Token vào trong cookie.
Cookie có giới hạn kích thước là 4KB. Do đó, nếu sử dụng một access Token có kích thước lớn thì việc lưu trữ vào cookie chưa chắc là đúng đắn.
Có những trường hợp không thể chia sẻ cookie với máy chủ API hoặc API yêu cầu đặt Access Token vào trong Authorization Header. Trong trường hợp này, sẽ không thể sử dụng cookie để lưu trữ access Token.
III. Thực chiến một trường hợp trong thực tế
Như đầu bài mình đã nêu ra là "Từ lỗ hổng XSS tấn công leo thang đặc quyền và vấn đề của việc lưu trữ access token", lỗ hổng này được mình tìm ra của một ứng dụng đang sử dụng thực tế khi chơi bug bounty. Cụ thể như sau:
(Vì một số chính sách của một private program nên mình xin phép che hết các thông tin về ứng dụng, để lộ ra là tới công chuyện)
Ứng dụng mình tìm ra lỗi là một ứng dụng quản lý shop, có thể đăng ký một cái shop bán bất cứ thứ gì trên đó và bên trong nó có quản lý sản phẩm, quản lý thành viên, ... của shop lập ra. Trong ứng dụng này tồn tại lỗ hổng stored XSS ở chức năng thêm mới, cập nhật sản phẩm.
Trước tiên tạo tài khoản:
aaaaaa bbbbbb (admin - full permission)
- tài khoản tạo ra shop (Owner) nên có full quyền.Manh Den ( Products & catalog permission)
- Tài khoản được thêm vào chỉ có quyền quản lý (thêm, sửa, xóa) sản phẩm trong shop.
Access token được sử dụng để truy cập API được lưu trữ trong LocalStorage.
Bước 1: Đăng nhập vào tài khoản manh den
và chỉnh sửa hoặc thêm mới một sản phẩm bất kỳ.
Bước 2: Dùng burpsuite để intercept request gửi lên khi cập nhật sản phẩm
Bước 3: Tạo một http server port 8080
Bước 4: Inject mã javascript lấy localstorage với key ***-access-token
Bước 5: Khi admin bấm vào xem sản phẩm do tài khoản manh den
thêm, javasript đã inject sẽ được thực thi và gửi access token của aaaaaa bbbbbb (admin) về http server.
Bước 6: Sử dụng access token của aaaaaa bbbbbb (admin)
để privilege escalation full permission cho manh den
.
Kết quả: Tài khoản manh den
đã có full permission
IV. Kết luận
Vậy qua bài viết mình đã đưa ra được vấn đề của việc lưu trữ trữ access token, và có demo một trường hợp thực tế.
Mặc dù Cookies vẫn tồn tại nhiều khuyết điểm, nhưng nên ưu tiên sử dụng Cookies bất cứ khi nào có thể. Cả localStorage và cookie đều dễ bị tấn công XSS nhưng sẽ làm khó kẻ tấn công hơn khi sử dụng Cookie với cờ httpOnly.
Vậy là bài viết của mình đến đây là hết rồi, chúc bạn đọc những điều tốt đẹp. Các bạn nhớ đón đọc nhiều bài của mình ở blog: https://manhnv.com nhé.