Ví dụ về lỗ Hổng bảo mật trong smart contract khi check Bằng Securify

Khi dùng Securify để kiểm tra, chúng ta phát hiện 1 vài lỗ hổng bảo mật trong smart contract, và cách mà Securify phát hiện và báo cáo về vấn đề này. Bài viết dưới đây sẽ nêu ra 2 ví dụ về lỗ hổng bảo mật đó và giải thích chi tiết.

Lỗ hổng 1: Đánh cắp token

contract OwnableWallet {
 address owner;

 // called by the constructor
 function initWallet(address _owner) {
 owner = _owner; // any user can change owner
 // more setup
 }

 // function that allows the owner to withdraw ether
 function withdraw(uint _amount) {
 if (msg.sender == owner) {
 owner.transfer(_amount);
 }
 }
 // ...
 }

Trong contract này có một thuộc tính owner, lưu trữ địa chỉ của chủ sở hữu ví. Hơn nữa, hợp đồng có một hàm initWallet, nhận địa chỉ _owner như là đối số và khởi tạo trường owner bằng địa chỉ này. Hàm này được gọi bởi hàm khởi tạo, và được giả định là không thể truy cập bằng cách khác. Cuối cùng, hợp đồng còn có một hàm withdraw, nhận một số nguyên không dấu _amount như là đối số. Hàm này kiểm tra xem địa chỉ gửi giao dịch (được trả về bởi msg.sender) có bằng với địa chỉ của chủ sở hữu hợp đồng (được lưu trữ trong trường owner) không. Nếu kiểm tra này thành công, nó sẽ chuyển _amount ether cho chủ sở hữu với câu lệnh owner.transfer(_amount); nếu không, không có ether nào được chuyển. Hàm withdraw đảm bảo rằng chỉ chủ sở hữu mới có thể rút ether từ ví.

Tấn Công

Hợp đồng này có một lỗ hổng bảo mật nghiêm trọng: bất kỳ người dùng nào cũng có thể gọi hàm initWallet và lưu trữ một địa chỉ tùy ý trong trường owner. Một kẻ tấn công có thể lấy toàn bộ ether lưu trữ trong ví này chỉ trong hai bước. Trước hết, kẻ tấn công gọi hàm initWallet, truyền địa chỉ của chính họ như là đối số. Tiếp theo, kẻ tấn công gọi hàm withdraw, truyền số lượng ether lưu trữ trong ví làm đối số. Chúng ta chú ý rằng trong cuộc tấn công vào ví của Parity, để thực hiện bước đầu tiên, kẻ tấn công khai thác một cơ chế rơi vào khi gọi hàm initWallet; chúng tôi bỏ qua các chi tiết này vì đơn giản và tham khảo đọc [10] để biết chi tiết về cuộc tấn công thực tế.

Thuộc Tính Bảo Mật

Vấn đề bảo mật cơ bản đã cho phép kẻ tấn công lấy ether là trường owner quan trọng về bảo mật có thể được ghi bởi bất kỳ người dùng Ethereum nào. Vấn đề bảo mật này phản ánh một thuộc tính tổng quát hơn, xác định việc viết vào trường owner bị hạn chế, trong ý nghĩa rằng không phải tất cả người dùng đều có thể tạo giao dịch viết vào trường này. Để chứng minh rằng thuộc tính này được đảm bảo, chúng ta cần chứng minh rằng một số người dùng không thể tạo giao dịch sửa đổi trường owner. Ngược lại, để chứng minh vi phạm, chúng ta cần chứng minh rằng tất cả người dùng đều có thể tạo giao dịch sửa đổi trường owner. Việc chứng minh cả hai yêu cầu này và chứng minh vi phạm của thuộc tính này là không trực tiếp do không gian người dùng và giao dịch có thể tạo ra quá lớn.

Phát Hiện

Để khám phá vấn đề bảo mật này, Securify cung cấp một mẫu vi phạm được khớp nếu việc thực thi gán owner = _owner, không phụ thuộc vào giá trị trả về bởi lệnh gọi của người gửi giao dịch (trả về địa chỉ của người gửi giao dịch). Để kiểm tra mẫu này, Securify suy ra các phụ thuộc dữ liệu và luồng điều khiển bằng cách phân tích đồ thị phụ thuộc của hợp đồng; so sánh. Tại đây, Securify suy ra rằng việc gán owner = _owner không phụ thuộc vào lệnh gọi của người gửi giao dịch, ngụ ý rằng việc gán này có thể tiếp cận bởi bất kỳ người dùng nào. Chúng tôi chú ý rằng một số công cụ kiểm tra tượng trưng thực hiện các kiểm tra không chính xác về các thuộc tính tương tự, dẫn đến cả những kết quả giả và thiếu sót. Ví dụ, như chúng tôi thể hiện trong hình, Mythril có khoảng 65% kết quả giả khi kiểm tra thuộc tính tương tự, nghĩa là không phải tất cả người dùng có thể kích hoạt một giao dịch chuyển ether cụ thể.

