

Vào ngày 8 tháng 12 năm 2023, OpenZeppelin chính thức đưa ra cảnh báo bảo mật quan trọng cho cộng đồng. Cảnh báo chỉ ra rằng khi sử dụng tiêu chuẩn ERC-2771 với các phương pháp giống Multicall trong tích hợp dự án, có thể có nguy cơ xảy ra các cuộc tấn công giả mạo địa chỉ tùy ý.
SharkTeam đã tiến hành phân tích kỹ thuật về sự cố này ngay lập tức và tóm tắt các biện pháp phòng ngừa an ninh. Chúng tôi hy vọng rằng các dự án tiếp theo có thể học hỏi từ điều này và cùng nhau xây dựng tuyến phòng thủ an ninh cho ngành công nghiệp blockchain.
1. Phân tích giao dịch tấn công
Vì có một loạt giao dịch tấn công liên quan đến lỗ hổng này nên chúng tôi đã chọn một trong các giao dịch tấn công để phân tích.
Địa chỉ của kẻ tấn công:
0xFDe0d1575Ed8E06FBf36256bcdfA1F359281455A
Giao dịch tấn công:
0xecdd111a60debfadc6533de30fb7f55dc5ceed01dfadd30e4a7ebdb416d2f6b6
Quá trình tấn công:
1. Đầu tiên. Kẻ tấn công (0xFDe0d157) lần đầu tiên sử dụng 5 WETH để đổi lấy khoảng 3, 455, 399, 346 TIME.
2. Sau đó, kẻ tấn công (0xFDe0d157) đã xây dựng một tham số calldata độc hại và gọi là hàm [Forwarder].execute.
3. Khi gọi hàm [Forwarder].execute, dữ liệu cuộc gọi độc hại đã kích hoạt chức năng multicall của hợp đồng TIME. Sau đó, dữ liệu cuộc gọi còn lại được sử dụng để kích hoạt chức năng ghi của hợp đồng TIME nhằm hủy mã thông báo TIME trong nhóm.
2. Phân tích lỗ hổng
Trước hết, cuộc tấn công này chủ yếu liên quan đến một số khía cạnh: ERC 2771, Multicall và dữ liệu cuộc gọi được xây dựng cẩn thận. Chúng tôi có thể tìm thấy phần kế thừa có liên quan từ hợp đồng mã thông báo TIME:
1. ERC 2771 cung cấp khả năng có một msg.sender ảo, cho phép người dùng ủy thác cho bên thứ ba [Forwarder] thực hiện các giao dịch để giảm chi phí gas. Khi một giao dịch được gửi, địa chỉ msg.sender sẽ được thêm vào calldata.
Hợp đồng mã thông báo 2.TIME kế thừa ERC2771Context. Khi [Forwarder] gọi hợp đồng, _msgSender() sẽ kiểm tra dữ liệu calldata và chuyển nó sang phải, cắt bớt 20 byte cuối cùng làm msg.sender dự kiến.
3.Multicall là phương thức chuyển đổi một lệnh gọi hàm thành nhiều hàm được gọi tuần tự trong cùng một hợp đồng. Nó chấp nhận một loạt các cuộc gọi do người dùng mã hóa và thực hiện hợp đồng của riêng mình. Hàm này lặp qua mảng cuộc gọi và thực hiện delegatecall() trên mỗi thao tác. Điều này cho phép người dùng kết hợp chuỗi hoạt động của riêng họ và thực hiện chúng một cách tuần tự trong cùng một giao dịch mà không cần phải xác định trước một số kết hợp hoạt động nhất định trong giao thức. Mục đích chính của nó cũng là để tiết kiệm gas.
4. Đối với dữ liệu cuộc gọi được xây dựng cẩn thận, kẻ tấn công đã gọi hàm [Forwarder].execute và truyền vào các tham số liên quan.
Chúng tôi định dạng giá trị dữ liệu phù hợp theo cách dễ đọc và nhận được:
Kẻ tấn công (0x FDe 0 d 157) lấy giá trị dữ liệu mới thông qua hoạt động bù đắp của dữ liệu cuộc gọi hiện tại và chuyển giá trị đó cho hàm multicall(bytes[]). 4 byte đầu tiên của dữ liệu mới là bộ chọn của hàm ghi (uint 256) và tham số số lượng là 6222725951000000000000000000000.
5. Trong hàm multicall(bytes[]), gọi hàm burn(uint 256) thông qua delegatecall. Trong dòng 0x 20, địa chỉ 0x760dc1e043d99394a10605b2fa08f123d60faf84 ban đầu được thêm vào cuối khi xây dựng calldata. Địa chỉ này tương ứng với nhóm thanh khoản TIME-ETH trên Uniswap v2, đây là thông điệp dự kiến được đề cập ở trên.
6. Tại sao msg.sender được đề cập vừa trở thành địa chỉ nhóm thanh khoản TIME-ETH? Lý do là msg.sender là địa chỉ hợp đồng [Forwarder] lúc đầu. Để xác định xem đó có phải là [Người chuyển tiếp] đáng tin cậy hay không, nếu đó là [Người chuyển tiếp] đáng tin cậy, hãy đặt msg.sender thành 20 byte cuối cùng của dữ liệu cuộc gọi.
3. Khuyến nghị về an toàn
Nguyên nhân sâu xa của cuộc tấn công này: Trong ERC-2771, [Forwarder] không được thiết kế cho multicall. Kẻ tấn công thêm các tham số có liên quan trong hàm _msgSender() vào lệnh gọi bên ngoài của multicall, tức là hàm [Forwarder].execute của sự kiện này. Trong hàm multicall, một số hàm cũng sẽ thêm các tham số liên quan vào _msgSender(), cho phép kẻ tấn công giả mạo _msgSender(). Do đó, kẻ tấn công có thể bắt chước các cuộc gọi đến các địa chỉ tùy ý bằng cách sử dụng multicall để gọi các chức năng liên quan. Cuối cùng, mã thông báo TIME trong nhóm sẽ bị hủy thông qua ủy quyền.
Để đối phó với sự cố này, có thể thực hiện các biện pháp giảm thiểu và phòng ngừa sau:
1. Sử dụng phiên bản mới sau khi sửa lỗi Phiên bản Multicall mới của OpenZeppelin có độ dài hậu tố ngữ cảnh là dữ liệu ERC 277 1context, dùng để xác định độ dài hậu tố ngữ cảnh dự kiến của ERC-2771. Do đó, mọi cuộc gọi từ [Người chuyển tiếp] đáng tin cậy sẽ được nhận dạng và điều chỉnh cho phù hợp với từng cuộc gọi chức năng phụ.
Sau đây là biểu đồ so sánh giữa phiên bản lỗi và phiên bản cập nhật:
2. Cấm mọi hợp đồng gọi multicall để ngăn chặn [Forwarder] sử dụng nó.Lấy ThirdWeb làm ví dụ, phương pháp này được so sánh với giải pháp của OpenZeppelin, OpenZeppelin vẫn cho phép multicall thông qua hợp đồng. Sau đây là biểu đồ so sánh các phiên bản lỗi liên quan và phiên bản cập nhật của ThirdWeb.
About Us
Tầm nhìn của SharkTeam là bảo vệ thế giới Web3. Nhóm bao gồm các chuyên gia bảo mật giàu kinh nghiệm và các nhà nghiên cứu cấp cao từ khắp nơi trên thế giới, những người thành thạo lý thuyết cơ bản về blockchain và hợp đồng thông minh. Nó cung cấp các dịch vụ bao gồm phân tích dữ liệu lớn trên chuỗi, cảnh báo rủi ro trên chuỗi, kiểm toán hợp đồng thông minh, phục hồi tài sản tiền điện tử và các dịch vụ khác, đồng thời đã xây dựng nền tảng cảnh báo rủi ro và phân tích dữ liệu lớn trên chuỗi ChainAegis. phân tích biểu đồ chuyên sâu và có thể chống lại Mối đe dọa liên tục nâng cao (APT) một cách hiệu quả trong thế giới Web3. Nó đã thiết lập mối quan hệ hợp tác lâu dài với những người chơi chủ chốt trong các lĩnh vực khác nhau của hệ sinh thái Web3, như Polkadot, Moonbeam, Polygon, Sui, OKX, imToken, ChainIDE, v.v.
Trang web chính thức:https://www.sharkteam.org
Twitter:https://twitter.com/sharkteamorg
