+11

Note 1: JWT và các loại tấn công nhắm vào JWT

Mayfest2023

✨Hôm nay trái gió trở trời tâm tình bất ổn thế là hay quên. ✨ ✨Bài viết chỉ mang tính chất note lại kiến thức ✨

JWT và cách thức xác thực

  • JWT (JSON Web Token) là một phương thức xác thực được sử dụng trong các ứng dụng web và di động. Khi một người dùng đăng nhập vào một ứng dụng, máy chủ sẽ tạo ra một JWT chứa thông tin về người dùng và ký số để xác thực tính hợp lệ của JWT. Sau đó, JWT này sẽ được gửi đến cho người dùng, và người dùng sẽ gửi nó lại với các yêu cầu được thực hiện trong ứng dụng.
  • Mỗi lần người dùng gửi yêu cầu, JWT sẽ được gửi đến máy chủ và được giải mã để trích xuất thông tin về người dùng. Máy chủ sẽ kiểm tra chữ ký của JWT để đảm bảo tính hợp lệ của nó. Nếu chữ ký hợp lệ, máy chủ sẽ trả về các dữ liệu hoặc thực hiện các hành động được yêu cầu.

JWT format

  • JWT gồm 3 phần header, payload và signature được mã hóa bằng base64 mỗi thành phần sẽ được ngăn cách bằng dấu chấm.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJjb25jYXR4YW5obGEiLCJleHAiOjEyMzEyMywibmFtZSI6ImJheWJpc2hhcmsiLCJzdWIiOiJjYXJsb3MiLCJyb2xlIjoiYmxvZ19hdXRob3IiLCJpYXQiOjEyMzEyM30=.SYZBPIBg2CRjXAJ8vCER0LAENjII1JakvNQoP-Hw6GG1zfl4JyngsZReIfqRvIAEi5L4HV0q79qGhQZvy9ZdxEJbwTxRs6Lb-fZTDpW6lKYNdMyjw45alSCZ1fypsMWz2mTpQzil0lOtps5Eiz7mM7M8gCweAGpI53JxduQOaB5HkT5gVrv9cKu9CsW5MS6ZbqYXpGyOG5ehoxqm8DL5tFYaW3lB50ELxi0KsuTKEbD0t5BCl0aCR2MBJWAbN-xeLwEenaqBiwPVvKixYleeDQiBEIylFdNNIMviKRgXiYuAvMziVPbwSgkZVHeEdF5MQP1Oe2Spac-6IfA
  • Cụ thể phần header là một đối tượng JSON chứa hai thông tin: loại token (type) và thuật toán mã hóa (algorithm) được sử dụng để mã hóa phần nội dung của token.
{
 "alg": "HS256",
 "typ": "JWT"
}
  • Phần payload là một đối tượng JSON chứa các thông tin xác thực và thông tin khác. Các thông tin này được mã hóa bằng cách sử dụng thuật toán đã được chỉ định trong phần header.
{
"iss":"concatxanhla",=> viết tắt của issuer là thông tin hệ thống tạo 
"exp":123123, => thời gian hết hạn của token
name":"baybishark",
"sub":"carlos",
"role":"blog_author",
"iat":123123 => thời gian tạo của token
}
  • Phần signatuer là phần cuối cùng của JWT, được tạo bằng cách kết hợp header, payload và một secret key để tạo ra một chuỗi chữ ký duy nhất. Chữ ký này được sử dụng để xác thực tính hợp lệ của token.HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret),

JWT vs JWS vs JWE

  • JWT được sử dụng để xác thực người dùng và truyền tải thông tin giữa các bên. JWS (JSON Web Signature) được sử dụng để xác thực tính toàn vẹn của dữ liệu và JWE (JSON Web Encryption) được sử dụng để bảo vệ dữ liệu truyền tải. Các chuẩn định dạng này có thể được kết hợp để đảm bảo tính toàn vẹn và bảo mật cho dữ liệu trong quá trình truyền tải.
  • image.png

