Authentication vulnerability - Lỗ hổng xác thực (phần 4)
V. Một số lỗ hổng xác thực khác
1. Tổng quan
Bên cạnh các lỗ hổng trong xác thực bằng mật khẩu, xác thực qua phương thức 2FA, chúng ta còn có thể khai thác các lỗ hỏng dựa trên một số tính năng khác trong quá trình xác thực.
Đa phần các ứng dụng web đều có những tính năng hỗ trợ thêm trong quá trình đăng nhập của người dùng, cho phép người dùng có thể dễ dàng hơn trong việc quan lí tài khoản của họ. Những điều này đểu được tạo ra với mong muốn mang lại sự tiện lợi và hướng đến người dùng, tuy nhiên nó cũng có thể trở thành các mục tiêu bị tấn công.
2. Tấn công cookie ghi nhớ đăng nhập (cookie stay-logged-in)
Một trong những chức năng hỗ trợ người dùng thường thấy là chức năng ghi nhớ đăng nhập. Sau lần xác thực thành công đầu tiên, đến những lần tiếp theo người dùng truy cập lại trang web / ứng dụng đó sẽ không cần thực hiện xác thực nữa, tránh người dùng phiền phức khi phải đăng nhập lại nhiều lần.
Chức năng này thường được người dùng lựa chọn sử dụng hoặc không. Khi người dùng yêu cầu chức năng này, nó thường được lưu trữ trong một biến cookie. Lúc này biến cookie này sẽ đóng vai trò như một lệnh bài tối cao, có thể trực tiếp vượt qua quá trình xác thực từ hệ thống. Lệnh bài có quyền lực như vậy sẽ thường trở thành mục tiêu tấn công của kẻ xấu. Đối với cơ chế mã hóa không đủ độ chắc chắn, sẽ dễ dàng bị nắm bắt cơ chế mã hóa bởi kẻ tấn công có thể suy luận từ chính cookie tương ứng với tài khoản của họ.
Phân tích lab Brute-forcing a stay-logged-in cookie
Ở tình huống này chúng ta được cung cập một tài khoản hợp lệ (dùng cho việc phân cách tạo thành của cookie ghi nhớ đăng nhập) và được biết username của victim là carlos
. Chúng ta cần tấn công cơ chế ghi nhớ đăng nhập này để truy cập vào người dùng carlos
.
Đăng nhập tài khoản hợp lệ wiener:peter
cùng với tính năng Stay logged in.
Hệ thống xác nhận việc ghi nhớ đăng nhập bằng giá trị cookie: stay-logged-in=d2llbmVyOjUxZGMzMGRkYzQ3M2Q0M2E2MDExZTllYmJhNmNhNzcw
Thử phân tích giá trị cookie này được mã hóa ra sao nào. Thú thật với các bạn rằng ngay khi nhìn thấy chuỗi kí tự này tôi đã nghĩ ngay tới Base64 (Tìm hiểu Thuật toán mã hóa Base64). Làm sao để biết ư, chắc là kinh nghiệm )) Vậy thì, khi không "đoán" được phương thức mã hóa của nó, chúng ta phải làm sao? Dùng phương pháp brute force tất cả các phép toán mã hóa chẳng? Không, tôi mong rằng các bạn đừng bị tấn công brute force làm cho tẩu hỏa nhập ma, hehe. Có một số trang web có thể giúp ta phát hiện khá chính xác phương thức mã hóa của những chuỗi kí tự lằng nhằng này. Ở đây tôi muốn giới thiệu với các bạn trang Cyber chef. Trang này có phải hiệu quả nhất không, tôi cũng không rõ, đơn giản tôi giới thiệu vì tôi hay dùng nó, trên Google còn có rất nhiều các trang khác đợi các bạn khám phá và review lại giùm tôi nhé! Dán đoạn mã vào ô Input, và kéo thả tùy chọn Magic, khi đó tại ô Output ta thu được kết quả:
Ầu, sau khi decode bằng Base64 thì nó trở thành:
wiener:51dc30ddc473d43a6011e9ebba6ca770
Định dạng này khá quen thuộc nhỉ, chắc các bạn cũng đoán được rằng 51dc30ddc473d43a6011e9ebba6ca770
kia khả năng lớn là mật khẩu của wiener sau khi được mã hóa bằng cách nào đó. Lúc này, dùng trang web này sẽ không tìm ra cách mã hóa nữa (hoặc có thể nhưng tôi chưa biết cách thực hiện). Chúng ta cần suy luận một chút thôi:
- Đầu tiên, khả năng lớn
51dc30ddc473d43a6011e9ebba6ca770
là một dạng mã hóa cho mật khẩu (Do định dạng cookieX:Y
). - Quan sát các kí tự tạo thành: được tạo thành từ các chữ số 0-9 và các chữ cái thường từ a đến e.
- Độ dài bằng đúng 32 kí tự (128 bit nếu mỗi kí tự sử dùng 4 bit mã hóa)
Từ những điều trên ta có thể suy đoán khả năng lớn đây là dạng mã hóa MD5 (Tìm hiểu Thuật toán mã hóa MD5). Chúng ta có thể kiểm tra nó bằng một số trang web MD5 decode.
Như vậy chúng ta đã hiểu cơ chế tạo ra cookie ghi nhớ đăng nhập của hệ thống, nên có thể thực hiện tấn công brute force cookie này theo đúng định dạng mã hóa trên.
- Cách 1: Tự túc là hạnh phúc. Các bạn có thể tự code một danh sách tấn công theo cơ chế mã hóa trên. Ở đây tôi sử dụng Python
# thư viện hashlib phục vụ cho thuật toán mã hóa MD5
# thư viên base64 phục vụ thuật toán mã hóa Base64
import hashlib
import base64
username = 'carlos'
password_list = ['password1', 'password2'] # danh sách mật khẩu
for password in password_list:
password = password.encode()
# mã hóa password bằng MD5
password = hashlib.md5(password).hexdigest()
# ghép thành dạng x:y
cookie = username + ':' + password
# mã hóa cookie bằng Base64
cookie = base64.b64encode(cookie.encode()).decode()
print(cookie)
Khi thu được danh sách cookie, thực hiện brute force tương tự các lab trước.
- Cách 2: Sử dụng chức năng Burp Suite tự động cơ chế mã hóa.
Gửi request tới Intruder
Thêm danh sách mật khẩu như bình thường:
Chọn Add trong mục Payload Proccessing, chọn Hash và MD5 để mã hóa password trước:
Tiếp theo, thêm tiền tố carlos:
(lưu ý có dấu :
):
Cuối cùng, thực hiện mã hóa Base64:
Bắt đầu tấn công nào!
Request 53 cho ta tài khoản victim: carlos:ranger
Sử dụng Show response in browser sẽ truy cập được vào tài khoản của carlos:
Ngoài cách brute force cookie trên, kẻ tấn công còn có thể tận dụng lỗ hổng XSS để lấy cắp giá trị cookie này. Với lỗ hổng Cross site scripting thì họ cũng không cần quan tâm tới cách hệ thống mã hóa, mà đơn giản họ chỉ cần lấy được giá trị cookie đó. Tuy nhiên, nếu như cơ chế mã hóa của hệ thống không đủ mạnh, và trong cookie ghi nhớ đăng nhập có sử dụng tới những thông tin nhảy cảm của người dùng như mật khẩu (chẳng hạn với cách mã hóa ở lab trên) thì kẻ tấn công sau khi lấy được cookie nạn nhân có thể thực hiện giải mã và sử dụng lại nhiều lần tài khoản của họ. Điều này sẽ được phân tích rõ hơn ở bài viết riêng về XSS.
3. Khai thác tính năng Resetting users password - đặt lại mật khẩu
Bên cạnh sự nỗ lực ngăn chặn các cuộc tấn công của bên cung cấp dịch vụ, bản thân người dùng cũng cần có những biện pháp bảo vệ tài khoản và thông tin của họ. Để đăng nhập vào tài khoản của mình, thì người dùng ít nhất cần tự ghi nhớ tên đăng nhập và mật khẩu của họ. Tuy nhiên, con người không thể có bộ nhớ "bất diệt" như máy móc, nên trong nhiều trường hợp khác nhau, người dùng có thể quên mất, hoặc đánh mất mật khẩu của họ (Đối với những trường hợp quên cả tài khoản, mật khẩu, số điện thoại, email xác nhận thì tôi không kể đến). Tất nhiên các nhà cung cấp dịch vụ đã lường trước trường hợp này. Bởi vậy, những người dùng thường có thể sử dụng chức năng "Quên mật khẩu" để lấy lại mật khẩu của họ.
Ví dụ: người dùng có thể lấy lại hoặc đặt lại mật khẩu của họ thông qua xác nhận họ chính là chủ sở hữu của số điện thoại hoặc email đại diện cho tài khoản đó. Thông thông, hệ thống sẽ gửi tới số điện thoại của họ một mã code dạng 2FA để họ xác nhận, hoặc gửi một đường link xác thực danh tính vào email của họ.
Có phải các bạn cũng nhận ra rằng, có thể sử dụng kiểu tấn công giống các lab tấn công mã xác thực hai bước phải không? Vì về bản chất cơ chế hoạt động của tính năng quên mật khẩu khá giống tính năng xác thực 2FA.
Để bạn đọc dễ hình dung hơn, tôi sẽ lầy một ví dụ đường link đặt lại mật khẩu sẽ có dạng như sau:
http://vulnerable-website.com/reset-password?token=a0ba0d1cb3b63d13822572fcff1a241895d893f659164d4cc550b421ebdd48a8
Dựa vào giá trị token
nhận được từ yêu cầu phía người dùng, hệ thống sẽ xác nhận đây có phải một token
hợp lệ hay không, rồi kiểm tra nó tương ứng với người dùng nào để thực hiện cung cấp chức năng cho họ.
Các trang web thường không trực tiếp gửi lại mật khẩu cũ cho người dùng khi người dùng yêu cầu lấy lại mật khẩu do có thể đó chính là kẻ tấn công giả mạo. Các mã xác thực hoặc đường link đặt lại mật khẩu gửi cho người dùng cần cài đặt để chỉ có hiệu lực trong một khoảng thời gian nhất định, nếu không sẽ có thể bị đánh cắp bởi kẻ tấn công. Ngoài ra, do kẻ tấn công cũng đóng vai trò là người dùng, nên những đường link đó cũng cần ở định dạng "không thể giả mạo được". Bởi vì mỗi đường link sẽ tương ứng với một người dùng duy nhất, nếu có thể dễ dàng bị phân tích ra sự liên hệ giữa đường link đặt lại mật khẩu và người dùng, kẻ tấn công có thể dễ dàng làm giả một đường link và đánh lừa hệ thống.
Phân tích lab Password reset broken logic
Chúng ta được cung cấp một tài khoản hợp lệ wiener:peter
và đã biết username của victim. Để giải quyết lab này, chúng ta cần khai thác tính năng đặt lại mật khẩu để truy cập tài khoản của carlos.
Sử dụng tính năng quên mật khẩu với username wiener
:
Chúng ta được cung cấp một đường link đặt lại mật khẩu tại Email client:
Truy cập link đặt lại mật khẩu, quan sát request qua Burp Suite:
Chúng ta thấy tại request này, client đã gửi tới server các giá trị temp-forgot-password-token
, username
, new-password-1
, new-password-2
qua phương thức POST
.
Từ các tham số này, chúng ta có thể dự đoán hệ thống xác thực yêu cầu đặt lại mật khẩu bằng tham số temp-forgot-password-token
(token được gửi cho tài khoản mail yêu cầu đặt lại mật khẩu) và xác thực danh tính người dùng cần đặt lại mật khẩu qua tham số username
, sau đó hai tham số new-password-1
và new-password-2
tương ứng là mật khẩu mới và xác nhận mật khẩu mới.
Do việc xác nhận đặt lại mật khẩu và danh tính người dùng cần đặt lại mật khẩu tương ứng với hai tham số khác nhau, không "ràng buộc" vào nhau. Nên chúng ta có thể thay đổi giá trị username
và đặt lại mật khẩu cho nạn nhân bất kì!
Đăng nhập với tài khoản carlos:1
và thành công:
Qua tình huống trên, chắc hẳn các bạn cũng đã phần nào hình dung được cách thức hoạt động của tính năng đặt lại mật khẩu qua đường link. Sử dụng phương thức này, hệ thống luôn mong muốn rằng đường link đặt lại mật khẩu sẽ được chuyển đến chính xác người dùng. Đây cũng là yêu tố thường được kẻ tấn công chú ý và nhắm tới.
Quay lại khoảnh khắc hệ thống yêu cầu cung cấp tên người dùng bị quên mật khẩu trong lab Password reset broken logic:
Thay vì cung cấp wiener
, nếu chúng ta yêu cầu đặt lại mật khẩu cho carlos
thì sao? Đúng vậy, email của carlos
sẽ nhận được mail chứa đường link đặt lại mật khẩu, điều chúng ta mong muốn là làm sao mail đó sẽ được chuyển vào Email client của chúng ta phải không? Điều này có thể được khai thác do tính bất cẩn của người dùng thường click vào những link lạ mà chưa chú ý tới hậu quả, khi đó chúng ta sẽ kiểm soát hoàn toàn tính năng đặt lại mật khẩu cho tài khoản nạn nhân!
Phân tích lab Password reset poisoning via middleware
Chúng ta biết rằng người dùng carlos
sẽ bất cẩn click vào link được gửi tới Email client của anh ấy. Để giải quyết bài này, chúng ta cần khai thác lỗ hổng trong tính năng đặt lại mật khẩu để lấy được token đặt lại mật khẩu của victim carlos
. Hệ thống cung cấp một exploit server dùng để lấy các dữ liệu thông tin từ victim.
Giống với lab Password reset broken logic, chúng ta có thể cung cấp tài khoản bất kì để hệ thống gửi đường link đặt lại mật khẩu cho tài khoản đó. Theo đúng kịch bản, carlos
sẽ click vào link đặt lại mật khẩu đó và "forward" tới exploit server của chúng ta. Như vậy, vấn đề cần giải quyết ở đây là làm sao khi carlos
click vào đường dẫn đó, exploit server của chúng ta sẽ nhận được dữ liệu của anh ấy? Đối với các bạn quen thuộc các HTTP Headers chắc hẳn đã nghĩ tới X-Forwarded-Host. Đúng vậy, X-Forwarded-Host khai báo tên máy chủ được sử dụng để truy cập web trên trình duyệt.
Thử nghiệm cuộc tấn công trên chính Email client của wiener
.
Bắt request qua Burp Suite thao tác gửi username cần đặt lại mật khẩu cho hệ thống, thêm header X-Forwarded-Host với giá trị là exploit server của chúng ta:
Lúc này, email client của wiener
nhận được một đường link đặt lại mật khẩu:
Nếu chúng ta bất cẩn click vào đường link này, hệ thống sẽ forward các dữ liệu tới exploit server do giá trị header X-Forwarded-Host.
(giao diện người dùng thấy)
(Exploit server nhận được dữ liệu victim)
Cuộc tấn công thử nghiệm thành công! Đến lượt carlos
thôi!
Thêm header X-Forwarded-Host và đặt lại mật khẩu "giúp" carlos
:
Sau đó, chúng ta nhận được giá trị temp-forgot-password-token
của tài khoản carlos
qua Access log.
Bây giờ có thể dễ dàng cập nhật mật khẩu của carlos
:
Truy cập tài khoản carlos:1
và lab được giải quyết:
Bên cạnh tính năng quên mật khẩu, các nhà cung cấp cũng cho phép người dùng đổi mật khẩu mật khẩu của họ.
Để ý rằng khi người dùng sử dụng tính năng thay đổi mật khẩu, hệ thống thường yêu cầu họ nhập mật khẩu hiện tại để xác nhận danh tính, và hai tham số là mật khẩu mới và xác nhận mật khẩu mới.
Tất nhiên, hệ thống luôn mong muốn chúng ta sẽ nhập New password
và Confirm new password
có giá trị giống nhau. Nếu chúng ta cố tình cho hai tham số này các giá trị khác nhau thì sao? Kết hợp với giá trị Current password
, nếu lập trình viên không cẩn thận trong việc đưa ra các thống báo cho người dùng, một số thông tin nhạy cảm có thể bị lợi dụng.
Với cơ chế hoạt động này, kẻ tấn công có thể thực hiện tấn công Brute force trong giá trị Current password
để tìm kiếm mật khẩu đúng của người dùng dựa vào các thống báo chứa thông tin nhạy cảm và việc hệ thống không ngăn chặn hành vi tấn công vét cạn.
Phân tích lab Password brute-force via password change
Chúng ta được cung cấp 1 tài khoản hợp lệ wiener:peter
, username victim và 1 danh sách passwords chứa password đúng của carlos
.
Đăng nhập tài khoản wiener:peter
và thử đổi mật khẩu, nếu current password nhập đúng, password mới và password confirm không giống nhau thì hệ thống trả về thông báo New passwords do not match.
Nếu current password nhập sai, password mới và password confirm giống nhau thì hệ thống trả về trang login.
Nếu current password nhập sai, password mới và password confirm không giống nhau thì hệ thống trả về thông báo Current password is incorrect.
Như vậy chúng ta có thể cố tình nhập password mới và password confirm không giống nhau, sử dụng tham số current password thực hiện tấn công Brute force với danh sách password được cung cấp.
Request 37 cho ta tài khoản victim là carlos:zxcvbnm
.
Đăng nhập và lab được giải quyết!
Các tài liệu tham khảo
- https://portswigger.net/web-security/authentication
- https://en.wikipedia.org/wiki/MD5
- https://www.geeksforgeeks.org/http-header-x-forwarded-host/
©️ Tác giả: Lê Ngọc Hoa từ Viblo
All rights reserved