
Phân tích sâu về sự việc đánh cắp trên Optimism: Tấn công tái phát triển hợp đồng mạng Layer2
Tuyển chọn TechFlowTuyển chọn TechFlow

Phân tích sâu về sự việc đánh cắp trên Optimism: Tấn công tái phát triển hợp đồng mạng Layer2
Cobo phân tích và tái hiện sự kiện đánh cắp trên Optimism, thực hiện giải thích kỹ thuật toàn diện dưới nhiều góc độ như dòng thời gian, lộ trình tấn công, cơ chế sinh địa chỉ hợp đồng Ethereum và các chi tiết kỹ thuật khác.
Tổng quan sự việc
Vào cuối tháng 5 năm nay, Quỹ Optimism đã thuê nhà tạo lập thị trường Wintermute cung cấp thanh khoản cho token OP. Quỹ Optimism đã cung cấp 20 triệu token OP cho đội ngũ Wintermute để thực hiện hoạt động tạo lập thị trường. Trong quá trình này xảy ra sai sót trong giao tiếp: Đội ngũ Wintermute cung cấp cho Quỹ Optimism một địa chỉ ví nhận trên Layer1 (ETH), nhưng địa chỉ này chưa được triển khai trên Layer2 (Optimism). Sau khi Quỹ Optimism gửi tiền vào địa chỉ Layer2, đội ngũ Wintermute phát hiện vấn đề, tuy nhiên trước khi sửa chữa tài khoản, tin tặc đã giành quyền kiểm soát tài khoản và bắt đầu bán tháo lượng lớn token OP trong tài khoản.
Timeline
● 26/05 & 27/05 - Quỹ Optimism chuyển thử 1 OP và 1 triệu OP tới địa chỉ 0x4f3a120e72c76c22ae802d129f599bfdbc31cb81 do đội Wintermute cung cấp.
● 27/05 - Quỹ Optimism chuyển phần còn lại là 19 triệu OP vào địa chỉ trên.
● 30/05 - Đội Wintermute phát hiện lỗi tài khoản, liên hệ với Quỹ Optimism và nhóm Gnosis Safe để yêu cầu hỗ trợ lấy lại tiền. Sau khi thảo luận với Quỹ Optimism và nhóm Gnosis Safe, họ đánh giá rằng tài khoản vẫn an toàn, không thể bị kiểm soát bởi bên ngoài đội Wintermute, và có thể lấy lại tiền dưới sự hỗ trợ của nhóm Gnosis Safe. Kế hoạch sửa quyền tài khoản được lên vào ngày 07/06.
● 01/06 - Tin tặc triển khai hợp đồng tấn công, mã hóa cứng địa chỉ factory trong hợp đồng, cho thấy lúc này tin tặc đã xác định rõ quy trình tấn công.
● 05/06 - Tin tặc phát động tấn công, giành quyền kiểm soát tài khoản mục tiêu và rút 1 triệu OP đến Tornado Cash để đổi chéo.
● 09/06 - Đội Wintermute ra tuyên bố chịu trách nhiệm hoàn toàn về sự cố này, cam kết mua lại tất cả token mà tin tặc đã bán ra, đồng thời yêu cầu tin tặc hoàn trả lượng token còn lại. Bốn giờ sau khi tuyên bố được đưa ra, tin tặc tiếp tục rút thêm 1 triệu OP vào một tài khoản cá nhân khác.
Đường đi của cuộc tấn công
1. Tất cả các hợp đồng ví Gnosis Safe đều được triển khai thông qua hợp đồng Gnosis Safe Proxy Factory. Để giành quyền kiểm soát địa chỉ mục tiêu, cần gọi Proxy Factory triển khai một proxy contract tại địa chỉ đó.
2. Trước khi vụ tấn công xảy ra, hợp đồng Proxy Factory trên Layer2 (Optimism) chưa được triển khai. Tin tặc đã sao chép giao dịch triển khai factory từ Layer1 sang Layer2 để triển khai factory mới trên Layer2.
3. Trên Layer2, tin tặc nhiều lần gọi phương thức createProxy của factory để triển khai proxy contract, liên tục tăng giá trị nonce của factory contract cho đến khi thành công triển khai proxy tại đúng địa chỉ mục tiêu.
4. Khi gọi createProxy để triển khai proxy, tin tặc thiết lập tham số masterCopy là địa chỉ hợp đồng do chúng kiểm soát. masterCopy sẽ trở thành implementation của proxy. Như vậy, tin tặc giành được quyền kiểm soát địa chỉ mục tiêu.
Cơ chế sinh địa chỉ hợp đồng Ethereum
Để hiểu vì sao cuộc tấn công trên có thể triển khai hợp đồng tại một địa chỉ cụ thể, ta cần tìm hiểu cơ chế sinh địa chỉ hợp đồng Ethereum.
Địa chỉ hợp đồng không có khóa riêng tương ứng, mà được xác định ngay khi triển khai hợp đồng. Có hai cách triển khai hợp đồng: CREATE và CREATE2. Cơ chế sinh địa chỉ bằng CREATE như sau: địa chỉ khởi tạo và giá trị nonce liên kết với địa chỉ đó được mã hóa bằng RLP, dữ liệu mã hóa sau đó được băm bằng hàm sha3, lấy 20 byte cuối làm địa chỉ hợp đồng vừa triển khai.
địa_chỉ_mới = hash(người_gửi, nonce)
Có thể biểu diễn bằng mã JavaScript như sau:
const Web3 = require("web3");
const RLP = require("rlp");
const nonce = 0;
const account = "0xa990077c3205cbdf861e17fa532eeb069ce9ff96";
var e = RLP.encode(
[
account,
nonce,
],
);
const nonceHash = Web3.utils.sha3(Buffer.from(e));
console.log(nonceHash.substring(26));
Đối với tài khoản EOA, mỗi giao dịch thực hiện sẽ tăng nonce lên 1. Đối với tài khoản hợp đồng, mỗi lần tạo một hợp đồng mới thì nonce cũng tăng lên 1.
CREATE2 thường được gọi bởi hợp đồng thông minh, thuật toán sinh địa chỉ như sau (phương pháp mã hóa giống CREATE):
địa_chỉ_mới = hash(0xFF, người_gửi, salt, bytecode)
● 0xff là hằng số cố định
● người_gửi là địa chỉ khởi tạo triển khai
● salt là giá trị tùy ý do người_gửi chỉ định
● bytecode là mã hợp đồng cần triển khai
● CREATE2 tránh dùng giá trị nonce tăng dần, thay vào đó sử dụng giá trị salt do người_gửi kiểm soát, nhờ đó có thể kiểm soát tốt hơn địa chỉ triển khai hợp đồng.
Chi tiết kỹ thuật
Quá trình tạo proxy trên Layer1
Từ phần trước về cách sinh địa chỉ hợp đồng, ta biết rằng nếu muốn triển khai hợp đồng tại một địa chỉ nhất định trên Layer2, ta cần xác định trước cách triển khai trên Layer1. Proxy đa chữ ký (multisig) của Wintermute trên Layer1 được tạo bởi giao dịch https://etherscan.io/tx/0xd705178d68551a6a6f65ca74363264b32150857a26dd62c27f3f96b8ec69ca01, sử dụng factory là Proxy Factory 1.1.1. Phương thức tạo là createProxy. Cài đặt của phương thức ProxyFactory.createProxy như sau:
function createProxy(address masterCopy, bytes memory data)
public
returns (Proxy proxy)
{
proxy = new Proxy(masterCopy);
if (data.length > 0)
// solium-disable-next-line security/no-inline-assembly
assembly {
if eq(call(gas, proxy, 0, add(data, 0x20), mload(data), 0, 0), 0) { revert(0, 0) }
}
emit ProxyCreation(proxy);
}
Có thể thấy ở đây dùng từ khóa new để triển khai hợp đồng Proxy, từ khóa new底层 sử dụng opcode CREATE chứ không phải CREATE2.
Do đó, nếu ta gọi phương thức createProxy của cùng hợp đồng Proxy Factory 1.1.1 trên Layer2, miễn là đạt được cùng giá trị nonce khi triển khai, ta có thể tạo được proxy contract có địa chỉ giống hệt như trên Layer1.
Tái triển khai Gnosis Safe proxy factory 1.1.1 trên Layer2
Trước khi vụ tấn công xảy ra, Optimism chưa triển khai Gnosis Safe proxy factory 1.1.1. Vì vậy, ta cần triển khai trước hợp đồng factory này tại đúng địa chỉ như trên Layer1.
Địa chỉ của proxy factory 1.1.1 trên Layer1 là 0x76E2cFc1F5Fa8F6a5b3fC4c8F4788F0116861F9B, được tạo vào năm 2019 qua giao dịch https://etherscan.io/tx/0x75a42f240d229518979199f56cd7c82e4fc1f1a20ad9a4864c635354b4a34261.
Giải mã giao dịch này tại https://www.ethereumdecoder.com/?search=0x75a42f240d229518979199f56cd7c82e4fc1f1a20ad9a4864c635354b4a34261, dữ liệu gốc như sau:
{
"nonce": 2,
"gasPrice": {
"_hex": "0x02540be400"
},
"gasLimit": {
"_hex": "0x114343"
},
"to": "0x00",
"value": {
"_hex": "0x00"
},
"data": "xxxx...xxxx",
"v": 28,
"r": "0xc7841dea9284aeb34c2fb783843910adfdc057a37e92011676fddcc33c712926",
"s": "0x4e59ce12b6a06da8f7ec7c2d734787bd413c284fc3d1be3a70903ebc23945e8c"
}
Thấy v = 28, theo EIP-155, giao dịch có v = 27 hoặc v = 28 là giao dịch không dùng chữ ký EIP-155, tức là không đưa ChainID vào quá trình ký giao dịch.
Do đó, giao dịch triển khai hợp đồng trên Layer1 này có thể trực tiếp được tái sử dụng (replay) trên Layer2 (Optimism). Giao dịch tái sử dụng là https://optimistic.etherscan.io/tx/0x75a42f240d229518979199f56cd7c82e4fc1f1a20ad9a4864c635354b4a34261, triển khai một Gnosis Safe proxy factory mới, có địa chỉ giống hệt Layer1: https://optimistic.etherscan.io/address/0x76e2cfc1f5fa8f6a5b3fc4c8f4788f0116861f9b.

