

Lưu ý của biên tập viên: Bài viết này đến từPeckShield(ID:PeckShield), được in lại bởi Odaily với sự cho phép.
Lưu ý của biên tập viên: Bài viết này đến từ
Nhân viên bảo mật của PeckShield đã tích cực theo dõi vụ tấn công bZx và nhận thấy rằng vụ việc này là một cuộc tấn công nhằm vào thiết kế tính thanh khoản được chia sẻ và có thể kết hợp giữa các dự án DeFi, đặc biệt là trong các dự án DeFi có chức năng giao dịch và cho vay đòn bẩy, vấn đề này sẽ dễ bị khai thác hơn.
Figure 1: Five Arbitrage Steps in bZx Hack
Các chi tiết tấn công của lỗ hổng như sau:
Các chi tiết tấn công của lỗ hổng như sau:
Sự kiện tấn công này xảy ra vào 2020-02-15 09:38:57 giờ Bắc Kinh (chiều cao khối #9484688). Thông tin giao dịch của kẻ tấn công có thể được tìm thấy trên etherscan. Quá trình tấn công này có thể được chia thành năm bước sau:
Bước 1: Nhận tiền khả dụng với khoản vay nhanh
Figure 2: Flashloan Borrowing From dYdX
Mô tả hình ảnh
Sau bước đầu tiên, tài sản của kẻ tấn công trong bảng sau không có lợi ích gì vào lúc này:
Bước 2: Tích trữ WBTC tại chỗ
Figure 3: WBTC Hoarding From Compound
Mô tả hình ảnh
Sau bước này, chúng ta có thể thấy rằng tài sản do kẻ tấn công kiểm soát đã thay đổi, nhưng vẫn chưa có lợi ích gì vào thời điểm này:
tiêu đề phụ
Sử dụng chức năng giao dịch đòn bẩy của bZx, rút ngắn ETH để mua một lượng lớn WBTC. Các bước cụ thể là: kẻ tấn công gửi 1.300 ETH và gọi chức năng giao dịch đòn bẩy bZx, cụ thể là giao diện mintWithEther(), chức năng này sẽ tiếp tục gọi nội bộ giao diện marginTradeFromDeposit(). Tiếp theo, kẻ tấn công đã đổi 5.637,62 ETH thu được từ đòn bẩy gấp 5 lần của bZx thành 51,345576 WBTC thông qua KyberSwap. Xin lưu ý rằng rút ngắn ETH ở đây là 5 lần vay. Giao dịch này dẫn đến tỷ giá hối đoái WETH/WBTC tăng lên 109,8, gấp khoảng 3 lần tỷ giá hối đoái thông thường (~38,5 WETH/WBTC).
Figure 4: Margin Pumping With bZx (and Kyber + Uniswap)
Để hoàn thành giao dịch này, KyberSwap về cơ bản sẽ truy vấn dự trữ của nó và tìm tỷ giá hối đoái tốt nhất. Cuối cùng, chỉ Uniswap mới có thể cung cấp tính thanh khoản như vậy, vì vậy giao dịch này về cơ bản sẽ đẩy giá WBTC trong Uniswap lên gấp 3 lần.
Cần lưu ý rằng bước này thực hiện logic kiểm tra bảo mật bên trong hợp đồng, nhưng thực tế không xác minh giá trị khóa sau giao dịch. Tức là khi cuộc tấn công xảy ra, kiểm tra này không được kích hoạt và chúng tôi sẽ trình bày chi tiết các vấn đề trong hợp đồng này ở phần sau.
Sau bước này, chúng tôi nhận thấy những thay đổi sau liên quan đến tài sản do tin tặc kiểm soát. Tuy nhiên, vẫn không có lợi nhuận sau bước này.
Mô tả hình ảnh
Figure 5: WBTC Dumping With Uniswap
Bước 5: Thanh toán khoản vay nhanh
tiêu đề phụ
Bước 5: Thanh toán khoản vay nhanh
Sau bước này, chúng tôi đã tính toán lại các chi tiết nội dung sau. Kết quả cho thấy kẻ tấn công đã thu được 71 ETH thông qua cuộc tấn công này, cộng với hai vị trí bị khóa sau: Compound (+5.500weth/-112WBTC) và bZx (-4.337WETH/+51WBTC). Khóa bZx ở chế độ mặc định và khóa Compound có lãi. Rõ ràng, sau cuộc tấn công, kẻ tấn công đã bắt đầu trả Khoản nợ kép (112 BTC) để chuộc lại 5.500 WETH đã thế chấp. Vì khóa bZx đã được mặc định nên kẻ tấn công không còn quan tâm nữa.
Đề cập đến giá thị trường trung bình là 1WBTC=38,5WETH (1WETH=0,025BTC), nếu kẻ tấn công mua 112 WBTC theo giá thị trường, nó sẽ có giá khoảng 4.300 ETH. 112 WBTC được sử dụng để thanh toán khoản nợ của Compond và lấy lại tài sản thế chấp 5.500 ETH, do đó, tổng lợi nhuận của kẻ tấn công cuối cùng là 71 WETH +5.500 WETH -4.300 ETH=1.271 ETH, tổng cộng khoảng 355.880 USD (giá ETH hiện tại là 280 USD).
tiêu đề phụ
Phân tích lõi cứng: bZx có thể tránh các lỗi logic mã rủi ro
Từ các bước trước đó kẻ tấn công đã thực hiện trong hợp đồng, có thể thấy nguyên nhân cốt lõi của vấn đề là ở bước thứ ba, marginTradeFromDeposit() được gọi để bán khống các giao dịch ETH/WBTC bằng cách vay 1.300 ETH và thêm đòn bẩy gấp 5 lần , vì vậy chúng tôi xem xét thêm Mã hợp đồng nhận thấy rằng đây là "cơ hội chênh lệch giá có thể tránh được", nhưng do lỗi logic trong mã nên logic mã có thể được sử dụng để tránh rủi ro đã không có hiệu lực. Việc theo dõi mã cụ thể như sau:
Đầu tiên, marginTradeFromDeposit( ) gọi _borrowTokenAndUse( ). Ở đây, vì tài sản ký gửi được sử dụng cho giao dịch đòn bẩy, nên tham số thứ tư là đúng (dòng 840).
Trong _borrowTokenAndUse(), khi số tiềnIsADeposit là đúng, hãy gọi _getBorrowAmountAndRate( ) và lưu trữ số tiền mượn trong số tiền đã gửi[1] (dòng 1,348).
Tại dòng 1355, sendAmounts[6] được đặt thành sendAmounts[1] và _borrowTokenAndUseFinal( ) được gọi tại dòng 1370
Nhập hàm takeOrderFromiToken( ) của bZxContract qua giao diện IBZx.
bZxContract thuộc về một hợp đồng khác iTokens_loanOpeningFunctions Vì vậy, chúng tôi tiếp tục phân tích mã hợp đồng và tìm phán đoán logic chính trong hàm:
Trong dòng 148, bZx thực sự cố gắng sử dụng shouldLiquidate( ) của hợp đồng tiên tri để kiểm tra xem vị thế của giao dịch đòn bẩy này có lành mạnh hay không. Tuy nhiên, vì điều kiện đầu tiên (dòng 146-147) đã đúng, nên việc thực thi vẫn tiếp tục, bỏ qua phán đoán logic của shouldLiquidate().
