Tác giả: Chengdu Lian’an
Bản gốc: “Research on Cross-Chain Bridge Security (3)” | Lọc máu an toàn Polygon Warrior, làm thế nào để ngăn chặn việc mở “Pandora’s Box”?
Chào mừng bạn đến với loạt bài viết về “Nghiên cứu bảo mật cầu nối xuyên chuỗi” do Chengdu Chain Security sản xuất, trong bài viết trước (Nghiên cứu bảo mật cầu nối xuyên chuỗi (2) | Vụ cướp phi tập trung đầu tiên của cây cầu Nomad mang lại cho chúng ta điều gì?), Chúng tôi tiến hành phân tích kỹ thuật chuyên nghiệp về giao thức cầu Nomad một cách chi tiết.
Hôm nay, Nhóm nghiên cứu bảo mật chuỗi Thành Đô sẽ tiến hành lọc máu an toàn Polygon, một chiến binh đa giác, vì vậy hãy tiếp tục đọc.
1_Polygon là ai?
Polygon là giải pháp mở rộng quy mô lớp 2 của Ethereum, với tầm nhìn xây dựng internet blockchain của Ethereum. Polygon cung cấp một khung chung cho phép các nhà phát triển tận dụng bảo mật của Ethereum để tạo các chuỗi tùy chỉnh, tập trung vào ứng dụng và cung cấp một mạng có thể tương tác kết hợp nhiều sơ đồ mở rộng quy mô khác nhau như: zk-rollup, PoS, v.v. Trong số đó, Polygon PoS hiện là giải pháp mở rộng quy mô trưởng thành và nổi tiếng nhất trên Polygon. Nó sử dụng sidechain để xử lý giao dịch để đạt được mục đích cải thiện tốc độ giao dịch và tiết kiệm gas tiêu thụ, và cấu trúc mạng chủ yếu bao gồm ba lớp sau:
Lớp Ethereum:
Một loạt các hợp đồng trên mạng chính Ethereum, chủ yếu bao gồm: Hợp đồng Staking, Checkpoint và Reward, chịu trách nhiệm về các chức năng quản lý đặt cọc liên quan đến cổ phần PoS, bao gồm: cung cấp chức năng đặt cọc của token gốc MATIC, để bất kỳ ai đặt cược token đều có thể tham gia hệ thống với tư cách là người xác thực, xác minh việc chuyển đổi mạng Polygon để nhận phần thưởng đặt cược, trừng phạt người xác thực vì chữ ký kép, thời gian ngừng hoạt động của trình xác thực và các hành vi bất hợp pháp khác và lưu các điểm kiểm tra.
** Lớp Heimdall: **
Lớp xác thực bằng chứng cổ phần, bao gồm một tập hợp các nút PoS Heimdall, chịu trách nhiệm gửi các điểm kiểm tra của mạng Polygon đến mạng chính Ethereum trong khi lắng nghe một tập hợp các hợp đồng đặt cọc được triển khai trên Ethereum. Quá trình chính như sau: đầu tiên, chọn một tập hợp con các trình xác thực đang hoạt động trong nhóm trình xác thực làm nhà sản xuất khối, những người sẽ chịu trách nhiệm tạo các khối ở lớp Bor và phát chúng, sau đó xác thực hàm băm gốc Merkle và nối thêm chữ ký dựa trên các điểm kiểm tra do Bor gửi và cuối cùng, người đề xuất sẽ chịu trách nhiệm thu thập tất cả chữ ký của trình xác thực cho điểm kiểm tra được chỉ định và nếu số lượng chữ ký đạt hơn 2/3, điểm kiểm tra sẽ được gửi trên Ethereum.
** Lớp Lor: **
Lớp nhà sản xuất khối, bao gồm một nhóm các nhà sản xuất khối thường xuyên được lựa chọn bởi một ủy ban xác thực trên lớp Heimdall, là một tập hợp con các trình xác thực chịu trách nhiệm tổng hợp các giao dịch trên chuỗi bên Polygon và tạo các khối. Lớp này định kỳ xuất bản các điểm kiểm tra cho lớp Heimdall, trong đó điểm kiểm tra đại diện cho ảnh chụp nhanh của chuỗi Bor, như thể hiện trong hình dưới đây.
2_Polygon Khả năng tương tác
2.1 Trạm kiểm soát
Cơ chế điểm kiểm tra là cơ chế đồng bộ hóa dữ liệu của lớp Bor với Ethereum, trong đó dữ liệu được đồng bộ hóa là một điểm kiểm tra, nghĩa là ảnh chụp nhanh dữ liệu khối của lớp Bor có trong khoảng điểm kiểm tra, mã nguồn như sau:
Người đề xuất: Người đề xuất, cũng được lựa chọn bởi người xác nhận, người tạo khối và người đề xuất là một tập hợp con của người xác thực và trách nhiệm của họ được xác định bởi cổ phần của họ trong nhóm tổng thể
RootHash: là một hàm băm Merkle được tạo từ khối Bor giữa StartBlock và EndBlock
Sau đây là mã giả cho khối Bor được đánh số từ 1 đến n để tạo giá trị RootHash:
Tóm lại, giá trị này là giá trị băm gốc của cây Merkel, bao gồm số khối trong tiêu đề khối Bor, dấu thời gian khối, giá trị băm gốc cây giao dịch tx hash và giá trị băm keccak256 được tính từ băm gốc cây nhận.
AccountRootHash: Một hàm băm Merkle của thông tin tài khoản liên quan đến trình xác thực cần được gửi đến từng điểm kiểm tra trên Ethereum và giá trị băm của thông tin tài khoản cá nhân được tính như sau:
AccountRootHash được tạo từ hàm băm gốc cây Merkle của tài khoản theo cách tương tự như giá trị RootHash.
2.2 Đồng bộ trạng thái
StateSync đề cập đến việc đồng bộ hóa dữ liệu Ethereum với chuỗi Polygon Matic, chủ yếu được chia thành các bước sau:
Đầu tiên, hợp đồng trên Ethereum sẽ kích hoạt hàm syncState() trong StateSender.sol để đồng bộ hóa trạng thái
Hàm syncState() sẽ phát ra một sự kiện event như sau:
Tất cả các trình xác thực trong lớp Heimdall sẽ nhận được sự kiện và một trong các trình xác thực sẽ đóng gói giao dịch vào khối heimdall và thêm nó vào danh sách đồng bộ hóa trạng thái đang chờ xử lý;
Nút của lớp bor sẽ lấy danh sách trên để được đồng bộ hóa thông qua API và bàn giao nó cho hợp đồng của lớp bor để xử lý logic nghiệp vụ hơn nữa.
2.3 Cầu đa giác
Polygon Bridge cho phép kênh chuỗi chéo hai chiều giữa Polygon và Ethereum, giúp người dùng dễ dàng chuyển mã thông báo giữa hai nền tảng chuỗi khác nhau mà không bị đe dọa bởi bên thứ ba và hạn chế thanh khoản thị trường. Có hai loại Polygon Bridge, PoS và Plasma, và cả hai đều có những điểm tương đồng sau trong việc chuyển giao tài sản giữa Polygon và Ethereum:
Trước tiên, bạn cần ánh xạ mã thông báo trên Ethereum sang Polygon, như thể hiện trong hình dưới đây:
Công nghệ neo hai chiều (Chốt hai chiều) cũng được sử dụng, tức là
a: Tất cả các tài sản mã thông báo được chuyển từ Ethereum sẽ bị khóa trên Ethereum trước tiên và cùng một số mã thông báo được ánh xạ sẽ được đúc trên Polygon;
b: Để rút tài sản mã thông báo về Ethereum, trước tiên bạn cần đốt các mã thông báo được ánh xạ này trên Polygon, sau đó mở khóa các tài sản bị khóa trên Ethereum;
Hình dưới đây cho thấy sự so sánh giữa PoS Bridge và Plasma Bridge:
Như có thể thấy từ hình trên, về mặt bảo mật, PoS Bridge dựa vào tính bảo mật của bộ trình xác thực bên ngoài, trong khi Plasma dựa vào tính bảo mật của chuỗi chính Ethereum. Đồng thời, khi người dùng thực hiện chuyển tài sản chuỗi chéo (chẳng hạn như chuyển mã thông báo từ Polygon sang Ethereum), PoS chỉ yêu cầu khoảng thời gian trạm kiểm soát, khoảng 20 phút đến 3 giờ, trong khi Plasma yêu cầu thời gian thử thách tranh chấp 7 ngày. Đồng thời, PoS hỗ trợ nhiều token tiêu chuẩn hơn, trong khi Plasma chỉ hỗ trợ ba loại, bao gồm: ETH, ERC20, ERC721.
3_Cross-chain messaging—PoS Bridge
Cầu nối PoS chủ yếu bao gồm hai chức năng: Tiền gửi đề cập đến việc chuyển tài sản của người dùng trên Ethereum sang Polygon và Rút tiền đề cập đến việc rút tài sản từ Polygon sang Ethereum.
Đặt cọc
Sau đây là ví dụ về người dùng Alice sử dụng PoS Bridge để gửi tài sản token từ tài khoản Ethereum của cô ấy đến tài khoản Polygon của cô ấy:
Nếu tài sản mã thông báo bạn muốn chuyển là ERC20, ERC721 hoặc ERC1155, bạn cần ủy quyền mã thông báo bạn muốn chuyển thông qua chức năng approtect. Như hình dưới đây, số lượng token tương ứng được ủy quyền cho hợp đồng erc20Prefer bằng cách gọi phương thức approtect trong hợp đồng token trên Ethereum.
Hàm approtect có hai tham số:
Spender: Địa chỉ đích nơi người dùng cho phép chi tiêu token
số tiền: Số lượng mã thông báo có thể được chi tiêu
Sau khi giao dịch ủy quyền trên được xác nhận, người dùng sẽ khóa token vào hợp đồng erc20Preliminary trên Ethereum bằng cách gọi phương thức depositFor() của hợp đồng RootChainManager. Ở đây, nếu loại tài sản được chuyển là ETH, depositEtherFor() được gọi. Cụ thể như sau:
Hàm depositFor có ba tham số:
user: Địa chỉ của người dùng đã nhận được token nạp tiền trên Polygon
rootToken: Địa chỉ token trên chuỗi Ethereum chính
depositData: Số lượng token được mã hóa bởi ABI
Sau đây là code cụ thể của hàm depositFor trong hợp đồng RootChainManager:
Phân tích mã nguồn, có thể thấy hàm đầu tiên lấy địa chỉ hợp đồng vị ngữ tương ứng với token, sau đó gọi hàm lockTokens() của nó để khóa token trong contract. Cuối cùng, syncState() sẽ được gọi để đồng bộ hóa trạng thái bởi _stateSender, chỉ có thể được gọi bởi người gửi trạng thái do admin đặt.
Hàm syncState() trong StateSender.sol sẽ submit sự kiện StateSynced, cụ thể:
Tham số đầu tiên là chỉ số số thứ tự của nhật ký, tham số thứ hai được sử dụng để xác minh xem người gọi có phải là địa chỉ hợp đồng hợp pháp đã đăng ký hay không và tham số thứ ba là dữ liệu cần được đồng bộ hóa với trạng thái. Giao dịch được thêm vào khối Heimdall và được thêm vào danh sách đồng bộ hóa trạng thái đang chờ xử lý.
Sau đó, sau khi nút bor trên chuỗi Polygon Matic lấy được sự kiện StateSynced trong danh sách đồng bộ hóa trạng thái thông qua API, hợp đồng ChildChainManager trên chuỗi sẽ gọi hàm onStateReceive(), được sử dụng để nhận dữ liệu đồng bộ hóa được tải lên từ Ethereum và tiến hành bước tiếp theo theo kiểu logic nghiệp vụ của đồng bộ hóa trạng thái:
dữ liệu: bytes32 syncType và bytes syncData. Khi syncType ánh xạ, syncData là địa chỉ rootToken được mã hóa, địa chỉ childToken và bytes32 tokenType và khi syncType được gửi tiền, syncData là địa chỉ người dùng được mã hóa. Địa chỉ rootToken và depositData của loại byte. depositData là số lượng trong REC20 và tokenId trong ERC721.
Vì đây là một doanh nghiệp Deposit, hàm _syncDeposit() sẽ được gọi. Hàm này trước tiên sẽ giải mã syncData theo định dạng tương ứng để lấy rootToken, địa chỉ người dùng và depositData tương ứng. Sau đó kiểm tra xem rootToken có token ánh xạ tương ứng trên đa giác hay không và gọi hàm deposit() của childToken nếu có.
Ở đây chúng tôi lấy hợp đồng token ERC20 làm ví dụ để giới thiệu cách nạp tiền vào hợp đồng token ánh xạ. Chức năng này chuyển số lượng token tương ứng vào tài khoản của người dùng.
Hàm có hai tham số:
user: Địa chỉ của người dùng đang nạp tiền
depositData: Số tiền được mã hóa trong ABI
Rút tiền
Sau đây là ví dụ về người dùng Alice sử dụng PoS Bridge để rút tiền được gửi trong tài khoản Polygon của cô ấy vào tài khoản Ethereum của cô ấy:
Khi người dùng rút tiền, cần đốt số lượng token được ánh xạ tương ứng bằng cách gọi hàm withdraw() của hợp đồng token ánh xạ trên chuỗi Polygon.
Rút tiền chỉ chứa một tham số: số lượng mã thông báo sẽ bị đốt cháy. Hàm withdraw() trong hợp đồng token tương ứng như sau:
Các giao dịch trên sẽ được đưa vào điểm kiểm tra sau khoảng 20 phút đến 3 giờ và trình xác thực sẽ gửi nó đến Ethereum.
Khi giao dịch được thêm vào điểm kiểm tra và gửi đến Ethereum, hàm exit() của hợp đồng RootChainManager trên Ethereum sẽ được gọi, chức năng này sẽ xác nhận tính hợp lệ của giao dịch rút tiền trên Polygon bằng cách xác minh nội dung điểm kiểm tra đã gửi và kích hoạt hợp đồng Vị ngữ tương ứng để mở khóa mã thông báo đã gửi của người dùng.
Proof proof inputData truyền vào hàm bao gồm các dữ liệu sau:
headerNumber: Chứa tiêu đề khối trạm kiểm soát cho giao dịch rút tiền
blockProof: Chứng minh rằng tiêu đề khối trong chuỗi con là nút lá của gốc merkle đã cam kết
blockNumber: Số block trên chuỗi con chứa giao dịch rút tiền
blockTime: Dấu thời gian khối của giao dịch rút tiền
txRoot: Giá trị gốc của cây giao dịch khối
receiptRoot: Giá trị gốc của cây biên nhận khối
Biên lai: Biên lai cho một giao dịch rút tiền
receiptProof: Merck proof of the withdrawal transaction receipt
branchMask: Đường dẫn đến biên lai được biểu thị bằng 32 bit trong cây biên nhận
receiptLogIndex: Chỉ mục nhật ký được đọc từ cây biên lai
Sau đây là logic cốt lõi của hàm, chủ yếu bao gồm ba phần: phần đầu tiên là xác minh tính hợp lệ của biên lai giao dịch rút tiền, phần thứ hai là xác minh xem điểm kiểm tra có chứa khối giao dịch hay không và phần thứ ba là gọi hàm exitTokens() trong hợp đồng vị ngữ để gửi token bị khóa cho người dùng.
Lấy hợp đồng ERC20Predicate làm ví dụ, nghĩa là sau khi giải mã người nhận, người gửi và số lượng mã thông báo được gửi từ nhật ký, một số lượng mã thông báo nhất định sẽ được gửi đến người dùng.
Theo phân tích mã nguồn của tiến trình nhắn tin xuyên chuỗi PoS Bridge, các cuộc gọi hàm của toàn bộ quá trình chỉ có thể được gọi bởi vai trò được chỉ định bởi trình xác thực, do đó tính bảo mật của chuỗi chéo chỉ được đảm bảo bởi PoS (công chứng viên).
4_Cross-chain messaging—Plasma Bridge
Plasma Bridge cũng bao gồm hai chức năng: Gửi và Rút tiền, như thể hiện trong hình sau:
Polygon Plasma hơi khác so với việc triển khai Bitcoin Plasma MVP được giới thiệu trong bài viết đầu tiên của loạt cầu nối chuỗi chéo của chúng tôi, chủ yếu sử dụng mô hình Plasma MoreVP dựa trên tài khoản. So với Plasma, thuật toán đã được cải thiện một phần trong phần rút tiền.
Vì việc chuyển mã thông báo của ERC20 và ERC721 được thực hiện thông qua nhật ký sự kiện tương tự như Bitcoin UTXO, trước tiên hãy giới thiệu sự kiện:
input1: Số dư tài khoản của người gửi trước khi chuyển khoản
input2: Số dư tài khoản của người nhận trước khi chuyển khoản
output1: Số dư tài khoản của người gửi sau khi chuyển khoản
Đầu ra 2: Số dư tài khoản của người nhận sau khi chuyển khoản
Thứ hai, vì MVP Plasma ban đầu được tạo ra bởi một nhà khai thác duy nhất hoặc một số lượng nhỏ các nhà sản xuất khối, có hai kịch bản tấn công trên Polygon:
** Nhà điều hành Ác: **
Bài viết trước (Nghiên cứu về bảo mật cầu nối xuyên chuỗi (2) | Cầu nối chuỗi chéo Nomad) đề cập rằng khi giao dịch của người dùng được Nhà điều hành đóng gói thành khối Plasma, sẽ không có sẵn dữ liệu ngoài chuỗi. Do đó, khi người dùng thực hiện giao dịch thoát, nếu họ bắt đầu rút tiền từ một giao dịch cũ hơn, Nhà điều hành có thể thách thức nó bằng một trong những giao dịch gần đây nhất của họ và thử thách sẽ thành công. Đồng thời, do cơ chế điểm kiểm tra PoS được sử dụng trong Plasma, nếu Nhà điều hành thông đồng với các trình xác thực để làm điều ác, họ thậm chí có thể giả mạo một số chuyển đổi trạng thái và gửi chúng cho Ethereum.
Người dùng ác:
Người dùng tiếp tục chi tiêu token trên Polygon sau khi bắt đầu giao dịch thoát, tương tự như chi tiêu gấp đôi chuỗi chéo.
Tóm lại, thuật toán Plasma MoreVp của Polygon sử dụng một thuật toán khác để tính mức độ ưu tiên thoát, đó là thoát khỏi giao dịch gần đây nhất. Vì phương thức này sử dụng sự kiện LogTransfer tương tự như UTXO, miễn là giao dịch hợp pháp của người dùng sử dụng đúng input1 và input2, ngay cả khi một số giao dịch độc hại được đóng gói trước giao dịch của người dùng, giao dịch của người dùng có thể được xử lý chính xác vì giao dịch của người dùng chỉ đến từ một đầu vào hợp lệ. Mã giả có liên quan như sau:
Đặt cọc
Hãy lấy ví dụ về người dùng Alice sử dụng Plasma Bridge để gửi tài sản mã thông báo từ tài khoản Ethereum của cô ấy đến tài khoản Polygon của cô ấy:
Trước hết, người dùng cũng cần ủy quyền các tài sản token cần chuyển cho người gửi tiền của hợp đồng Polygon trên chuỗi chính (Ethereum) thông qua chức năng approtect.
Sau khi giao dịch được ủy quyền được xác nhận, người dùng gọi hàm erc20token.deposit() để kích hoạt hàm depositERC20ForUser() của hợp đồng depositManager và nạp tài sản token ERC20 của người dùng.
Khi mainnet Ethereum xác nhận giao dịch tiền gửi, nó sẽ tạo một khối chỉ chứa giao dịch này và gửi nó đến hợp đồng childChain trên mạng Polygon bằng cơ chế đồng bộ hóa trạng thái, đúc cùng một lượng tiền được ánh xạ và gửi chúng vào tài khoản của người dùng trên Polygon.
Lưu ý: Theo phân tích mã nguồn của hợp đồng childChain, Plasma chỉ hỗ trợ ba loại, bao gồm: ETH, ERC20 và ERC721.
Rút tiền
Khi người dùng muốn sử dụng cầu nối Plasma để rút tài sản từ Polygon sang Ethereum, họ sẽ thực hiện các bước sau:
Người dùng đốt các tài sản token được ánh xạ trên chuỗi Polygon bằng cách gọi hàm withdraw() của đồng tiền được ánh xạ trên Polygon:
Bạn cũng có thể gọi triển khai giao diện withdrawStart() của Plasma Client trên Polygon.
Người dùng có thể gọi hàm startExitWithBurntTokens() trong hợp đồng ERC20Predicate, trước tiên sẽ gọi WithdrawManager.verifyInclusion() để xác minh xem điểm kiểm tra có chứa giao dịch rút tiền và biên lai tương ứng hay không, mã như sau:
Sau khi xác minh được thông qua, WithdrawManager.addExitToQueue() sẽ được gọi để chèn nó vào hàng đợi tin nhắn theo thứ tự ưu tiên:
Cuối cùng, addExitToQueue() gọi _addExitToQueue() để đúc NFT làm voucher hoàn tiền:
Người dùng chờ thời gian thử thách 7 ngày
Sau khi thời gian thử thách hoàn tất, bạn có thể gọi hàm WithdrawManager.processExits() để gửi token cho người dùng.
Hàm được chia thành hai bước: đầu tiên, xác nhận xem giao dịch rút tiền trong hàng đợi tin nhắn đã vượt qua thời gian thử thách 7 ngày hay chưa và nếu thời gian thử thách đã qua, hãy xóa giao dịch khỏi hàng đợi:
Sau đó, xác định xem NFT phiếu hoàn tiền đã bị xóa trong thời gian thử thách hay chưa và nếu không, NFT sẽ bị hủy và tài sản tương ứng sẽ được trả lại cho người dùng:
5_Polygon Lỗ hổng chi tiêu gấp đôi Plasma Bridge
Vào ngày 5 tháng 10 năm 2021, White Hat Gerhard Wagner đã đệ trình một lỗ hổng Polygon có thể dẫn đến một cuộc tấn công chi tiêu gấp đôi liên quan đến 850 triệu đô la, mà White Hat đã nhận được tiền thưởng lỗi chính thức trị giá 2,000,000 đô la từ Polygon.
Trong phần giới thiệu về Plasma Bridge ở trên, chúng ta biết rằng quy trình giao dịch Rút tiền hoàn chỉnh như sau:
- Người dùng bắt đầu giao dịch Rút tiền trên Polygon, đốt mã thông báo của người dùng trên Polygon;
- Sau một khoảng thời gian trạm kiểm soát (khoảng 30 phút), đợi giao dịch rút tiền được đưa vào trạm kiểm soát;
- Hơn 2/3 số người xác thực ký và gửi nó đến Ethereum, tại thời điểm đó người dùng gọi startExitWithBurntTokens () trong hợp đồng ERC20PredicateBurnOnly để xác minh xem điểm kiểm tra có chứa các giao dịch ghi hay không;
- Nếu xác minh được thông qua, phiếu hoàn lại NFT sẽ được đúc và gửi cho người dùng
- Người dùng chờ thời gian thử thách 7 ngày
- Gọi WithdrawManager.processExits() để hủy NFT và hoàn tiền cho người dùng
Lưu ý: Để ngăn chặn phát lại giao dịch (tấn công chi tiêu gấp đôi), Polygon sử dụng NFT làm bằng chứng hoàn tiền để xác định duy nhất giao dịch Rút tiền. Tuy nhiên, do lỗi tạo NFT ID, kẻ tấn công có thể xây dựng các tham số để tạo nhiều NFT với các ID khác nhau bằng cách sử dụng cùng một giao dịch Rút tiền hợp lệ, sau đó sử dụng các NFT này cho các giao dịch hoàn tiền, do đó đạt được “cuộc tấn công chi tiêu kép”.
Dưới đây là cái nhìn sâu hơn về cách tạo NFT:
Từ phân tích source code ở trên, có thể thấy addExitToQueue() sẽ gọi _addExitToQueue() để mint một NFT:
Theo phân tích tham số, exitid = priority, sau đó ID của NFT được tạo ra bởi sự dịch chuyển bên trái của mức độ ưu tiên độ tuổi trong Plasma Bridge.
Như có thể thấy từ phân tích mã nguồn ở trên, tuổi là giá trị trả về của hàm WithdrawManager.verifyInclusion(), trước tiên sẽ xác minh tính hợp lệ của giao dịch rút tiền, sau đó tạo độ tuổi tương ứng nếu xác minh được thông qua. Trong logic xác thực, giá trị được giải mã bởi dữ liệu tham số có thể điều khiển là branchMaskBytes:
Giá trị này cũng được sử dụng khi tạo tuổi:
Theo dõi hàm MerklePatriciaProof.verify() được gọi trong logic xác minh giao dịch và thấy rằng hàm gọi _getNibbleArray() để chuyển mã branchMaskBytes:
Tiếp tục theo dõi hàm giải mã, loại bỏ một phần giá trị khi chuyển mã branchMaskBytes và cách mất giá trị này sẽ khiến các giá trị khác nhau được chuyển mã để có được cùng một giá trị được giải mã. Cụ thể, nếu bit thập lục phân đầu tiên (nửa byte) của giá trị b được mã hóa hp đến là 1 hoặc 3, bit thập lục phân thứ hai được phân tích cú pháp. Nếu không, byte đầu tiên chỉ đơn giản là bị bỏ qua.
Nếu kẻ tấn công xây dựng tham số branchMaskBytes sao cho bit thập lục phân đầu tiên không bằng 1 và 3, có 14*16 = 224 cách để có được cùng một giá trị được chuyển mã.
Quy trình tấn công cụ thể như sau:
- Gửi một lượng lớn ETH / token vào Polygon thông qua Polygon Plasma
- Bắt đầu giao dịch Rút tiền trên Polygon và chờ thời gian thử thách 7 ngày
- Sửa đổi byte đầu tiên của tham số branchMaskBytes trong giao dịch rút tiền (cùng một giao dịch hợp lệ có thể được gửi lại tối đa 223 lần) và bắt đầu giao dịch rút tiền nhiều lần
Tóm lại, lỗ hổng này chủ yếu là do sự cố trong thiết kế thuật toán ID của NFT tạo ra voucher hoàn tiền để ngăn phát lại, dẫn đến cùng một giao dịch hoàn tiền có thể tạo ra các NFT khác nhau, dẫn đến tấn công chi tiêu gấp đôi. Nó chỉ ra rằng byte đầu tiên của mặt nạ nhánh được mã hóa phải luôn được 0x00. Cách khắc phục là kiểm tra xem byte đầu tiên của mặt nạ nhánh được mã hóa có 0x00 không và không coi đó là mặt nạ không chính xác.
Vâng, chia sẻ hôm nay đã kết thúc, trong số tiếp theo, Nhóm nghiên cứu bảo mật an ninh chuỗi Thành Đô sẽ giới thiệu nghiên cứu bảo mật của một dự án chuỗi chéo khác, hãy chờ đón nó.
Xem bản gốc
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.
Polygon Warrior Polygon Security Dialysis: Làm thế nào để đảm bảo an ninh và ổn định chuỗi chéo?
Tác giả: Chengdu Lian’an
Bản gốc: “Research on Cross-Chain Bridge Security (3)” | Lọc máu an toàn Polygon Warrior, làm thế nào để ngăn chặn việc mở “Pandora’s Box”?
Chào mừng bạn đến với loạt bài viết về “Nghiên cứu bảo mật cầu nối xuyên chuỗi” do Chengdu Chain Security sản xuất, trong bài viết trước (Nghiên cứu bảo mật cầu nối xuyên chuỗi (2) | Vụ cướp phi tập trung đầu tiên của cây cầu Nomad mang lại cho chúng ta điều gì?), Chúng tôi tiến hành phân tích kỹ thuật chuyên nghiệp về giao thức cầu Nomad một cách chi tiết.
Hôm nay, Nhóm nghiên cứu bảo mật chuỗi Thành Đô sẽ tiến hành lọc máu an toàn Polygon, một chiến binh đa giác, vì vậy hãy tiếp tục đọc.
1_Polygon là ai?
Polygon là giải pháp mở rộng quy mô lớp 2 của Ethereum, với tầm nhìn xây dựng internet blockchain của Ethereum. Polygon cung cấp một khung chung cho phép các nhà phát triển tận dụng bảo mật của Ethereum để tạo các chuỗi tùy chỉnh, tập trung vào ứng dụng và cung cấp một mạng có thể tương tác kết hợp nhiều sơ đồ mở rộng quy mô khác nhau như: zk-rollup, PoS, v.v. Trong số đó, Polygon PoS hiện là giải pháp mở rộng quy mô trưởng thành và nổi tiếng nhất trên Polygon. Nó sử dụng sidechain để xử lý giao dịch để đạt được mục đích cải thiện tốc độ giao dịch và tiết kiệm gas tiêu thụ, và cấu trúc mạng chủ yếu bao gồm ba lớp sau:
Lớp Ethereum:
Một loạt các hợp đồng trên mạng chính Ethereum, chủ yếu bao gồm: Hợp đồng Staking, Checkpoint và Reward, chịu trách nhiệm về các chức năng quản lý đặt cọc liên quan đến cổ phần PoS, bao gồm: cung cấp chức năng đặt cọc của token gốc MATIC, để bất kỳ ai đặt cược token đều có thể tham gia hệ thống với tư cách là người xác thực, xác minh việc chuyển đổi mạng Polygon để nhận phần thưởng đặt cược, trừng phạt người xác thực vì chữ ký kép, thời gian ngừng hoạt động của trình xác thực và các hành vi bất hợp pháp khác và lưu các điểm kiểm tra.
** Lớp Heimdall: **
Lớp xác thực bằng chứng cổ phần, bao gồm một tập hợp các nút PoS Heimdall, chịu trách nhiệm gửi các điểm kiểm tra của mạng Polygon đến mạng chính Ethereum trong khi lắng nghe một tập hợp các hợp đồng đặt cọc được triển khai trên Ethereum. Quá trình chính như sau: đầu tiên, chọn một tập hợp con các trình xác thực đang hoạt động trong nhóm trình xác thực làm nhà sản xuất khối, những người sẽ chịu trách nhiệm tạo các khối ở lớp Bor và phát chúng, sau đó xác thực hàm băm gốc Merkle và nối thêm chữ ký dựa trên các điểm kiểm tra do Bor gửi và cuối cùng, người đề xuất sẽ chịu trách nhiệm thu thập tất cả chữ ký của trình xác thực cho điểm kiểm tra được chỉ định và nếu số lượng chữ ký đạt hơn 2/3, điểm kiểm tra sẽ được gửi trên Ethereum.
** Lớp Lor: **
Lớp nhà sản xuất khối, bao gồm một nhóm các nhà sản xuất khối thường xuyên được lựa chọn bởi một ủy ban xác thực trên lớp Heimdall, là một tập hợp con các trình xác thực chịu trách nhiệm tổng hợp các giao dịch trên chuỗi bên Polygon và tạo các khối. Lớp này định kỳ xuất bản các điểm kiểm tra cho lớp Heimdall, trong đó điểm kiểm tra đại diện cho ảnh chụp nhanh của chuỗi Bor, như thể hiện trong hình dưới đây.
2_Polygon Khả năng tương tác
2.1 Trạm kiểm soát
Cơ chế điểm kiểm tra là cơ chế đồng bộ hóa dữ liệu của lớp Bor với Ethereum, trong đó dữ liệu được đồng bộ hóa là một điểm kiểm tra, nghĩa là ảnh chụp nhanh dữ liệu khối của lớp Bor có trong khoảng điểm kiểm tra, mã nguồn như sau:
Người đề xuất: Người đề xuất, cũng được lựa chọn bởi người xác nhận, người tạo khối và người đề xuất là một tập hợp con của người xác thực và trách nhiệm của họ được xác định bởi cổ phần của họ trong nhóm tổng thể
RootHash: là một hàm băm Merkle được tạo từ khối Bor giữa StartBlock và EndBlock
Sau đây là mã giả cho khối Bor được đánh số từ 1 đến n để tạo giá trị RootHash:
Tóm lại, giá trị này là giá trị băm gốc của cây Merkel, bao gồm số khối trong tiêu đề khối Bor, dấu thời gian khối, giá trị băm gốc cây giao dịch tx hash và giá trị băm keccak256 được tính từ băm gốc cây nhận.
AccountRootHash: Một hàm băm Merkle của thông tin tài khoản liên quan đến trình xác thực cần được gửi đến từng điểm kiểm tra trên Ethereum và giá trị băm của thông tin tài khoản cá nhân được tính như sau:
AccountRootHash được tạo từ hàm băm gốc cây Merkle của tài khoản theo cách tương tự như giá trị RootHash.
2.2 Đồng bộ trạng thái
StateSync đề cập đến việc đồng bộ hóa dữ liệu Ethereum với chuỗi Polygon Matic, chủ yếu được chia thành các bước sau:
Đầu tiên, hợp đồng trên Ethereum sẽ kích hoạt hàm syncState() trong StateSender.sol để đồng bộ hóa trạng thái
Hàm syncState() sẽ phát ra một sự kiện event như sau:
Tất cả các trình xác thực trong lớp Heimdall sẽ nhận được sự kiện và một trong các trình xác thực sẽ đóng gói giao dịch vào khối heimdall và thêm nó vào danh sách đồng bộ hóa trạng thái đang chờ xử lý;
Nút của lớp bor sẽ lấy danh sách trên để được đồng bộ hóa thông qua API và bàn giao nó cho hợp đồng của lớp bor để xử lý logic nghiệp vụ hơn nữa.
2.3 Cầu đa giác
Polygon Bridge cho phép kênh chuỗi chéo hai chiều giữa Polygon và Ethereum, giúp người dùng dễ dàng chuyển mã thông báo giữa hai nền tảng chuỗi khác nhau mà không bị đe dọa bởi bên thứ ba và hạn chế thanh khoản thị trường. Có hai loại Polygon Bridge, PoS và Plasma, và cả hai đều có những điểm tương đồng sau trong việc chuyển giao tài sản giữa Polygon và Ethereum:
a: Tất cả các tài sản mã thông báo được chuyển từ Ethereum sẽ bị khóa trên Ethereum trước tiên và cùng một số mã thông báo được ánh xạ sẽ được đúc trên Polygon;
b: Để rút tài sản mã thông báo về Ethereum, trước tiên bạn cần đốt các mã thông báo được ánh xạ này trên Polygon, sau đó mở khóa các tài sản bị khóa trên Ethereum;
Hình dưới đây cho thấy sự so sánh giữa PoS Bridge và Plasma Bridge:
Như có thể thấy từ hình trên, về mặt bảo mật, PoS Bridge dựa vào tính bảo mật của bộ trình xác thực bên ngoài, trong khi Plasma dựa vào tính bảo mật của chuỗi chính Ethereum. Đồng thời, khi người dùng thực hiện chuyển tài sản chuỗi chéo (chẳng hạn như chuyển mã thông báo từ Polygon sang Ethereum), PoS chỉ yêu cầu khoảng thời gian trạm kiểm soát, khoảng 20 phút đến 3 giờ, trong khi Plasma yêu cầu thời gian thử thách tranh chấp 7 ngày. Đồng thời, PoS hỗ trợ nhiều token tiêu chuẩn hơn, trong khi Plasma chỉ hỗ trợ ba loại, bao gồm: ETH, ERC20, ERC721.
3_Cross-chain messaging—PoS Bridge
Cầu nối PoS chủ yếu bao gồm hai chức năng: Tiền gửi đề cập đến việc chuyển tài sản của người dùng trên Ethereum sang Polygon và Rút tiền đề cập đến việc rút tài sản từ Polygon sang Ethereum.
Đặt cọc
Sau đây là ví dụ về người dùng Alice sử dụng PoS Bridge để gửi tài sản token từ tài khoản Ethereum của cô ấy đến tài khoản Polygon của cô ấy:
Hàm approtect có hai tham số:
Spender: Địa chỉ đích nơi người dùng cho phép chi tiêu token
số tiền: Số lượng mã thông báo có thể được chi tiêu
Hàm depositFor có ba tham số:
user: Địa chỉ của người dùng đã nhận được token nạp tiền trên Polygon
rootToken: Địa chỉ token trên chuỗi Ethereum chính
depositData: Số lượng token được mã hóa bởi ABI
Sau đây là code cụ thể của hàm depositFor trong hợp đồng RootChainManager:
Phân tích mã nguồn, có thể thấy hàm đầu tiên lấy địa chỉ hợp đồng vị ngữ tương ứng với token, sau đó gọi hàm lockTokens() của nó để khóa token trong contract. Cuối cùng, syncState() sẽ được gọi để đồng bộ hóa trạng thái bởi _stateSender, chỉ có thể được gọi bởi người gửi trạng thái do admin đặt.
Tham số đầu tiên là chỉ số số thứ tự của nhật ký, tham số thứ hai được sử dụng để xác minh xem người gọi có phải là địa chỉ hợp đồng hợp pháp đã đăng ký hay không và tham số thứ ba là dữ liệu cần được đồng bộ hóa với trạng thái. Giao dịch được thêm vào khối Heimdall và được thêm vào danh sách đồng bộ hóa trạng thái đang chờ xử lý.
dữ liệu: bytes32 syncType và bytes syncData. Khi syncType ánh xạ, syncData là địa chỉ rootToken được mã hóa, địa chỉ childToken và bytes32 tokenType và khi syncType được gửi tiền, syncData là địa chỉ người dùng được mã hóa. Địa chỉ rootToken và depositData của loại byte. depositData là số lượng trong REC20 và tokenId trong ERC721.
Hàm có hai tham số:
user: Địa chỉ của người dùng đang nạp tiền
depositData: Số tiền được mã hóa trong ABI
Rút tiền
Sau đây là ví dụ về người dùng Alice sử dụng PoS Bridge để rút tiền được gửi trong tài khoản Polygon của cô ấy vào tài khoản Ethereum của cô ấy:
Rút tiền chỉ chứa một tham số: số lượng mã thông báo sẽ bị đốt cháy. Hàm withdraw() trong hợp đồng token tương ứng như sau:
Các giao dịch trên sẽ được đưa vào điểm kiểm tra sau khoảng 20 phút đến 3 giờ và trình xác thực sẽ gửi nó đến Ethereum.
Khi giao dịch được thêm vào điểm kiểm tra và gửi đến Ethereum, hàm exit() của hợp đồng RootChainManager trên Ethereum sẽ được gọi, chức năng này sẽ xác nhận tính hợp lệ của giao dịch rút tiền trên Polygon bằng cách xác minh nội dung điểm kiểm tra đã gửi và kích hoạt hợp đồng Vị ngữ tương ứng để mở khóa mã thông báo đã gửi của người dùng.
Proof proof inputData truyền vào hàm bao gồm các dữ liệu sau:
headerNumber: Chứa tiêu đề khối trạm kiểm soát cho giao dịch rút tiền
blockProof: Chứng minh rằng tiêu đề khối trong chuỗi con là nút lá của gốc merkle đã cam kết
blockNumber: Số block trên chuỗi con chứa giao dịch rút tiền
blockTime: Dấu thời gian khối của giao dịch rút tiền
txRoot: Giá trị gốc của cây giao dịch khối
receiptRoot: Giá trị gốc của cây biên nhận khối
Biên lai: Biên lai cho một giao dịch rút tiền
receiptProof: Merck proof of the withdrawal transaction receipt
branchMask: Đường dẫn đến biên lai được biểu thị bằng 32 bit trong cây biên nhận
Sau đây là logic cốt lõi của hàm, chủ yếu bao gồm ba phần: phần đầu tiên là xác minh tính hợp lệ của biên lai giao dịch rút tiền, phần thứ hai là xác minh xem điểm kiểm tra có chứa khối giao dịch hay không và phần thứ ba là gọi hàm exitTokens() trong hợp đồng vị ngữ để gửi token bị khóa cho người dùng.
Theo phân tích mã nguồn của tiến trình nhắn tin xuyên chuỗi PoS Bridge, các cuộc gọi hàm của toàn bộ quá trình chỉ có thể được gọi bởi vai trò được chỉ định bởi trình xác thực, do đó tính bảo mật của chuỗi chéo chỉ được đảm bảo bởi PoS (công chứng viên).
4_Cross-chain messaging—Plasma Bridge
Plasma Bridge cũng bao gồm hai chức năng: Gửi và Rút tiền, như thể hiện trong hình sau:
Polygon Plasma hơi khác so với việc triển khai Bitcoin Plasma MVP được giới thiệu trong bài viết đầu tiên của loạt cầu nối chuỗi chéo của chúng tôi, chủ yếu sử dụng mô hình Plasma MoreVP dựa trên tài khoản. So với Plasma, thuật toán đã được cải thiện một phần trong phần rút tiền.
Vì việc chuyển mã thông báo của ERC20 và ERC721 được thực hiện thông qua nhật ký sự kiện tương tự như Bitcoin UTXO, trước tiên hãy giới thiệu sự kiện:
input1: Số dư tài khoản của người gửi trước khi chuyển khoản
input2: Số dư tài khoản của người nhận trước khi chuyển khoản
output1: Số dư tài khoản của người gửi sau khi chuyển khoản
Đầu ra 2: Số dư tài khoản của người nhận sau khi chuyển khoản
Thứ hai, vì MVP Plasma ban đầu được tạo ra bởi một nhà khai thác duy nhất hoặc một số lượng nhỏ các nhà sản xuất khối, có hai kịch bản tấn công trên Polygon:
** Nhà điều hành Ác: **
Bài viết trước (Nghiên cứu về bảo mật cầu nối xuyên chuỗi (2) | Cầu nối chuỗi chéo Nomad) đề cập rằng khi giao dịch của người dùng được Nhà điều hành đóng gói thành khối Plasma, sẽ không có sẵn dữ liệu ngoài chuỗi. Do đó, khi người dùng thực hiện giao dịch thoát, nếu họ bắt đầu rút tiền từ một giao dịch cũ hơn, Nhà điều hành có thể thách thức nó bằng một trong những giao dịch gần đây nhất của họ và thử thách sẽ thành công. Đồng thời, do cơ chế điểm kiểm tra PoS được sử dụng trong Plasma, nếu Nhà điều hành thông đồng với các trình xác thực để làm điều ác, họ thậm chí có thể giả mạo một số chuyển đổi trạng thái và gửi chúng cho Ethereum.
Người dùng ác:
Người dùng tiếp tục chi tiêu token trên Polygon sau khi bắt đầu giao dịch thoát, tương tự như chi tiêu gấp đôi chuỗi chéo.
Tóm lại, thuật toán Plasma MoreVp của Polygon sử dụng một thuật toán khác để tính mức độ ưu tiên thoát, đó là thoát khỏi giao dịch gần đây nhất. Vì phương thức này sử dụng sự kiện LogTransfer tương tự như UTXO, miễn là giao dịch hợp pháp của người dùng sử dụng đúng input1 và input2, ngay cả khi một số giao dịch độc hại được đóng gói trước giao dịch của người dùng, giao dịch của người dùng có thể được xử lý chính xác vì giao dịch của người dùng chỉ đến từ một đầu vào hợp lệ. Mã giả có liên quan như sau:
Đặt cọc
Hãy lấy ví dụ về người dùng Alice sử dụng Plasma Bridge để gửi tài sản mã thông báo từ tài khoản Ethereum của cô ấy đến tài khoản Polygon của cô ấy:
Trước hết, người dùng cũng cần ủy quyền các tài sản token cần chuyển cho người gửi tiền của hợp đồng Polygon trên chuỗi chính (Ethereum) thông qua chức năng approtect.
Sau khi giao dịch được ủy quyền được xác nhận, người dùng gọi hàm erc20token.deposit() để kích hoạt hàm depositERC20ForUser() của hợp đồng depositManager và nạp tài sản token ERC20 của người dùng.
Lưu ý: Theo phân tích mã nguồn của hợp đồng childChain, Plasma chỉ hỗ trợ ba loại, bao gồm: ETH, ERC20 và ERC721.
Rút tiền
Khi người dùng muốn sử dụng cầu nối Plasma để rút tài sản từ Polygon sang Ethereum, họ sẽ thực hiện các bước sau:
Bạn cũng có thể gọi triển khai giao diện withdrawStart() của Plasma Client trên Polygon.
Sau khi xác minh được thông qua, WithdrawManager.addExitToQueue() sẽ được gọi để chèn nó vào hàng đợi tin nhắn theo thứ tự ưu tiên:
Cuối cùng, addExitToQueue() gọi _addExitToQueue() để đúc NFT làm voucher hoàn tiền:
Người dùng chờ thời gian thử thách 7 ngày
Sau khi thời gian thử thách hoàn tất, bạn có thể gọi hàm WithdrawManager.processExits() để gửi token cho người dùng.
Hàm được chia thành hai bước: đầu tiên, xác nhận xem giao dịch rút tiền trong hàng đợi tin nhắn đã vượt qua thời gian thử thách 7 ngày hay chưa và nếu thời gian thử thách đã qua, hãy xóa giao dịch khỏi hàng đợi:
Sau đó, xác định xem NFT phiếu hoàn tiền đã bị xóa trong thời gian thử thách hay chưa và nếu không, NFT sẽ bị hủy và tài sản tương ứng sẽ được trả lại cho người dùng:
5_Polygon Lỗ hổng chi tiêu gấp đôi Plasma Bridge
Vào ngày 5 tháng 10 năm 2021, White Hat Gerhard Wagner đã đệ trình một lỗ hổng Polygon có thể dẫn đến một cuộc tấn công chi tiêu gấp đôi liên quan đến 850 triệu đô la, mà White Hat đã nhận được tiền thưởng lỗi chính thức trị giá 2,000,000 đô la từ Polygon.
Trong phần giới thiệu về Plasma Bridge ở trên, chúng ta biết rằng quy trình giao dịch Rút tiền hoàn chỉnh như sau:
- Người dùng bắt đầu giao dịch Rút tiền trên Polygon, đốt mã thông báo của người dùng trên Polygon;
- Sau một khoảng thời gian trạm kiểm soát (khoảng 30 phút), đợi giao dịch rút tiền được đưa vào trạm kiểm soát;
- Hơn 2/3 số người xác thực ký và gửi nó đến Ethereum, tại thời điểm đó người dùng gọi startExitWithBurntTokens () trong hợp đồng ERC20PredicateBurnOnly để xác minh xem điểm kiểm tra có chứa các giao dịch ghi hay không;
- Nếu xác minh được thông qua, phiếu hoàn lại NFT sẽ được đúc và gửi cho người dùng
- Người dùng chờ thời gian thử thách 7 ngày
- Gọi WithdrawManager.processExits() để hủy NFT và hoàn tiền cho người dùng
Lưu ý: Để ngăn chặn phát lại giao dịch (tấn công chi tiêu gấp đôi), Polygon sử dụng NFT làm bằng chứng hoàn tiền để xác định duy nhất giao dịch Rút tiền. Tuy nhiên, do lỗi tạo NFT ID, kẻ tấn công có thể xây dựng các tham số để tạo nhiều NFT với các ID khác nhau bằng cách sử dụng cùng một giao dịch Rút tiền hợp lệ, sau đó sử dụng các NFT này cho các giao dịch hoàn tiền, do đó đạt được “cuộc tấn công chi tiêu kép”.
Dưới đây là cái nhìn sâu hơn về cách tạo NFT:
Theo phân tích tham số, exitid = priority, sau đó ID của NFT được tạo ra bởi sự dịch chuyển bên trái của mức độ ưu tiên độ tuổi trong Plasma Bridge.
Giá trị này cũng được sử dụng khi tạo tuổi:
Nếu kẻ tấn công xây dựng tham số branchMaskBytes sao cho bit thập lục phân đầu tiên không bằng 1 và 3, có 14*16 = 224 cách để có được cùng một giá trị được chuyển mã.
Quy trình tấn công cụ thể như sau:
- Gửi một lượng lớn ETH / token vào Polygon thông qua Polygon Plasma
- Bắt đầu giao dịch Rút tiền trên Polygon và chờ thời gian thử thách 7 ngày
- Sửa đổi byte đầu tiên của tham số branchMaskBytes trong giao dịch rút tiền (cùng một giao dịch hợp lệ có thể được gửi lại tối đa 223 lần) và bắt đầu giao dịch rút tiền nhiều lần
Tóm lại, lỗ hổng này chủ yếu là do sự cố trong thiết kế thuật toán ID của NFT tạo ra voucher hoàn tiền để ngăn phát lại, dẫn đến cùng một giao dịch hoàn tiền có thể tạo ra các NFT khác nhau, dẫn đến tấn công chi tiêu gấp đôi. Nó chỉ ra rằng byte đầu tiên của mặt nạ nhánh được mã hóa phải luôn được 0x00. Cách khắc phục là kiểm tra xem byte đầu tiên của mặt nạ nhánh được mã hóa có 0x00 không và không coi đó là mặt nạ không chính xác.
Vâng, chia sẻ hôm nay đã kết thúc, trong số tiếp theo, Nhóm nghiên cứu bảo mật an ninh chuỗi Thành Đô sẽ giới thiệu nghiên cứu bảo mật của một dự án chuỗi chéo khác, hãy chờ đón nó.