Vào ngày 28 tháng 5 năm 2024, dự án Orion đã bị khai thác, gây ra thiệt hại khoảng 645.000 đô la tại thời điểm viết bài. Chúng ta hãy cùng xem xét chi tiết về cách thức cuộc tấn công này diễn ra.
Tổng quan
Địa chỉ của kẻ tấn công: https://bscscan.com/address/0x51177db1ff3b450007958447946a2eee388288d2
https://bscscan.com/address/0xf7a8c237ac04c1c3361851ea78e8f50b04c76152
Hợp đồng tấn công: https://bscscan.com/address/0xf8bfac82bdd7ac82d3aeec98b9e1e73579509db6
Hợp đồng nạn nhân:
https://bscscan.com/address/0xc662cea3d8d6660ca97fb9ff98122da69a199cd8
Giao dịch tấn công: https://bscscan.com/tx/0x660837a1640dd9cc0561ab7ff6c85325edebfa17d8b11a3bb94457ba6dcae18c
Chuẩn bị giao dịch:
Gửi tài sản vào
Khóa Stake
Đổi thưởng Atomic
Yêu cầu phát hành Stake
Đổi thưởng Atomic
Gửi tài sản vào
Khóa Stake
Đổi thưởng Atomic
Yêu cầu phát hành Stake
Đổi thưởng Atomic
ExchangeWithGenericSwap
triển khai một nền tảng trao đổi Token và Staking . Người dùng có thể gửi số dư để Stake hoặc chuyển bằng cách gọi các hàm lockStake
hoặc doRedeemAtomic
. Cụ thể, với hàm transfer, người dùng có thể hoãn các khoản nợ mà không ảnh hưởng đến số lượng token đang staking miễn là các khoản nợ không vượt quá tổng số dư.
Phân tích khai thác
Cuộc tấn công dường như đã tuân theo một mô hình đơn giản: kẻ tấn công đã tỉ mỉ thao túng mảng nợ phải trả của một tài khoản có địa chỉ 0xf7a8c237ac04c1c3361851ea78e8f50b04c76152
thông qua một loạt các giao dịch chuẩn bị.
Đầu tiên, anh ta gửi 10.000.000 ORN vào tài khoản và gọi hàm lockStake
để khóa và Stake các token, làm giảm giá trị assetBalances xuống 0.
Sau đó, anh ta sử dụng hàm redeemAtomic
để chuyển cùng một lượng ORN sang một tài khoản được kiểm soát khác có tên là B
Hàm này cho phép người dùng chịu trách nhiệm khi chuyển token thông qua cơ chế setLiability
. Khi người dùng chuyển một lượng token lớn hơn số dư tài sản của họ, hệ thống sẽ kiểm tra xem họ có đủ số dư và quyền hạn để gửi số lượng token cần thiết hay không. Nếu số dư vẫn nhỏ hơn 0, hệ thống sẽ đặt một khoản nợ cho người dùng đó. Cơ chế này được đảm bảo bởi kiểm tra của hệ thống, tính toán tổng số dư, bao gồm tài sản thế chấp và tài sản nợ.
Quay trở lại trường hợp thực tế, kẻ tấn công đã chuyển từ 0xf7a8c237ac04c1c3361851ea78e8f50b04c76152
, có số dư là 0. Do đó, hệ thống đã thiết lập khoản nợ cho địa chỉ này với số tiền là 10.000.000, khiến số dư của tài khoản trở thành -10.000.000.
Ở bước tiếp theo, kẻ tấn công gọi requestReleaseStake
để rút tất cả các token đã đặt cược và thêm các token đó vào số dư của 0xf7a8c237ac04c1c3361851ea78e8f50b04c76152
, đưa số dư tài sản của tài khoản này trở về 0. Sau đó, kẻ tấn công gọi redeemAtomic
một lần nữa để chuyển thêm 10.000.000 ORN đến địa chỉ B
Hành động này đã thao túng mảng debts của 0xf7a8c237ac04c1c3361851ea78e8f50b04c76152
để chứa hai phần tử có cùng giá trị: ["ORN", timestamp, 10,000,000]
.
Kẻ tấn công đã gửi thêm 20.000.000 ORN và lặp lại tất cả các bước một lần nữa. Tại thời điểm này, mảng nợ phải trả của 0xf7a8c237ac04c1c3361851ea78e8f50b04c76152
chứa ba phần tử: ["ORN", timestamp, 10,000,000]
, trong khi số dư tài sản của tài khoản này chỉ là -10.000.000.
Với một mảng nợ phải trả bị thao túng, kẻ tấn công đã sử dụng Khoản vay nhanh của PancakeSwap
để chuyển một số tiền lớn từ tài khoản B
trở lại 0xf7a8c237ac04c1c3361851ea78e8f50b04c76152
. Điều này khiến số dư thay đổi từ -10.000.000 thành khoảng 1,96 triệu. Kết hợp với thông tin trước đó, kẻ khai thác có thể vay nhiều tài sản hơn từ hệ thống so với số tiền chúng đáng được hưởng. Sau đó, kẻ tấn công đã sử dụng lại hàm redeemAtomic
để chuyển mã thông báo sang hợp đồng tấn công.
Như đã đề cập ở trên, có một cơ chế kiểm tra để đảm bảo rằng tổng số dư của người dùng (bao gồm số dư tài sản và số dư Staking ) trừ đi số dư nợ phải lớn hơn 0.
Đầu tiên, hệ thống tính toán số dư tài sản của người dùng thông qua hàm calcAssets
. Sau đó, hệ thống gọi calcLiabilities
để tính tổng tất cả các khoản nợ của người dùng và tính toán trạng thái cuối cùng bằng cách thực hiện phép trừ các giá trị đó. Chỉ có thể chấp nhận trạng thái POSITIVE
để chuyển mã thông báo.
Vì số dư tài sản của người dùng xấp xỉ 1,96 triệu và mảng nợ phải trả vẫn tồn tại, giá trị của liabilityValue
, được cho là âm, đã trở thành dương. Do đó, kẻ tấn công có thể bỏ qua cơ chế kiểm tra tình trạng khi vay các mã thông báo khác. Ngoài ra, bằng cách thao túng mảng nợ phải trả, kẻ tấn công có thể vay một giá trị lớn hơn của các mã thông báo.
Anh ta đã sử dụng mô hình tấn công này để chuyển và rút khoảng 645.000 đô la tiền ORN, BNB, BUSD-T và các loại tiền khác.
Sau khi khai thác, kẻ tấn công đã gửi lại khoản vay đã vay từ Khoản vay nhanhPancakeSwap
.
Nguyên nhân gốc rễ của lỗ hổng là nạn nhân không quản lý đúng nghĩa vụ. Nghĩa vụ phải được cập nhật khi số dư tài sản của người dùng thay đổi. Tuy nhiên, trong requestReleaseStake
, việc không cập nhật nghĩa vụ cho người dùng khi giải phóng tài sản là yếu tố chính góp phần vào khai thác này.
Ngoài ra, hệ thống phải kiểm tra xem người dùng có các nghĩa vụ khác nhau đối với cùng Token khi cập nhật hoặc xóa nghĩa vụ hay không.
Tóm lại, việc thiếu kiểm soát hiệu quả đối với các khoản nợ phải trả trong quá trình cập nhật số dư có thể dẫn đến sự khác biệt đáng kể về tài chính và sự không hài lòng của người dùng. Điều cần thiết là phải triển khai các biện pháp kiểm soát mạnh mẽ để theo dõi và quản lý mức nợ phải trả theo thời gian thực, đảm bảo rằng người dùng duy trì được số dư bền vững và ngăn ngừa sự bất ổn về tài chính trong nền tảng. Bằng cách giải quyết những mối quan ngại này, chúng tôi có thể thúc đẩy một môi trường an toàn và đáng tin cậy hơn cho tất cả người dùng.