So sánh Securify, Mythril và Oyente

So sánh Securify, Mythril và Oyente

Lỗ hổng 2: Hợp Đồng Đóng Băng Quỹ

Luồng cao cấp minh họa cách Securify tìm việc ghi không hạn chế vào trường chủ sở hữu của hợp đồng từ đoạn code ở phần 1 bên trên
Thông tin đầu vào (EVM bytecode và các mẫu bảo mật) được đánh dấu màu xanh lá cây, kết quả đầu ra (trong ví dụ của chúng tôi, một lệnh vi phạm) được đánh dấu màu đỏ, và hộp màu xám đại diện cho các sản phẩm phân tích trung gian. Securify thực hiện theo ba bước: (1) nó giải mã bytecode EVM của hợp đồng thành dạng gán tĩnh duy nhất, (2) nó suy luận các sự thật về ngữ nghĩa của hợp đồng và (3) nó tìm sự phù hợp của mẫu vi phạm của thuộc tính ghi hạn chế trên lệnh sstore mà ghi vào trường chủ sở hữu.

Trong hình, chúng ta thấy một hợp đồng ví có một vấn đề bảo mật khiến hàng triệu USD bị đóng băng vào tháng 11 năm 2017. Hợp đồng này có một trường walletLibrary, lưu trữ địa chỉ của một hợp đồng thực hiện chức năng ví thông thường. Hơn nữa, hợp đồng có một hàm deposit, được đánh dấu là có thể thanh toán, có nghĩa là người dùng có thể gửi ether vào hợp đồng bằng cách gọi hàm này. Hàm deposit ghi nhật ký số lượng ether (được xác định bởi msg.value) được gửi bởi người gửi giao dịch (được xác định bởi msg.sender). Cuối cùng, hợp đồng có một hàm withdraw, giao toàn bộ cuộc gọi cho thư viện ví. Điều này có nghĩa là câu lệnh walletLibrary.delegatecall(msg.data) dẫn đến thực thi phương thức withdraw của thư viện ví trong ngữ cảnh của ví hiện tại.

Tấn Công

Hợp đồng thông qua lệnh “kill” có thể được loại bỏ khỏi blockchain. Nếu một kẻ tấn công có thể loại bỏ thư viện ví khỏi blockchain, thì số tiền trong ví không thể được rút ra khỏi ví. Việc này xảy ra bởi vì ví dựa vào hợp đồng thông thường để rút ether. Vào tháng 11 năm 2017, một thư viện ví phổ biến đã bị loại bỏ khỏi blockchain, làm đóng băng khoảng 280 triệu USD.

Thuộc Tính Bảo Mật

Vấn đề bảo mật cơ bản với ví này là cho phép người dùng gửi ether, nhưng không đảm bảo rằng ether có thể được chuyển ra khỏi hợp đồng, do việc chuyển phụ thuộc vào một thư viện. Để phát hiện rằng ví có vấn đề này, chúng ta phải chứng minh hai sự thật: (i) người dùng có thể gửi ether và (ii) hợp đồng không có lệnh chuyển ether nào (tức là cuộc gọi) với số lượng ether khác không. Lưu ý rằng nếu hợp đồng chỉ chuyển ether ra thông qua thư viện, yêu cầu thứ hai sẽ được đáp ứng.

Phát Hiện

Để khám phá lỗ hổng này, mẫu vi phạm của Securify kiểm tra sự kết hợp của hai sự thật. Đầu tiên, để chứng minh rằng người dùng có thể gửi ether, Securify kiểm tra xem có lệnh dừng nào thực thi không phụ thuộc vào số lượng ether được chuyển là không. Giả sử rằng lệnh dừng này có thể đạt được cho một số giao dịch, điều này ngụ ý rằng người dùng có thể đạt đến nó với một số lượng ether dương, dẫn đến việc gửi ether vào hợp đồng. Thứ hai, Securify kiểm tra xem cho tất cả các lệnh gọi, số lượng ether được rút từ hợp đồng có phải là không. Sự kết hợp của hai sự thật này ngụ ý rằng ether có thể bị khóa trong hợp đồng.

Vietnam Pham – Click Digital

  • If you’d like to invest in blockchain advertising companies, just BUY token Saigon (SGN) at Pancakeswap: https://t.co/KJbk71cFe8 (do not worry about low liquidity)
  • Backed by Click Digital Company
  • BSC address: 0xa29c5da6673fd66e96065f44da94e351a3e2af65
  • Twitter: https://twitter.com/SaigonSGN135
  • Staking SGN: http://135web.net

Leave a Reply

Your email address will not be published. Required fields are marked *