Lỗ hổng trong vấn đề sinh số ngẫu nhiên một ví dụ từ dự án MechMaster
Tags: random, exploit, bsc, smartcontract, audit, security audit SubscribeSign in blog.verichains.io lifebowMay 06, 2022Share this post
Lỗ hổng trong vấn đề sinh số ngẫu nhiên, một ví dụ từ dự án MechMaster
blog.verichains.ioCopy linkFacebookEmailNoteOtherShare blog.verichains.io Contract thực hiện chức năngdraw MechMaster sử dụng một đoạn logic random với các thông số không đủ mạnh, nên mình đã có thể khai thác và kiểm soát được kết quả tạo ra các item trong game có độ hiếm cao.
Phạm vi bài viết
Mã nguồn của proxy contract mà website trỏ tới đã được verified trên bscscan: https://bscscan.com/address/0xe35f67aec4f633c01130fdc9f18286a4215c3e5f#code
Contract chứa logic vận hành của proxy contract (cho tới thời điểm bài này được viết):
https://bscscan.com/address/0x37281cf9d0eda5059f41a62e969757f55c62bc1f
Website market của Mech master:
https://market.mechmaster.io/#/marketplace
Một số thông tin liên quan về game và contract khai thác
ERC1155 là contract chứa logic stake $MECH token và mint token ERC1155 trong game MechMaster. Người chơi sẽ phải stake một lượng $MECH token để có thể tham gia quay “xổ số” và nhận được các mảnh item dưới dạng token ERC1155.
Mỗi lượt quay có kết quả là ngẫu nhiên và có tỉ lệ rarity phân bố như hình trên.
Quá trình phân tích và khai thác
Phân tích
Nhìn sơ qua website của game mình thấy hàm draw khá là hay ho nên mình tìm tòi xung quanh frontend của web. Webpack enabled nên mình có thể đọc được phần xử lý khidraw như hình bên dưới.
Phương thức draw chỉ nhận vào 2 giá trị của người dùng là now (thời điểm hiện tại) và count (số lần draw). Có vẻ như user có thể điều khiển được 2 tham số này vì hàm không có truyền signature từ server.
Debug một chút để lấy được abi và địa chỉ contract tương tác.
Địa chỉ contract thu được:
https://bscscan.com/address/0xe35f67aec4f633c01130fdc9f18286a4215c3e5f
Contract mà game tương tác là một proxy contract. Proxy contract là một contract không chứa trực tiếp logic vận hành mà nó sẽ gọi qua một contract khác có địa chỉ được lưu bên trong _IMPLEMENTATION_SLOT của proxy contract để lấy logic.
Để tìm ra địa chỉ đứng phía sau proxy contract có 2 cách:
- Đọc giá trị storage của contract tại địa chỉ mà _IMPLEMENTATION_SLOT đang trỏ tới.
- Quan sát các transaction của owner contract và tìm transaction mới nhất update address implementation của proxy contract.
Tx update địa chỉ implementation của proxy contract.
https://bscscan.com/tx/0x3bbf4583a54ed46fb41db58fc97fecfcf4d1193b9a50b7ccac5c5369d5bb0000
Bằng cả hai cách ở trên, kết quả mình nhận được đều là địa chỉ contract: 0x37281cf9d0eda5059f41a62e969757f55c62bc1f
https://bscscan.com/address/0x37281cf9d0eda5059f41a62e969757f55c62bc1f
Tuy nhiên contract này chưa được verify nên chúng ta không có một source code tường minh để đào sâu vào hàm draw.
Với Bytecode public, mình thử sử dụng chức năng decompile bytecode có sẵn ngay trên bscscan.
Hầu hết các function trong contract đều được decompile và dễ dàng đọc được. Nhưng mục tiêu chính là hàm drawthì gặp phải một lỗi.
Chức năng này trên bscscan cũng không hoạt động hiệu quả 100%
Bằng một số kỹ năng dịch ngược, mình đã decompile bytecode này trên máy cá nhân và thu được kết quả như bên dưới.
Một phần mã nguồn hàm draw sau khi decompile.
Một phần đáng chú ý của hàm draw khi được decompile có sử dụng hash của block.difficulty và các input đầu vào để tính toán. Phân bổ các nhánh tương ứng với tỉ lệ cách mảnh item trong document nên ắt hẳn đây là logic của phần random.
Phân tích kỹ hơn về các đối số sử dụng với hàm hash sha3:
- block.difficulty: độ khó của block mặc định trên Binance Smart Chain là 2.
- _blockNumber: đối số thứ nhất của hàm draw là tương ứng với now - là giá trị user có thể kiểm soát được.
- caller: người gửi transaction là một địa chỉ ví mà ta sở hữu.
- stor256: giá trị storage của contract tại slot 256, có thể đọc một cách dễ dàng.
Các đối số sử dụng đối với hàm sha3 chúng ta đều có thể kiểm soát hoặc đọc được nên việc điều chỉnh tham số _blockNumber để nhảy vào đúng nhánh if-else là hoàn toàn khả thi.
Khai thác
Mình sử dụng ganache để fork mainnet ở block.number mới nhất của bsc mainnet.
Trong chain dưới local này mình sẽ gọi transaction với một giá trị _blockNumber tới contract, kết quả trả về dưới local sẽ tương ứng nếu dùng giá trị đó trên mainnet. Bằng việc thử đi thử lại nhiều lần với các _blockNumber khác nhau, ta sẽ có được giá trị _blockNumber cho ra kết quả của hàm draw mà ta muốn.
Dưới đây là 3 transacsions liên tục có kết quả draw được item có rarity Legendary - TOKEN ID1mà mình đã thực hiện trên mainnet:
- https://bscscan.com/tx/0x7dc44ff24ac46250547be458261699a8bb2854e2e189c557985fef4394ecf7f2
- https://bscscan.com/tx/0xac972b895e72331a4ba79ba63140f666ea18338383ae15d2d3c3832d1f4019a6
- https://bscscan.com/tx/0xf26bc9f07e9e2052da502fda20b55ce1019bb069a9695da3272bbc8cf042535f
Kết quả thu được sau quá trình khai thác
Đôi lời nhận xét về lỗ hổng
Như đã đề cập ở phần phân tích phía trên, hàm draw sử dụng block.difficulty và một số tham số khác làm đầu vào của sha3. Có lẽ developer nhầm lẫn block.difficulty là một thông số thay đổi liên tục như trên Ethereum, tiếc thay giá trị này là một giá trị cố định trên Binanace smart chain. Dẫu vậy cho dù giá trị này có thay đổi liên tục thì chúng ta vẫn có một cách thức khác để khai thác (nếu có cơ hội mình sẽ chia sẻ trong các blog khác).
Việc nhầm lẫn sử dụng block.difficulty trong logic random trên BSC là một lỗi cũ, có lẽ do kích thước hàm draw quá lớn dẫn tới việc khó khăn trong việc dịch ngược nên contract chưa bị tấn công ồ ạt.
Kết luận
Những lỗi trên sẽ gây ảnh hưởng rất lớn đến dự án và mình mong các dự án sẽ quan tâm và đầu tư hơn về các vấn đề bảo mật của cả ở phần offchain hay trên blockchain. Rất nhiều dự án đã phải chết yểu hay bị tấn công gây ra rất nhiều thiệt hại nghiêm trọng cho cả nhà đầu tư và chủ dự án. Audit mã nguồn sẽ là một phương pháp để phát hiện sớm các lỗi, tuy nhiên việc audit cũng chưa chắc đã phát hiện hết lỗi trong hệ thống. Để đảm bảo hơn dự án nên được audit bởi các công ty uy tín và sẽ càng tốt nếu được audit nhiều lần bởi nhiều đội ngũ hoạt động độc lập với nhau.
blog.verichains.io CommentsRestacks
FAQ
WPT Global có ứng dụng di động không?
Ứng dụng di động toàn cầu WPT: Tính năng, tính khả dụng và cách tải xuống WPT Global, một trong những nền tảng poker trực tuyến phát triển nhanh nhất, cung cấp ứng dụng di động tiện lợi và thân thiện với người dùng cho cả thiết bị iOS và Android. Bài viết này sẽ hướng dẫn bạn về các tính năng, phạm vi cung cấp và quy trình tải xuống của ứng dụng.
Cách chơi WPT Global trên máy tính của bạn 2024
Cách chơi WPT Global trên máy tính của bạn Tải xuống phần mềm 1. Truy cập Trang web chính thức: Truy cập trang web WPT Global hoặc sử dụng các liên kết liên kết được cung cấp bởi các trang tin tức poker. 2. Bắt đầu Tải xuống: Nhấp vào nút “Tải xuống” dành riêng cho hệ điều hành của bạn ( Windows hoặc Mac). 3. Cài đặt ứng dụng:
Vòng quay random số tương tự như vòng quay may mắn và vòng quay chữ cái A-Z nhưng với mục đích để chọn ra số ngẫu nhiên
Trang web này chỉ thu thập các bài viết liên quan. Để xem bản gốc, vui lòng sao chép và mở liên kết sau:Lỗ hổng trong vấn đề sinh số ngẫu nhiên một ví dụ từ dự án MechMaster