Trong hình có thể thấy, hợp đồng này được tạo ra cách đây 4 ngày khi cuộc tấn công bắt đầu, nhưng trước khi tạo đã có nhiều bản ghi gọi hợp đồng.
Lúc này giá trị nonce của tài khoản factory là 0. Với tài khoản hợp đồng, mỗi lần triển khai hợp đồng mới thì nonce tăng thêm 1. Do đó, chỉ cần tiếp tục gọi phương thức createProxy để triển khai proxy contract, tăng dần giá trị nonce, cuối cùng sẽ thu được proxy contract tại đúng địa chỉ mục tiêu.
Triển khai proxy tại địa chỉ mục tiêu trên Layer2
Hợp đồng tấn công 0xe7145dd6287ae53326347f3a6694fcf2954bcd8a[1]
Tin tặc sử dụng hợp đồng tấn công này để gọi hàng loạt phương thức createProxy của ProxyFactory[2], đồng thời thiết lập tham số masterCopy là địa chỉ chính nó, từ đó tạo ra hàng loạt proxy contract có implementation là chính hợp đồng tấn công. Như vậy, tin tặc giành quyền kiểm soát hợp đồng mục tiêu.
Chi tiết quá trình:
Tin tặc từ EOA address 1[3] nhiều lần gọi hợp đồng tấn công, mỗi giao dịch tạo 162 proxy contract, cuối cùng trong giao dịch https://optimistic.etherscan.io/tx/0x00a3da68f0f6a69cb067f09c3f7e741a01636cbc27a84c603b468f65271d415b đã tạo thành công hợp đồng tại địa chỉ 0x4f3a120e72c76c22ae802d129f599bfdbc31cb81.
Tin tặc sử dụng EOA address 2[4] làm chủ sở hữu (owner) của proxy để điều khiển thao tác trên hợp đồng mục tiêu.
> eth_call 0x4f3a120E72C76c22ae802D129F599BFDbc31cb81 owner()
0x0000000000000000000000008bcfe4f1358e50a1db10025d731c8b3b17f04dbb
Bài học kinh nghiệm
Khi ngày càng có nhiều giải pháp lớp thứ hai Ethereum (như Optimism, Arbitrum) và chuỗi phụ (sidechain) như xDai, Polygon xuất hiện, tài sản và dApp bị phân tán qua nhiều mạng lưới khác nhau. Tuy nhiên, giữa tài khoản EOA và tài khoản hợp đồng thông minh như Gnosis Safe có sự khác biệt rất lớn về hành vi xuyên chuỗi.
Tài khoản EOA dựa trên khóa riêng nên có thể sử dụng xuyên mạng, nhưng tài khoản hợp đồng không có khóa riêng và cần logic triển khai, khởi tạo phức tạp để xác định quyền kiểm soát và chức năng tài khoản, do đó không thể sử dụng trực tiếp xuyên chuỗi.
Tương tự, các hợp đồng hạ tầng trên các mạng khác nhau cũng không tự động xuất hiện hay sao chép tương đương.
Vì vậy, khi xử lý các mạng ở các cấp độ khác nhau, cần thận trọng với các thao tác liên quan đến hợp đồng: trước tiên phải kiểm tra xem địa chỉ, nội dung và trạng thái hợp đồng trên mạng đích và mạng chính ETH có giống nhau hay không; trong các trường hợp có logic phức tạp, thậm chí cần kiểm tra tính tương thích về đặc điểm mạng đích và chức năng hợp đồng. Không nên mặc định cho rằng địa chỉ Layer1 sẽ được ánh xạ vô điều kiện sang Layer2 hay sidechain, để tránh tái diễn những sự cố đáng tiếc như vụ mất mát của đội Wintermute.
Tài liệu tham khảo
[1] Hợp đồng tấn công: https://optimistic.etherscan.io/address/0xe7145dd6287ae53326347f3a6694fcf2954bcd8a
[2] ProxyFactory: https://optimistic.etherscan.io/address/0x76e2cfc1f5fa8f6a5b3fc4c8f4788f0116861f9b#code
[3] EOA address 1 của tin tặc: https://optimistic.etherscan.io/address/0x60B28637879B5a09D21B68040020FFbf7dbA5107
[4] EOA address 2 của tin tặc: https://optimistic.etherscan.io/address/0x8bcfe4f1358e50a1db10025d731c8b3b17f04dbb
Chào mừng tham gia cộng đồng chính thức TechFlow
Nhóm Telegram:https://t.me/TechFlowDaily
Tài khoản Twitter chính thức:https://x.com/TechFlowPost
Tài khoản Twitter tiếng Anh:https://x.com/BlockFlow_News














