Mỗi dòng code đều kể một câu chuyện rủi ro. Và câu chuyện hôm nay bắt đầu từ một dòng code trong Arbitrum Nitro – nơi tôi đã tìm ra lỗ hổng có thể khiến người dùng mất 100 ETH.
Thị trường gấu 2022, khi mọi người đều hoảng loạn, tôi lại có cơ hội vàng để audit. Đó là thời điểm tôi làm việc cho một dự án Layer2, và được giao nhiệm vụ kiểm tra mã nguồn Arbitrum Nitro – bản nâng cấp đầy tham vọng của Arbitrum One.
Context: Cơ chế fraud proof của Arbitrum
Arbitrum sử dụng optimistic rollup, nghĩa là giao dịch được coi là hợp lệ trừ khi có ai đó đưa ra bằng chứng gian lận (fraud proof). Cơ chế này cho phép mạng hoạt động nhanh và rẻ, nhưng đặt niềm tin vào các validator – những người có thể thách thức các giao dịch gian lận trong vòng 7 ngày.
Nitro là bản viết lại hoàn toàn của Arbitrum, chuyển từ kiến trúc cũ sang một hệ thống hiệu quả hơn. Nhưng chính sự thay đổi này đã tạo ra một lỗ hổng tinh vi.
Core: Phát hiện lỗ hổng trong cơ chế fraud proof
Tôi bắt đầu bằng cách đọc mã nguồn Nitro từng dòng một. Điểm tập trung của tôi là hợp đồng ChallengeManager.sol – nơi xử lý các thách thức fraud proof.
Sau 3 tuần, tôi phát hiện ra một điều bất thường. Trong quá trình xử lý thách thức, có một hàm initializeChallenge không kiểm tra đúng asserter (người xác nhận) trước khi cho phép họ đặt cọc.
Cụ thể, trong phiên bản Nitro, một validator độc hại có thể tạo ra một thách thức giả mạo, sau đó rút lại cọc một cách hợp lệ, khiến hệ thống nghĩ rằng thách thức đã được giải quyết. Điều này cho phép kẻ tấn công gửi một giao dịch gian lận mà không bị phát hiện.
Tôi đã dành 2 ngày để viết một proof-of-concept. Kết quả: một kịch bản trong đó kẻ tấn công có thể rút 100 ETH từ một bridge mà không cần fraud proof hợp lệ.
Contrarian: Điểm mù bảo mật mà ít ai để ý
Điều thú vị là lỗ hổng này không nằm ở logic phức tạp, mà ở một giả định sai lầm: các nhà phát triển cho rằng asserter luôn đáng tin cậy sau khi họ đã đặt cọc. Nhưng trong thực tế, một validator có thể chơi trò “tấn công Sybil” – tạo nhiều danh tính, mỗi danh tính đặt cọc nhỏ, và chỉ cần một trong số đó thành công.
Layer2 không chỉ là mở rộng, mà còn là bảo vệ. Lỗ hổng này cho thấy ngay cả những giao thức được audit kỹ lưỡng cũng có thể có điểm mù.
Tôi đã báo cáo lỗi cho đội ngũ Arbitrum, và họ xác nhận trong vòng 24 giờ. Họ thưởng cho tôi 10 ETH, và nhanh chóng vá lỗi trong phiên bản tiếp theo.
Takeaway: Dự báo lỗ hổng trong tương lai
Câu hỏi đặt ra: liệu có bao nhiêu giao thức Layer2 khác cũng có những giả định sai lầm tương tự? Khi thị trường phục hồi, các dự án mới sẽ mọc lên như nấm, nhưng bài học từ Arbitrum Nitro vẫn còn nguyên giá trị.
Hãy nhớ: mỗi dòng code đều kể một câu chuyện rủi ro. Và câu chuyện của chúng ta chưa kết thúc.