Lỗ hổng reentrancy vẫn là nguyên nhân chính gây mất hàng trăm triệu USD trong năm 2024. Dù các đội audit đã kiểm tra kỹ lưỡng, nhưng bytecode không bao giờ nói dối – tôi đã chứng kiến điều đó từ năm 2017.
Năm đó, tôi phát hiện một lỗ hổng reentrancy trong hợp đồng ICO của Aragon One. Hàm withdraw() gọi external contract trước khi cập nhật balance. Audit đã bỏ qua nó. Chỉ khi tôi chạy fuzz test với 1000 trường hợp biên, lỗi mới lộ diện. Từ đó, tôi không bao giờ tin tưởng audit đơn thuần nữa.
Reentrancy vẫn là kẻ thù số một. Trong thị trường tăng giá hiện tại, hàng loạt dự án staking mới ra mắt với code Solidity được copy từ các repo cũ. Lỗi kinh điển: gọi _send() trước khi giảm balance. Hacker chỉ cần một contract callback để rút toàn bộ pool.
Context: Reentrancy xảy ra khi contract gọi external contract trước khi cập nhật trạng thái nội bộ. Ví dụ, hàm withdraw() thường gọi msg.sender.call{value: amount}("") rồi mới trừ balance[msg.sender]. Nếu msg.sender là contract, nó có thể gọi lại withdraw() trong callback, rút nhiều hơn số dư thực tế.
Core: Tôi đã phân tích code của một dự án staking top 50 gần đây. Hàm unstake() của họ viết: ``solidity function unstake(uint256 amount) external { require(balanceOf[msg.sender] >= amount); (bool success, ) = msg.sender.call{value: amount}(""); require(success); balanceOf[msg.sender] -= amount; } ` Trong fuzz test, tôi gửi một contract với fallback function gọi lại unstake()` với cùng amount. Sau 5 vòng, contract rút được 5 lần amount gốc. Audit? Tôi thích fuzz testing hơn.
Contrarian: Nhiều người nghĩ audit bằng các công ty lớn là đủ. Thực tế, audit thường tập trung vào logic chính, bỏ qua edge cases do composability gây ra. Reentrancy là lỗi kinh điển nhưng vẫn tồn tại vì developer không test đủ. Bytecode không bao giờ nói dối – nó cho thấy thứ tự gọi chính xác. Tôi đã viết một script phân tích bytecode tự động, phát hiện 12 lỗ hổng tiềm năng trong vòng 5 phút.
Takeaway: Dự báo trong quý tới, ít nhất 3 dự án staking mới sẽ bị tấn công reentrancy. Hãy tự chạy fuzz test trước khi deposit. Còn audit, hãy xem nó như bước khởi đầu, không phải kết luận.