BTC $66,561.9 +2.68%
ETH $1,927.17 +2.39%
SOL $78 +1.44%
BNB $575.1 +0.77%
XRP $1.15 +4.02%
DOGE $0.0732 +0.49%
ADA $0.1753 +6.57%
AVAX $6.6 +0.27%
DOT $0.8542 +4.29%
LINK $8.67 +2.40%
⛽ ETH Gas 28 Gwei
Sợ&Tham
25

Đào mã thấy lỗi: SolarLend mất 500 ETH vì một dòng code access control

Vũ Việt
Lừa đảo

Hook

7 ngày trước, SolarLend – một giao thức lending mới nổi trên Arbitrum – mất 500 ETH từ pool WETH. Không phải reentrancy, không phải oracle manipulation. Lỗi nằm ở access control. Một dòng require() bị thiếu. 500 ETH bay ra trong 3 block. Sàn giao dịch dừng pull, nhưng thanh khoản đã cạn.

Đào mã thấy lỗi, im lặng là vàng.

Context

SolarLend là fork từ Compound V2, thêm tính năng isolated lending. Người dùng có thể tạo pool riêng, set tham số riêng. Họ deploy trên Arbitrum tháng 4/2025. TVL đỉnh 45 triệu USD. Đội ngũ ẩn danh, audit bởi công ty nhỏ tên SecureChain. Báo cáo audit công bố: không có critical issue.

Tôi audit lại từ đầu. Lý do: thấy một dòng code trong hàm withdraw() không kiểm tra chủ pool. Hợp đồng chính gọi withdraw(user, amount) nhưng không khóa chỉ owner pool mới được rút khi pool ở chế độ private.

Core

Phân tích kỹ thuật:

Mỗi pool có struct: `` struct Pool { address creator; bool isPrivate; mapping(address => uint) balances; uint totalSupply; } ``

Hàm withdraw(address user, uint amount): `` function withdraw(address user, uint amount) public { require(amount > 0, "Zero amount"); require(balances[user] >= amount, "Insufficient balance"); balances[user] -= amount; totalSupply -= amount; IERC20(token).safeTransfer(user, amount); } ``

Nhìn kỹ: không có kiểm tra msg.sender == user và cũng không kiểm tra msg.sender == pool.creator cho pool private. Trong pool public, bất kỳ ai cũng có thể rút tiền của user khác bằng cách gọi withdraw(victim, amount). Chỉ cần biết địa chỉ.

Kẻ tấn công dùng script scan pool public, tìm user có balance lớn. Gọi withdraw target, lấy ETH. Chỉ 3 giao dịch là xong 500 ETH.

Đây là lỗi access control cơ bản. Nhưng SecureChain bỏ sót vì không test flow withdraw từ góc nhìn attacker.

Tôi viết PoC trong 2 giờ. Mô phỏng lại cuộc tấn công. Kết quả khớp.

Thanh khoản cạn, bẫy còn đó.

Contrarian

Nhiều người nói: lỗi này do dev bất cẩn, audit kém. Nhưng tôi thấy có góc nhìn khác. Bản chất của fork là copy-paste an toàn? Sai. Compound V2 không có isolated pool, nên không có logic isPrivate. Khi thêm tính năng, dev thêm struct pool nhưng quên cập nhật access control. Đây là lỗi phổ biến ở fork: chỉ copy 90% code, 10% custom lại trở thành điểm chết.

Thị trường giảm, các dự án fork rẻ chạy đua kiếm TVL. Audit thì chọn rẻ. SecureChain audit bằng tool tự động? Báo cáo chỉ check reentrancy, oracle, integer overflow – không check logic nghiệp vụ. Kết quả: lỗi sơ đẳng vượt qua.

Điểm mù: ai cũng nghĩ audit là đủ. Không ai audit cái audit.

Takeaway

SolarLend bị tấn công, TVL về 0. Nhưng câu hỏi lớn hơn: bao nhiêu fork khác đang mang cùng rủi ro? Trong thị trường giảm, an toàn là khan hiếm. Đào mã thấy lỗi, im lặng là vàng. Nhưng đôi khi, im lặng quá lâu sẽ thành vàng giả.

Tôi không đầu tư vào fork không audit. Và kể cả có audit, tôi tự kiểm tra lại. Vì 500 ETH kia từng thuộc về người dùng nghĩ rằng họ an toàn.