Phân tích lỗ hổng trình biên dịch Solidity và chiến lược ứng phó
Trình biên dịch là một trong những thành phần cơ bản của hệ thống máy tính hiện đại. Nó là một chương trình chuyển đổi ngôn ngữ lập trình bậc cao thành các lệnh có thể thực thi bởi máy tính. Mặc dù các nhà phát triển và chuyên gia an ninh thường chú trọng đến độ an toàn của mã ứng dụng, nhưng độ an toàn của chính trình biên dịch cũng quan trọng không kém.
Trình biên dịch như một chương trình máy tính cũng có thể tồn tại lỗ hổng bảo mật, trong một số trường hợp có thể gây ra rủi ro an ninh nghiêm trọng. Ví dụ, khi trình duyệt phân tích và thực thi mã JavaScript, có thể do lỗ hổng của bộ xử lý JavaScript mà người dùng bị tấn công khi truy cập vào trang web độc hại, cuối cùng dẫn đến việc kẻ tấn công kiểm soát trình duyệt của nạn nhân thậm chí cả hệ điều hành.
Trình biên dịch Solidity cũng không phải là ngoại lệ. Theo cảnh báo về an ninh của nhóm phát triển Solidity, nhiều phiên bản của trình biên dịch Solidity có lỗ hổng bảo mật.
Lỗ hổng biên dịch viên Solidity
Chức năng của trình biên dịch Solidity là chuyển đổi mã hợp đồng thông minh thành mã lệnh (EVM) của máy ảo Ethereum. Những lệnh EVM này được đóng gói và tải lên Ethereum thông qua giao dịch, cuối cùng được thực thi bởi EVM.
Cần phân biệt giữa lỗ hổng trình biên dịch Solidity và lỗ hổng của chính EVM. Lỗ hổng EVM là những lỗ hổng bảo mật trong quá trình máy ảo thực thi các lệnh, có thể ảnh hưởng đến toàn bộ mạng Ethereum. Trong khi đó, lỗ hổng trình biên dịch Solidity là những vấn đề phát sinh trong quá trình chuyển đổi Solidity thành mã EVM.
Lỗi trong trình biên dịch Solidity sẽ không ảnh hưởng trực tiếp đến mạng Ethereum, nhưng có thể dẫn đến mã EVM được tạo ra không tương thích với mong đợi của nhà phát triển. Do hợp đồng thông minh thường liên quan đến tài sản tiền điện tử, bất kỳ lỗi nào do trình biên dịch gây ra đều có thể dẫn đến tổn thất tài sản của người dùng, hậu quả sẽ rất nghiêm trọng.
Chỉ thông qua việc kiểm tra mã nguồn hợp đồng rất khó để phát hiện lỗ hổng của trình biên dịch. Cần kết hợp phiên bản trình biên dịch cụ thể và mẫu mã để phân tích, mới có thể xác định hợp đồng có bị ảnh hưởng bởi lỗ hổng của trình biên dịch hay không.
Ví dụ về lỗ hổng biên dịch viên Solidity
Dưới đây là một vài ví dụ thực tế về lỗ hổng biên dịch Solidity, trình bày các hình thức cụ thể, nguyên nhân và tác hại.
SOL-2016-9 HighOrderByteCleanStorage
Lỗi này tồn tại trong các phiên bản trước của trình biên dịch Solidity (>=0.1.6 <0.4.4).
Xem xét mã sau:
solidity
hợp đồng C {
uint32 a = 0x12345678;
uint32 b = 0;
hàm run() trả về (uint256) {
a = a + 1;
return b;
}
}
Biến lưu trữ b chưa được sửa đổi, hàm run() nên trả về giá trị mặc định 0. Nhưng trong phiên bản trình biên dịch có lỗ hổng, run() sẽ trả về 1.
Tình huống không nhất quán này, nếu biến b được sử dụng cho việc xác thực quyền hoặc ghi chép tài sản, có thể dẫn đến hậu quả nghiêm trọng.
Nguyên nhân gây ra hiện tượng này là do EVM sử dụng các phần tử ngăn xếp và khe lưu trữ có kích thước 32 byte, trong khi Solidity hỗ trợ các kiểu dữ liệu nhỏ hơn như uint32. Trình biên dịch cần xóa đi các bit cao khi xử lý các kiểu này, nhưng không xử lý đúng trong trường hợp tràn số nguyên, dẫn đến bit cao 1 bị ghi vào storage, ghi đè lên biến b.
SOL-2022-4 InlineAssemblyMemorySideEffects
Lỗi này tồn tại trong các phiên bản biên dịch viên từ >=0.8.13 đến <0.8.15.
Xem xét mã sau:
solidity
hợp đồng C {
function f() public pure returns (uint) {
assembly {
mstore(0, 0x42)
}
uint x;
lắp ráp {
x := mload(0)
}
return x;
}
}
Lỗi này xuất phát từ việc tối ưu hóa biên dịch. Trình biên dịch cố gắng loại bỏ các thao tác ghi vào bộ nhớ có vẻ dư thừa, nhưng đã phân tích sai qua các khối assembly. Trong phiên bản có lỗ hổng, hàm f() sẽ trả về 0, thay vì 0x42 chính xác.
Lỗ hổng này ảnh hưởng đến các phiên bản biên dịch viên >= 0.5.8 < 0.8.16.
Xem xét đoạn mã sau:
solidity
hợp đồng C {
function f(string[1] calldata a) external pure returns (string memory) {
return abi.decode(abi.encode(a), (string[1]))[0];
}
}
Trong trường hợp bình thường, đoạn mã này nên trả về giá trị của biến a là "aaaa". Nhưng trong phiên bản có lỗ hổng, nó sẽ trả về chuỗi rỗng "".
Điều này xảy ra do Solidity đã xóa sai một số dữ liệu khi thực hiện thao tác abi.encode trên mảng kiểu calldata, dẫn đến việc sửa đổi dữ liệu liền kề, gây ra sự không nhất quán của dữ liệu sau khi mã hóa và giải mã.
Cần lưu ý rằng, Solidity sẽ thực hiện abi.encode một cách ngầm định khi thực hiện cuộc gọi external và phát sự kiện, do đó, phạm vi ảnh hưởng của các lỗ hổng loại này có thể rộng hơn dự đoán.
Gợi ý an toàn
Dựa trên phân tích mô hình đe dọa từ các lỗ hổng của trình biên dịch Solidity và tổng hợp các lỗ hổng lịch sử, tôi đưa ra những gợi ý sau cho các nhà phát triển và nhân viên an ninh:
Đối với nhà phát triển:
Sử dụng phiên bản trình biên dịch Solidity mới hơn. Phiên bản mới thường sửa chữa các vấn đề bảo mật đã biết.
Hoàn thiện kiểm tra đơn vị. Hầu hết các lỗi ở cấp biên dịch sẽ dẫn đến kết quả thực thi mã không phù hợp với mong đợi, bằng cách tăng cường độ bao phủ của mã có thể phát hiện loại vấn đề này trong giai đoạn kiểm tra.
Tránh sử dụng lắp ráp nội tuyến, các thao tác mã hóa và giải mã ABI phức tạp. Hầu hết các lỗ hổng lịch sử liên quan đến những đặc điểm phức tạp này.
cho nhân viên an ninh:
Khi kiểm toán, đừng bỏ qua các rủi ro an ninh có thể do trình biên dịch gây ra. Mục kiểm tra phân loại điểm yếu hợp đồng thông minh liên quan là SWC-102.
Trong quy trình SDL nội bộ, yêu cầu nhóm phát triển nâng cấp phiên bản trình biên dịch Solidity, xem xét việc đưa vào kiểm tra tự động trong CI/CD.
Không cần quá lo lắng về lỗ hổng của trình biên dịch. Hầu hết các lỗ hổng chỉ được kích hoạt trong các mẫu mã cụ thể, cần đánh giá ảnh hưởng thực tế dựa trên từng trường hợp cụ thể.
( Tài nguyên hữu ích:
Cảnh báo an ninh từ đội ngũ Solidity:
Danh sách lỗi chính thức của Solidity:
Danh sách lỗi của các phiên bản biên dịch:
Biểu tượng cảnh báo ở góc trên bên phải trang mã hợp đồng Etherscan có thể chỉ ra các lỗ hổng bảo mật hiện có trong phiên bản trình biên dịch.
Tóm tắt
Bài viết này giới thiệu khái niệm về lỗ hổng trình biên dịch Solidity, phân tích các rủi ro an ninh có thể xảy ra trong quá trình phát triển Ethereum thực tế, và cung cấp các lời khuyên an ninh hữu ích cho các nhà phát triển và nhân viên an ninh. Bằng cách hiểu các đặc điểm và ảnh hưởng của lỗ hổng trình biên dịch, có thể đảm bảo tốt hơn an toàn cho hợp đồng thông minh.
![Phân tích lỗ hổng biên dịch Solidity và biện pháp ứng phó])https://img-cdn.gateio.im/webp-social/moments-84f5083d8748f2aab71fd92671d999a7.webp###
Trang này có thể chứa nội dung của bên thứ ba, được cung cấp chỉ nhằm mục đích thông tin (không phải là tuyên bố/bảo đảm) và không được coi là sự chứng thực cho quan điểm của Gate hoặc là lời khuyên về tài chính hoặc chuyên môn. Xem Tuyên bố từ chối trách nhiệm để biết chi tiết.
12 thích
Phần thưởng
12
3
Chia sẻ
Bình luận
0/400
DataBartender
· 21giờ trước
An toàn không có điểm dừng, bản vá tạm thời không thể chịu đựng được.
Phân tích lỗ hổng trình biên dịch Solidity và chiến lược bảo vệ an ninh
Phân tích lỗ hổng trình biên dịch Solidity và chiến lược ứng phó
Trình biên dịch là một trong những thành phần cơ bản của hệ thống máy tính hiện đại. Nó là một chương trình chuyển đổi ngôn ngữ lập trình bậc cao thành các lệnh có thể thực thi bởi máy tính. Mặc dù các nhà phát triển và chuyên gia an ninh thường chú trọng đến độ an toàn của mã ứng dụng, nhưng độ an toàn của chính trình biên dịch cũng quan trọng không kém.
Trình biên dịch như một chương trình máy tính cũng có thể tồn tại lỗ hổng bảo mật, trong một số trường hợp có thể gây ra rủi ro an ninh nghiêm trọng. Ví dụ, khi trình duyệt phân tích và thực thi mã JavaScript, có thể do lỗ hổng của bộ xử lý JavaScript mà người dùng bị tấn công khi truy cập vào trang web độc hại, cuối cùng dẫn đến việc kẻ tấn công kiểm soát trình duyệt của nạn nhân thậm chí cả hệ điều hành.
Trình biên dịch Solidity cũng không phải là ngoại lệ. Theo cảnh báo về an ninh của nhóm phát triển Solidity, nhiều phiên bản của trình biên dịch Solidity có lỗ hổng bảo mật.
Lỗ hổng biên dịch viên Solidity
Chức năng của trình biên dịch Solidity là chuyển đổi mã hợp đồng thông minh thành mã lệnh (EVM) của máy ảo Ethereum. Những lệnh EVM này được đóng gói và tải lên Ethereum thông qua giao dịch, cuối cùng được thực thi bởi EVM.
Cần phân biệt giữa lỗ hổng trình biên dịch Solidity và lỗ hổng của chính EVM. Lỗ hổng EVM là những lỗ hổng bảo mật trong quá trình máy ảo thực thi các lệnh, có thể ảnh hưởng đến toàn bộ mạng Ethereum. Trong khi đó, lỗ hổng trình biên dịch Solidity là những vấn đề phát sinh trong quá trình chuyển đổi Solidity thành mã EVM.
Lỗi trong trình biên dịch Solidity sẽ không ảnh hưởng trực tiếp đến mạng Ethereum, nhưng có thể dẫn đến mã EVM được tạo ra không tương thích với mong đợi của nhà phát triển. Do hợp đồng thông minh thường liên quan đến tài sản tiền điện tử, bất kỳ lỗi nào do trình biên dịch gây ra đều có thể dẫn đến tổn thất tài sản của người dùng, hậu quả sẽ rất nghiêm trọng.
Chỉ thông qua việc kiểm tra mã nguồn hợp đồng rất khó để phát hiện lỗ hổng của trình biên dịch. Cần kết hợp phiên bản trình biên dịch cụ thể và mẫu mã để phân tích, mới có thể xác định hợp đồng có bị ảnh hưởng bởi lỗ hổng của trình biên dịch hay không.
Ví dụ về lỗ hổng biên dịch viên Solidity
Dưới đây là một vài ví dụ thực tế về lỗ hổng biên dịch Solidity, trình bày các hình thức cụ thể, nguyên nhân và tác hại.
SOL-2016-9 HighOrderByteCleanStorage
Lỗi này tồn tại trong các phiên bản trước của trình biên dịch Solidity (>=0.1.6 <0.4.4).
Xem xét mã sau:
solidity hợp đồng C { uint32 a = 0x12345678; uint32 b = 0; hàm run() trả về (uint256) { a = a + 1; return b; } }
Biến lưu trữ b chưa được sửa đổi, hàm run() nên trả về giá trị mặc định 0. Nhưng trong phiên bản trình biên dịch có lỗ hổng, run() sẽ trả về 1.
Tình huống không nhất quán này, nếu biến b được sử dụng cho việc xác thực quyền hoặc ghi chép tài sản, có thể dẫn đến hậu quả nghiêm trọng.
Nguyên nhân gây ra hiện tượng này là do EVM sử dụng các phần tử ngăn xếp và khe lưu trữ có kích thước 32 byte, trong khi Solidity hỗ trợ các kiểu dữ liệu nhỏ hơn như uint32. Trình biên dịch cần xóa đi các bit cao khi xử lý các kiểu này, nhưng không xử lý đúng trong trường hợp tràn số nguyên, dẫn đến bit cao 1 bị ghi vào storage, ghi đè lên biến b.
SOL-2022-4 InlineAssemblyMemorySideEffects
Lỗi này tồn tại trong các phiên bản biên dịch viên từ >=0.8.13 đến <0.8.15.
Xem xét mã sau:
solidity hợp đồng C { function f() public pure returns (uint) { assembly { mstore(0, 0x42) } uint x; lắp ráp { x := mload(0) } return x; } }
Lỗi này xuất phát từ việc tối ưu hóa biên dịch. Trình biên dịch cố gắng loại bỏ các thao tác ghi vào bộ nhớ có vẻ dư thừa, nhưng đã phân tích sai qua các khối assembly. Trong phiên bản có lỗ hổng, hàm f() sẽ trả về 0, thay vì 0x42 chính xác.
SOL-2022-6 AbiReencodingHeadOverflowWithStaticArrayCleanup
Lỗ hổng này ảnh hưởng đến các phiên bản biên dịch viên >= 0.5.8 < 0.8.16.
Xem xét đoạn mã sau:
solidity hợp đồng C { function f(string[1] calldata a) external pure returns (string memory) { return abi.decode(abi.encode(a), (string[1]))[0]; } }
Trong trường hợp bình thường, đoạn mã này nên trả về giá trị của biến a là "aaaa". Nhưng trong phiên bản có lỗ hổng, nó sẽ trả về chuỗi rỗng "".
Điều này xảy ra do Solidity đã xóa sai một số dữ liệu khi thực hiện thao tác abi.encode trên mảng kiểu calldata, dẫn đến việc sửa đổi dữ liệu liền kề, gây ra sự không nhất quán của dữ liệu sau khi mã hóa và giải mã.
Cần lưu ý rằng, Solidity sẽ thực hiện abi.encode một cách ngầm định khi thực hiện cuộc gọi external và phát sự kiện, do đó, phạm vi ảnh hưởng của các lỗ hổng loại này có thể rộng hơn dự đoán.
Gợi ý an toàn
Dựa trên phân tích mô hình đe dọa từ các lỗ hổng của trình biên dịch Solidity và tổng hợp các lỗ hổng lịch sử, tôi đưa ra những gợi ý sau cho các nhà phát triển và nhân viên an ninh:
Đối với nhà phát triển:
Sử dụng phiên bản trình biên dịch Solidity mới hơn. Phiên bản mới thường sửa chữa các vấn đề bảo mật đã biết.
Hoàn thiện kiểm tra đơn vị. Hầu hết các lỗi ở cấp biên dịch sẽ dẫn đến kết quả thực thi mã không phù hợp với mong đợi, bằng cách tăng cường độ bao phủ của mã có thể phát hiện loại vấn đề này trong giai đoạn kiểm tra.
Tránh sử dụng lắp ráp nội tuyến, các thao tác mã hóa và giải mã ABI phức tạp. Hầu hết các lỗ hổng lịch sử liên quan đến những đặc điểm phức tạp này.
cho nhân viên an ninh:
Khi kiểm toán, đừng bỏ qua các rủi ro an ninh có thể do trình biên dịch gây ra. Mục kiểm tra phân loại điểm yếu hợp đồng thông minh liên quan là SWC-102.
Trong quy trình SDL nội bộ, yêu cầu nhóm phát triển nâng cấp phiên bản trình biên dịch Solidity, xem xét việc đưa vào kiểm tra tự động trong CI/CD.
Không cần quá lo lắng về lỗ hổng của trình biên dịch. Hầu hết các lỗ hổng chỉ được kích hoạt trong các mẫu mã cụ thể, cần đánh giá ảnh hưởng thực tế dựa trên từng trường hợp cụ thể.
( Tài nguyên hữu ích:
Tóm tắt
Bài viết này giới thiệu khái niệm về lỗ hổng trình biên dịch Solidity, phân tích các rủi ro an ninh có thể xảy ra trong quá trình phát triển Ethereum thực tế, và cung cấp các lời khuyên an ninh hữu ích cho các nhà phát triển và nhân viên an ninh. Bằng cách hiểu các đặc điểm và ảnh hưởng của lỗ hổng trình biên dịch, có thể đảm bảo tốt hơn an toàn cho hợp đồng thông minh.
![Phân tích lỗ hổng biên dịch Solidity và biện pháp ứng phó])https://img-cdn.gateio.im/webp-social/moments-84f5083d8748f2aab71fd92671d999a7.webp###