Hook
Chỉ trong 72 giờ qua, tôi đã fork toàn bộ mã nguồn của một giao thức AMM được quảng bá rầm rộ tại Việt Nam – tạm gọi là SaiGonSwap. Kết quả khiến tôi phải viết bài này ngay lập tức. Một đoạn code dài vỏn vẹn 15 dòng trong hợp đồng Pair.sol chứa lỗ hổng cho phép kẻ tấn công rút toàn bộ thanh khoản chỉ với một giao dịch. Tôi đã thử nghiệm trên môi trường fork của mainnet BSC và xác nhận: lỗi này hoạt động hoàn hảo. Hàng triệu USD thanh khoản từ cộng đồng người Việt đang nằm trên thòng lọng.
Context
SaiGonSwap là một Automated Market Maker (AMM) ra mắt vào tháng 8/2024, tập trung vào các cặp giao dịch stablecoin VNDC-USDT và token dự án Việt. Theo whitepaper, họ tuyên bố sử dụng mô hình CPMM (Constant Product Market Maker) tương tự Uniswap V2, nhưng có thêm cơ chế phí động (dynamic fee) để tối ưu hóa cho thị trường nội địa. Dự án đã huy động được 2.5 triệu USD từ các quỹ đầu tư tư nhân tại Việt Nam và Đông Nam Á, với lời hứa về audit bởi một công ty bảo mật nước ngoài. Tuy nhiên, đến nay chưa có báo cáo audit nào được công bố công khai. Hợp đồng thông minh được deploy trên BSC từ tháng 9, với tổng TVL đạt khoảng 8 triệu USD tính đến ngày hôm qua.
Core
Tôi bắt đầu với việc đọc mã nguồn của SaiGonSwapPair.sol. Thoạt nhìn, cấu trúc khá giống Uniswap V2: hàm swap, mint, burn với các modifier cơ bản. Nhưng khi đi sâu vào logic dynamic fee, tôi phát hiện một biến trạng thái dynamicFee được cập nhật trong hàm _update mỗi khi có giao dịch. Vấn đề nằm ở chỗ: hàm _update được gọi sau khi swap kết thúc, và nó sử dụng balanceOf của chính hợp đồng để tính phí cho lần giao dịch tiếp theo – nhưng không có cơ chế bảo vệ nào cho việc tái nhập (reentrancy).
Đây là những gì code thực sự nói: