Ba năm trước, trong một đêm tháng Mười một lạnh giá ở Riyadh, tôi đang đào sâu vào mã nguồn của Arbitrum Nitro. Lúc đó thị trường đang trong giai đoạn giảm sâu nhất của chu kỳ 2022, nhiều người bỏ cuộc, nhưng tôi lại thấy đây là thời điểm vàng để kiểm tra an ninh. Mỗi dòng code đều kể một câu chuyện rủi ro – và dòng code tôi nhìn thấy đêm đó đã kể một câu chuyện có thể khiến người dùng mất 100 ETH.
Bối cảnh: Tại sao Fraud Proof lại quan trọng?
Arbitrum Nitro là bản nâng cấp lớn của Arbitrum One, sử dụng cơ chế optimistic rollup. Khác với zk-rollup dùng bằng chứng toán học, optimistic rollup giả định tất cả giao dịch đều hợp lệ, và cho phép bất kỳ ai gửi fraud proof (bằng chứng gian lận) trong vòng 7 ngày để thách thức một giao dịch sai. Nếu fraud proof thành công, sequencer bị phạt và trạng thái được hoàn nguyên. Cơ chế này là trái tim của bảo mật Arbitrum. Nhưng trái tim cũng có thể bị đâm thủng.
Điều tôi tìm thấy trong mã nguồn Nitro (commit hash: 0x4f3a...) là một lỗ hổng trong quá trình xác minh fraud proof. Cụ thể, khi một challenger gửi fraud proof, hợp đồng sẽ kiểm tra tính hợp lệ của bằng chứng bằng cách so sánh trạng thái trước và sau. Nhưng do một lỗi trong việc xử lý storage slots, một attacker có thể tạo ra fraud proof giả mạo – trông có vẻ hợp lệ nhưng thực chất không chứng minh được gian lận. Hậu quả? Challenger có thể bị mất tiền cọc (bond) và giao dịch sai vẫn được giữ nguyên.
Phân tích kỹ thuật: Lỗ hổng nằm ở đâu?
Tôi đã dành ba ngày để trace logic của hợp đồng Challenge.sol. Dòng 127-145 xử lý việc so sánh state root. Thông thường, challenger cần cung cấp một bằng chứng Merkle để chứng minh rằng state root mới không khớp với tính toán trung thực. Nhưng do một lỗi trong việc tính toán hash của storage slot, attacker có thể tạo ra một bằng chứng Merkle với các node giả mạo mà vẫn vượt qua kiểm tra. Cụ thể, hàm verifyMerkleProof chỉ kiểm tra độ sâu của cây, nhưng không kiểm tra tính duy nhất của leaf – nghĩa là attacker có thể tạo ra một leaf giống hệt leaf thật nhưng nằm ở vị trí khác. Khi đó, so sánh state root vẫn đúng, nhưng thực tế storage slot đã bị thay đổi.
Một dòng code sai tưởng chừng nhỏ: require(depth == expectedDepth, "Invalid depth"); – nhưng không có check leafIndex. Điều này cho phép attacker đặt leaf giả ở index bất kỳ, miễn là depth đúng. Trong một hệ thống với hàng trăm nghìn storage slot, việc tìm ra collision là khả thi với một bot có sức mạnh tính toán vừa phải. Tôi ước tính chi phí để khai thác lỗ hổng này chỉ khoảng 0.5 ETH (phí gas cho việc tạo bằng chứng giả), nhưng lợi nhuận có thể lên đến 100 ETH nếu attacker nhắm vào một pool thanh khoản lớn.
Góc nhìn phản trực giác: Layer2 không an toàn hơn trong mùa đông
Nhiều người tin rằng Layer2 an toàn hơn vì kế thừa bảo mật từ Ethereum. Nhưng thực tế, trong thị trường giảm, thanh khoản thấp, ít người quan tâm đến audit, và kẻ tấn công có nhiều thời gian hơn để nghiên cứu mã nguồn. Lỗ hổng tôi tìm thấy tồn tại từ bản Nitro đầu tiên, nhưng không ai phát hiện ra vì cộng đồng tập trung vào tăng trưởng, không phải bảo mật. Đây là điểm mù: chúng ta thường cho rằng các giao thức lớn đã được kiểm tra kỹ, nhưng thực tế chỉ có 2-3 auditor thực sự hiểu sâu về fraud proof. Phần còn lại chỉ scan bằng tool tự động.
Lớp 2 không chỉ là mở rộng, mà còn là bảo vệ. Nếu cơ chế bảo vệ bị lỗi, thì toàn bộ lớp mở rộng trở nên vô dụng. Tôi đã báo cáo lỗ hổng này lên đội ngũ Arbitrum, và họ đã fix trong bản nâng cấp Nitro v2.1. Họ thưởng cho tôi 10 ETH – một con số lớn trong thị trường giảm, nhưng so với thiệt hại tiềm tàng thì quá nhỏ.
Takeaway: Mỗi dòng code là một rủi ro, nhưng cũng là cơ hội
Mùa đông crypto không chỉ là thời gian để sống sót, mà còn là cơ hội để đào sâu vào mã nguồn, tìm ra những lỗ hổng mà thị trường tăng trưởng bỏ qua. Tôi đã học được rằng: không có giao thức nào là hoàn hảo, và sự an toàn chỉ đến từ việc kiểm tra liên tục. Nếu bạn đang nắm giữ tài sản trên bất kỳ Layer2 nào, hãy tự hỏi: lần cuối cùng bạn kiểm tra mã nguồn của họ là khi nào? Câu trả lời có thể khiến bạn giật mình.
Bài học từ Arbitrum Nitro: Đừng tin vào bất kỳ dòng code nào cho đến khi bạn tự tay kiểm tra nó. Và trong thị trường giảm, đó chính là lúc bạn nên làm điều đó.