Xác thực JWT

  1. Trên server, hãy tạo ra một khóa bí mật (secret key). Khóa bí mật này sẽ được sử dụng để tạo và xác thực các mã JWT.
  2. Khi người dùng đăng nhập hoặc thực hiện quá trình xác thực, server sẽ tạo ra một JWT và gửi về cho client. JWT này chứa thông tin xác thực của người dùng, như thông tin về người dùng và các quyền truy cập.
  3. Khi client gửi yêu cầu đến server, nó sẽ gửi JWT kèm theo trong phần tiêu đề (header) của yêu cầu. Thông thường, phần tiêu đề này có tên là "Authorization" và giá trị của nó là "Bearer [token]", trong đó [token] là chuỗi JWT.
  4. Trên server, khi nhận được yêu cầu từ client, bạn cần xác thực JWT để đảm bảo rằng nó là hợp lệ và chưa bị sửa đổi. Bạn có thể thực hiện các bước sau để xác thực JWT:
  5. Trích xuất mã JWT từ phần tiêu đề "Authorization" của yêu cầu.
  6. Sử dụng khóa bí mật đã được chia sẻ giữa client và server để giải mã mã JWT.
  7. Kiểm tra chữ ký đi kèm trong JWT để xác minh tính toàn vẹn của nó. Chữ ký được tạo bằng cách sử dụng thuật toán mã hóa với khóa bí mật đã được chia sẻ.
  8. Kiểm tra thời hạn (expiration) của JWT để đảm bảo rằng nó vẫn còn trong thời gian hợp lệ.
  9. Nếu JWT xác thực thành công, server có thể truy xuất thông tin từ JWT và tiếp tục xử lý yêu cầu của client.
  10. Nếu JWT không hợp lệ hoặc đã hết hạn, server có thể trả về mã phản hồi (response) phù hợp, chẳng hạn như mã lỗi 401 Unauthorized.

Các loại tấn công vào JWT.

Không verify JWT

  • Trong trường hợp này, DEV không thực hiện verify hoặc nhầm lẫn giữa việc sử dụng hàm decode để lấy giá trị từ payload thay vì sử dụng hàm verify.=> gãy
  • Cách tấn công trong trường hợp này chỉ việc chỉnh sửa lại trường payload thành giá trị mong muốn và dứt. image.png

Chấp nhận token với signature là none

  • Trường hợp này có thể thay đổi thuật toán là none và có thể chỉnh sửa thông tin payload thoải mái
  • image.png

Sử dụng key jwt yếu

  • Trong trường hợp này sử dụng hashcat để tiến hành brute secret key của jwt.
  • hashcat -a 0 -m 16500 <YOUR-JWT> /path/to/jwt.secrets.list => secrec list có thể sử dụng rockyou hoặc seclist hoặc đại loại một thứ gì đó tồn tại ở internet.

Kid issues

Tiêu đề của JWT có thể chứa tham số kid(ID khóa), giúp máy chủ xác định khóa nào sẽ sử dụng khi xác minh chữ ký, ví dụ sử dụng kid để trỏ đến một tệp cụ thể hoặc lấy từ DB ra, điều đó có thể chứa một số rủi ro sau.

  1. Tiết lộ key: Nếu xác nhận "kid" được sử dụng trong tiêu đề, kiểm tra thư mục web để tìm tệp đó hoặc một biến thể của tệp đó. Ví dụ: nếu "kid":"key/12345" thì hãy tìm /key/12345 và /key/12345.pem hoặc /.well-known/jwks.json trên thư mục gốc của web.
  2. Control kid để nó trỏ về một tệp rỗng, trên linux cách dễ nhất là trỏ về tệp /dev/null=> lúc này giá trị key sẽ là null thì nó lại quay về bài toán 1 chỉnh sửa phần header chỉnh giá trị và húp thôi ez.=> khi gen key phải tạo giá trị k bằng AA== hay là %00 đó => gen xong nhớ ký image.png
  3. SSRF=> sẽ như kiểu blind đoán tệp thôi "kid":"/dev/tcp/yourIP/yourPort"
  4. SQL injection, khi nó select kid từ db ra=> 1 là bypass bằng union 2 là húp theo hướng sqli.
  5. OS Injection cũng tương tự khi lấy kid bằng cách bỏ nó vào một command => fuzz.

