0
0
Lập trình
Sơn Tùng Lê
Sơn Tùng Lê103931498422911686980

Tấn công Algorithm Confusion trong JSON Web Tokens (JWT) - Phần 5

Đăng vào 3 tuần trước

• 4 phút đọc

IV. Tấn công Algorithm Confusion trong JWT

Tấn công Algorithm Confusion trong JSON Web Tokens (JWT) là một phương thức tấn công nhằm lợi dụng sự nhầm lẫn trong việc xác định thuật toán được sử dụng để ký và xác minh JWT. Đặc biệt, các lỗ hổng này đã được ghi nhận trong các CVE như CVE-2016-5431CVE-2016-10555. Trong phần này, chúng ta sẽ tìm hiểu về hai loại thuật toán chính trong JWT: thuật toán đối xứng và thuật toán bất đối xứng.

1. Thuật toán đối xứng và bất đối xứng trong JWT

Thuật toán đối xứng (Symmetric algorithms) sử dụng cùng một khóa cho cả quá trình ký và xác minh JWT. Một ví dụ phổ biến là HS256 (HMAC-SHA256), trong đó sử dụng HMAC để đảm bảo tính toàn vẹn của thông điệp. Với thuật toán này, cả server và client đều biết khóa bí mật.

python Copy
import jwt

# Tạo JWT bằng thuật toán HS256
payload = {'user_id': 123, 'username': 'john.doe'}
secret_key = 'my_secret_key'

jwt_token = jwt.encode(payload, secret_key, algorithm='HS256')
print('JWT:', jwt_token)

# Xác minh JWT bằng thuật toán HS256
try:
    decoded_token = jwt.decode(jwt_token, secret_key, algorithms=['HS256'])
    print('Decoded Token:', decoded_token)
except jwt.InvalidTokenError:
    print('Invalid Token')

Thuật toán bất đối xứng (Asymmetric algorithms) sử dụng một cặp khóa bao gồm khóa riêng và khóa công khai để thực hiện ký và xác minh JWT. Khi server tạo JWT, nó sẽ sử dụng khóa riêng để ký, và client sẽ sử dụng khóa công khai để xác minh.

Ví dụ với thuật toán RS256 (RSA-SHA256):

python Copy
import jwt

# Tạo JWT bằng thuật toán RS256
payload = {'user_id': 123, 'username': 'john.doe'}
private_key = open('private_key.pem').read()
public_key = open('public_key.pem').read()

jwt_token = jwt.encode(payload, private_key, algorithm='RS256')
print('JWT:', jwt_token)

# Xác minh JWT bằng thuật toán RS256
try:
    decoded_token = jwt.decode(jwt_token, public_key, algorithms=['RS256'])
    print('Decoded Token:', decoded_token)
except jwt.InvalidTokenError:
    print('Invalid Token')

Trong JWT, thuật toán được chỉ định trong phần header của token. Nếu thuật toán không được định nghĩa hoặc không được hỗ trợ, quá trình xác minh sẽ thất bại. Việc chọn thuật toán đúng là cần thiết để bảo vệ tính toàn vẹn và bảo mật của JWT.

2. Các sai sót dẫn đến lỗ hổng tấn công Algorithm Confusion

JWT cho phép việc sử dụng nhiều thuật toán khác nhau để ký và xác minh. Tuy nhiên, nếu không kiểm tra hoặc kiểm tra không chính xác thuật toán trong header của JWT, kẻ tấn công có thể khai thác lỗ hổng bằng cách thay đổi thuật toán được sử dụng.

Xem đoạn mã sau đây:

javascript Copy
function verify(token, secretOrPublicKey){
    algorithm = token.getAlgHeader();
    if(algorithm == "RS256"){
        // Sử dụng key cung cấp như một public key RSA
    } else if (algorithm == "HS256"){
        // Sử dụng key cung cấp như một secret key HMAC
    }
}

Đoạn mã trên cho phép xác thực JWT từ người dùng với cả hai thuật toán RS256HS256. Nếu ứng dụng lộ public key RSA, kẻ tấn công có thể chuyển đổi nó sang định dạng PEM và sử dụng mã hóa Base64 để vận dụng cho thuật toán đối xứng.

Người đọc có thể thử nghiệm kỹ thuật tấn công này trong bài lab JWT authentication bypass via algorithm confusion.

Sử dụng các công cụ quét, đơn giản có thể thấy ứng dụng có đường dẫn /jwks.json chứa danh sách các public keys.

json Copy
{
  "kty": "RSA",
  "e": "AQAB",
  "use": "sig",
  "kid": "8f5a0479-7077-4d1e-966d-68b5f6115e65",
  "alg": "RS256",
  "n": "yvto63Vh_UjvqS5RcmU4xvweFCWMSq-mAAOrvjotDl8KLYxk4ulK71MLhiKw_-9Vo_7nZPqcNidJju20Jj-GbZq0HeJ7A7dAGI4dCFwYuG18mMVJF-lM9ch2BjCjQyf3YwhshtrOvSwUEt6DIvR-lu9FdPTj3aMwch79TqiANkqatOpnqerLqNs9lJmERd0FxgIuSwc1U82DXrqXxLCIZEY97GdXppjs33lkDCY1oq209w56Z4abkAEY6sIapBRMP1R9IP_CV-ieAnwXOzYKMKyJ2udMMDoYv_4Znze-dgaQSA2Q_4gIxEZE6GbcMOp1wtGlIyx-FTW_eXh4BHMR6Q"
}

Sau khi đăng nhập và phát hiện JWT dùng thuật toán RS256, có thể dự đoán ứng dụng sẽ truy cập /jwks.json tìm public key tương ứng với kid để xác thực.

Bằng cách chuyển đổi public key từ RS256 sang dạng secret key cho HS256, người tấn công có thể dễ dàng thực hiện mã hóa để đạt được mục tiêu.

3. Thử thách CTF

Chúng tôi xin giới thiệu một thử thách CTF mô phỏng trường hợp trang web chỉ chấp nhận thuật toán bất đối xứng RS256, nhưng với public key yếu, cho phép kẻ tấn công tìm ra private key. Mã nguồn thử thách như sau:

python Copy
from flask import Flask, request
import jwt, time, os

app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24)

private_key = open('priv').read()
public_key = open('pub').read()
flag = open('flag.txt').read()

@app.route("/get_token")
def get_token():
    return jwt.encode({'admin': False, 'now': time.time()}, private_key, algorithm='RS256')

@app.route("/get_flag", methods=['POST'])
def get_flag():
  try:
    payload = jwt.decode(request.form['jwt'], public_key, algorithms=['RS256'])
    if payload['admin']:
      return flag
  except:
    return ":)"

@app.route("/")
def sauce():
  return "%s" % open(__file__).read()

if __name__ == "__main__":
  app.run(host="0.0.0.0", port=5000)

Hướng dẫn giải thử thách có thể tham khảo tại CTF Time.

Tài liệu tham khảo

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào