# What is JWT? Đơn giản là một chuỗi mã hóa base64, thông tin ban đầu là 1 chuỗi có dạng JSON object. ex: ``eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEzODY4OTkxMzEsImlzcyI6ImppcmE6MTU0ODk1OTUiLCJxc2giOiI4MDYzZmY0Y2ExZTQxZGY3YmM5MGM4YWI2ZDBmNjIwN2Q0OTFjZjZkYWQ3YzY2ZWE3OTdiNDYxNGI3MTkyMmU5IiwiaWF0IjoxMzg2ODk4OTUxfQ.uKqU9dTB6gKwG6jQCuXYAiMNdfNRw98Hw_IWuA5MaMo`` Cấu trúc của nó đơn giản chỉ là: ``<base64-encoded header>.<base64-encoded payload>.<base64-encoded signature>`` Các ``header object``, ``payload object`` và ``signature`` dưới định dạng JSON encode base64 và nối với nhau qua dấu ``.``. # Components of JWT Có 3 phần trong JWT được nối với nhau bằng dấu ``.``: - Header - Payload - Signature ### Header Header gồm hai phần chính: loại token (ở đây là JWT) và thuật toán dùng để mã hóa (Thường là HS256 hoặc RS256). ``` { "alg": "HS256", "typ": "JWT" } ``` ### Payload Nó chứa thông tin về người dùng và các thuộc tính thực thể bổ sung, được gọi là ``claims``. ``` { "iat":"1695023887", "exp":"1695025687", "email":"trong.kma@kma.vn", "isAdmin":true } ``` Trong đó ``iat`` và ``exp`` lần lượt là thời gian cấp và thời gian hết hạn của token ### Signature Chữ ký trong JWT là một chuỗi được mã hóa bởi header, payload cùng với một chuỗi ``secret`` theo nguyên tắc sau: ``` HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret) ``` Do bản thân ``Signature`` đã bao gồm cả ``header`` và ``payload`` nên ``Signature`` có thể dùng để kiểm tra tính toàn vẹn của dữ liệu khi truyền tải. Việc thay đổi ``header`` và ``payload`` dẫn đến phần chữ ký này không hợp lệ. # What is the bug? Attacker có thể giả mạo hoặc thay đổi chuỗi JWT để vượt qua các cơ chế xác thực, từ đó attacker có thể leak ra các thông tin của user. # Where do it occur in the web? Xảy ra khi cơ chế verify chữ ký kém hiệu quả, dễ giả mạo hoặc thay đổi. JWT thường nằm ở phần ``cookie``, ``Authorization`` của một trang web. # How to detect? Kiểm tra xem JWT token có chứa thông tin nào nhạy cảm hay không? Kiểm tra xem có thể giả mạo hoặc thay đổi chuỗi JWT token hay không? # How to identify? Phân tích nội dung của JWT token bằng cách decode base64 hoặc sử dụng [tool](https://jwt.io/). ![alt text](image.png) Xác định thuật toán mã hóa mà nó sử dụng: - HMAC là thuật toán mã hóa đối xứng, sử dụng ``secret key`` cho cả việc mã hóa và giải mã. - RSA là thuật toán mã hóa bất đối xứng cần 1 cặp ``public`` và ``private key``, ``private key`` dùng để ký và giải mã còn ``public key`` dùng để mã hóa và xác thực. Kiểm tra xem token đã được xác thực chưa hoặc có sử dụng ``none alg`` không. Trường hợp token sử dụng ``alg HS256``, có thể bruteforce ``secret key``, kiểm tra tham số ``kid`` có bị dính các lỗi như ``path traversal`` hay ``sql injection`` hay không. Trường hợp token sử dụng ``alg RS256``, có thể thực hiện tấn công qua các tham số như ``jku``, ``jwk`` và ``Algorithm confusion``. # How to exploit? Một số lỗ hổng thường xảy ra, có thể bị khai thác của JWT ### Failing to verify the signature Trường hợp dev chỉ ``decode`` mà không xác thực chữ kí, ta có thể thay đổi phần payload theo ý của mình với các công cụ như ``jwt editor (burp)`` hay [tool](https://jwt.io/). ``` { "alg": "HS256", "typ": "JWT" }. { "name": "John Doe", "user_name": "john.doe", "is_admin": false } ``` Ở đây ta có thể chỉnh sửa giá trị của ``is_admin`` thành ``true``. ### Allowing the None algorithm Thuật toán ``none`` chỉ ra rằng token chưa được ký, nếu thuật toán này được cho phép, ta có thể bỏ qua việc kiểm tra chữ ký bằng cách sử dụng nó. ``` { "alg": "HS256", "typ": "JWT" }. { "name": "John Doe", "user_name": "john.doe", "is_admin": true }. ``` Thay đổi thuật toán ``HS256`` thành ``None``. ### Using trivial secrets Nếu tạo token với ``secret`` quá dễ đoán thì attacker có thể bruteforce ``secret`` (đối với mã hóa đối xứng) từ đó tiến hành thay đổi payload. ### Attacks using the jwk header ``jwk`` tức là JSON web key, là 1 object đại diện cho ``public key``. Ta có thể tạo nó bằng extension ``JSON Web Tokens`` trong burp. ``` { "kid": "ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG", "typ": "JWT", "alg": "RS256", "jwk": { "kty": "RSA", "e": "AQAB", "kid": "ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG", "n": "yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9m" } } ``` Ta có thể nhúng ``public key`` của mình vừa tạo vào payload của token, thay đổi tham số ``kid`` sao cho trùng với tham số ``kid`` trong tham số ``jwk``. Điều này làm cho server sử dụng khóa công khai được chèn để xác thực chữ ký của token. ### Attacks using the jku header ``jku`` tức là JSON web key, tham số này chỉ ra nơi mà ứng dụng có thể tìm được ``public key``, và sẽ dùng ``key`` đó để xác thực. ``` { "alg": "RS256", "typ": "JWT", "jku":"https://exploit-0a41001f0467f58a84d89e4e01d90055.exploit-server.net/key.json" }. { "name": "John Doe", "user_name": "john.doe", "is_admin": false } ``` File key.json được chỉ định trong url: ![alt text](image-1.png) ### Attacks using the kid parameter Tham số ``kid`` thường dùng để lấy ``key`` từ database hoặc file hệ thống. Ứng dụng xác thực chữ ký thông qua ``key`` từ tham số ``kid``, có thể sinh ra các lỗi như RCE, SQLi, LFI. ``` { "kid": "../../path/to/file", "typ": "JWT", "alg": "HS256", "k": "asGsADas3421-dfh9DGN-AFDFDbasfd8-anfjkvc" } ``` ![alt text](<Untitled 2.png>) ``secret key`` là ``AA==`` tương đương với null. Nó sẽ dẫn vào một file để lấy ra ``key`` nhằm xác thực token. ### Confusion algorithm # How to prevent? Tiến hành verify JWT Token trên phía server để đảm bảo người dùng không thể thay đổi dữ liệu trái phép trong JWT Token. Tiến hành verify JWT Token trên phía server để đảm bảo luôn sử dụng thuật toán để verify token, không chấp nhận việc không sử dụng thuật toán. Để ngăn chặn việc tấn công Injecting self-signed JWTs thông qua tham số ``jwk``, chúng ta không nên chấp nhận ``public key`` được chỉ định bởi người dùng. không cho phép người dùng thêm tham số ``jku``. Whitelist tham số ``kid``. Update thư viện, sử dụng ``secret key`` mạnh.