Đấm vào jku

  • jku là viết tắt của JWK Set URL. Nếu mã thông báo sử dụng xác nhận quyền sở hữu Tiêu đề “jku” thì hãy kiểm tra URL được cung cấp. Điều này sẽ trỏ đến một URL chứa tệp JWKS chứa Khóa chung để xác minh mã thông báo. Giả mạo mã thông báo để trỏ giá trị jku đến một dịch vụ web mà bạn có thể theo dõi lưu lượng truy cập.
  1. Đầu tiên phải tạo key và lưu phía server, thường bị đấm là do xài RSA
  2. image.png
  3. example:
{
   "keys": [
       {
           "kty": "RSA",
           "e": "AQAB",
           "kid": "893d8f0b-061f-42c2-a4aa-5056e12b8ae7",
           "n": "yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9mk6GPM9gNN4Y_qTVX67WhsN3JvaFYw"
       }
   ]
}
  1. sau đó sign nó và tiến hành xác thực key đúng không
  2. image.png

jwk ký bằng khóa công khai

  • Tấn công này nhắm vào RS256 (RSA + SHA-256) bản chất của thuật toán sử dụng 2 cặp key để mã hóa và giải mã, tấn công vào nó thì dựa vào câu chuyện server tin người, Mình sẽ mã hóa bằng khóa riêng cho jwt và truyền khóa công khai nào nó xong ký lại, gửi xuống server, server nhận được thông tin thì đíu giải mã được nên đành lấy public của mình đã chèn vào để giải mã thế là jwt hợp lệ.
  • Các bước để exploit:
  1. Gen key=> RSA
  2. Đem public key vào jwt image.png
  3. Ký và húp image.png

Nhầm lẫn thuật toán

  • Để mã hóa JWT thì sử dụng RS256(mã hóa đối xứng) sử dụng cặp key để xác thực HS256(chỉ mỗi khóa secret)
  • Lỗi này xảy ra khi DEV nhầm lẫn thuật toán(cảm ơn các bạn dev đã cho chúng tôi một cơ hội việc làm) giữa RS256 và HS256, giả sử có đoạn code sau
function verify(token, secretOrPublicKey){
    algorithm = token.getAlgHeader();
    if(algorithm == "RS256"){
        // Use the provided key as an RSA public key
    } else if (algorithm == "HS256"){
        // Use the provided key as an HMAC secret key
    }
}
  • Như các bạn thấy đó, hàm verify sẽ check thuật toàn nhận vào, nếu server đang sử dụng RS256 để mã hóa jwt nhưng khi truyền vào bạn đổi thành HS256 thì lúc này thằng server sẽ biến khóa chung thành khóa riêng để mã hóa luôn.
  1. Bước 1 phải kiếm được thằng public key lưu ở server /jwks.jsonhoặc /.well-known/jwks.json còn ko thì cứ ffuf mà phang.
  2. image.png
  3. Coppy key cho vào tool để gen image.png
  4. Bước này là mã hóa key qua base64 image.png
  5. image.png
  6. Sau đó tạo key để ký.image.png
  7. Sử thông tin và ký bằng public key vừa gen và húp nhớ sửa thuật toán về HS256
  8. image.png Đấm vào thằng thứ 3 hay còn gọi là đấm chéo
  9. Có nghĩa là 2 thằng domain cùng sử dụng chung xác thực của 1 thằng thứ 3.
  10. Muốn đấm thằng 1 mà không có authen, thay vì đấm trực tiếp thì đấm qua thằng số 2 cùng sử dụng chung cách xác thực jwt từ thằng số 3.
  11. Sử dụng jwt được gen từ bên thứ 3 cho thằng số 2 rồi dùng nó đấm thằng 1, nếu bị thì húp.

Đang viết tiếp


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí