Add SB Curated (copied from the smartbugs repository).
This commit is contained in:
35
dataset/denial_of_service/README.md
Executable file
35
dataset/denial_of_service/README.md
Executable file
@@ -0,0 +1,35 @@
|
||||
# Denial Of Service
|
||||
Including gas limit reached, unexpected throw, unexpected kill, access control breached.
|
||||
|
||||
Denial of service is deadly in the world of Ethereum: while other types of applications can eventually recover, smart contracts can be taken offline forever by just one of these attacks. Many ways lead to denials of service, including maliciously behaving when being the recipient of a transaction, artificially increasing the gas necessary to compute a function, abusing access controls to access private components of smart contracts, taking advantage of mixups and negligence, etc. This class of attack includes many different variants and will probably see a lot of development in the years to come.
|
||||
|
||||
Loss: estimated at 514,874 ETH (~300M USD at the time)
|
||||
|
||||
## Attack Scenario
|
||||
An auction contract allows its users to bid on different assets.
|
||||
To bid, a user must call a bid(uint object) function with the desired amount of ether. The auction contract will store the ether in escrow until the object's owner accepts the bid or the initial bidder cancels it. This means that the auction contract must hold the full value of any unresolved bid in its balance.
|
||||
The auction contract also contains a withdraw(uint amount) function which allows admins to retrieve funds from the contract. As the function sends the amount to a hardcoded address, the developers have decided to make the function public.
|
||||
An attacker sees a potential attack and calls the function, directing all the contract's funds to its admins. This destroys the promise of escrow and blocks all the pending bids.
|
||||
While the admins might return the escrowed money to the contract, the attacker can continue the attack by simply withdrawing the funds again.
|
||||
|
||||
## Examples
|
||||
In the following example (inspired by King of the Ether) a function of a game contract allows you to become the president if you publicly bribe the previous one. Unfortunately, if the previous president is a smart contract and causes reversion on payment, the transfer of power will fail and the malicious smart contract will remain president forever. Sounds like a dictatorship to me:
|
||||
```
|
||||
function becomePresident() payable {
|
||||
require(msg.value >= price); // must pay the price to become president
|
||||
president.transfer(price); // we pay the previous president
|
||||
president = msg.sender; // we crown the new president
|
||||
price = price * 2; // we double the price to become president
|
||||
}
|
||||
```
|
||||
In this second example, a caller can decide who the next function call will reward. Because of the expensive instructions in the for loop, an attacker can introduce a number too large to iterate on (due to gas block limitations in Ethereum) which will effectively block the function from functioning.
|
||||
```
|
||||
function selectNextWinners(uint256 _largestWinner) {
|
||||
for(uint256 i = 0; i < largestWinner, i++) {
|
||||
// heavy code
|
||||
}
|
||||
largestWinner = _largestWinner;
|
||||
}
|
||||
```
|
||||
## References
|
||||
Taken from [DASP TOP10](https://dasp.co/)
|
||||
29
dataset/denial_of_service/auction.sol
Normal file
29
dataset/denial_of_service/auction.sol
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* @source: https://github.com/trailofbits/not-so-smart-contracts/blob/master/denial_of_service/auction.sol
|
||||
* @author: -
|
||||
* @vulnerable_at_lines: 23
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.15;
|
||||
|
||||
//Auction susceptible to DoS attack
|
||||
contract DosAuction {
|
||||
address currentFrontrunner;
|
||||
uint currentBid;
|
||||
|
||||
//Takes in bid, refunding the frontrunner if they are outbid
|
||||
function bid() payable {
|
||||
require(msg.value > currentBid);
|
||||
|
||||
//If the refund fails, the entire transaction reverts.
|
||||
//Therefore a frontrunner who always fails will win
|
||||
if (currentFrontrunner != 0) {
|
||||
//E.g. if recipients fallback function is just revert()
|
||||
// <yes> <report> DENIAL_OF_SERVICE
|
||||
require(currentFrontrunner.send(currentBid));
|
||||
}
|
||||
|
||||
currentFrontrunner = msg.sender;
|
||||
currentBid = msg.value;
|
||||
}
|
||||
}
|
||||
36
dataset/denial_of_service/dos_address.sol
Normal file
36
dataset/denial_of_service/dos_address.sol
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* @source: https://github.com/SmartContractSecurity/SWC-registry/blob/master/test_cases/dos_gas_limit/dos_address.sol
|
||||
* @author: -
|
||||
* @vulnerable_at_lines: 16,17,18
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.25;
|
||||
|
||||
contract DosGas {
|
||||
|
||||
address[] creditorAddresses;
|
||||
bool win = false;
|
||||
|
||||
function emptyCreditors() public {
|
||||
// <yes> <report> DENIAL_OF_SERVICE
|
||||
if(creditorAddresses.length>1500) {
|
||||
creditorAddresses = new address[](0);
|
||||
win = true;
|
||||
}
|
||||
}
|
||||
|
||||
function addCreditors() public returns (bool) {
|
||||
for(uint i=0;i<350;i++) {
|
||||
creditorAddresses.push(msg.sender);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function iWin() public view returns (bool) {
|
||||
return win;
|
||||
}
|
||||
|
||||
function numberCreditors() public view returns (uint) {
|
||||
return creditorAddresses.length;
|
||||
}
|
||||
}
|
||||
47
dataset/denial_of_service/dos_number.sol
Normal file
47
dataset/denial_of_service/dos_number.sol
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* @source: https://github.com/SmartContractSecurity/SWC-registry/blob/master/test_cases/dos_gas_limit/dos_number.sol
|
||||
* @author: -
|
||||
* @vulnerable_at_lines: 18,19,20,21,22
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.25;
|
||||
|
||||
contract DosNumber {
|
||||
|
||||
uint numElements = 0;
|
||||
uint[] array;
|
||||
|
||||
function insertNnumbers(uint value,uint numbers) public {
|
||||
|
||||
// Gas DOS if number > 382 more or less, it depends on actual gas limit
|
||||
// <yes> <report> DENIAL_OF_SERVICE
|
||||
for(uint i=0;i<numbers;i++) {
|
||||
if(numElements == array.length) {
|
||||
array.length += 1;
|
||||
}
|
||||
array[numElements++] = value;
|
||||
}
|
||||
}
|
||||
|
||||
function clear() public {
|
||||
require(numElements>1500);
|
||||
numElements = 0;
|
||||
}
|
||||
|
||||
// Gas DOS clear
|
||||
function clearDOS() public {
|
||||
|
||||
// number depends on actual gas limit
|
||||
require(numElements>1500);
|
||||
array = new uint[](0);
|
||||
numElements = 0;
|
||||
}
|
||||
|
||||
function getLengthArray() public view returns(uint) {
|
||||
return numElements;
|
||||
}
|
||||
|
||||
function getRealLengthArray() public view returns(uint) {
|
||||
return array.length;
|
||||
}
|
||||
}
|
||||
27
dataset/denial_of_service/dos_simple.sol
Normal file
27
dataset/denial_of_service/dos_simple.sol
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* @source: https://github.com/SmartContractSecurity/SWC-registry/blob/master/test_cases/dos_gas_limit/dos_simple.sol
|
||||
* @author: -
|
||||
* @vulnerable_at_lines: 17,18
|
||||
*/
|
||||
|
||||
|
||||
pragma solidity ^0.4.25;
|
||||
|
||||
contract DosOneFunc {
|
||||
|
||||
address[] listAddresses;
|
||||
|
||||
function ifillArray() public returns (bool){
|
||||
if(listAddresses.length<1500) {
|
||||
// <yes> <report> DENIAL_OF_SERVICE
|
||||
for(uint i=0;i<350;i++) {
|
||||
listAddresses.push(msg.sender);
|
||||
}
|
||||
return true;
|
||||
|
||||
} else {
|
||||
listAddresses = new address[](0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
124
dataset/denial_of_service/list_dos.sol
Normal file
124
dataset/denial_of_service/list_dos.sol
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* @source: https://etherscan.io/address/0xf45717552f12ef7cb65e95476f217ea008167ae3#code
|
||||
* @author: -
|
||||
* @vulnerable_at_lines: 46,48
|
||||
*/
|
||||
|
||||
//added pragma version
|
||||
pragma solidity ^0.4.0;
|
||||
|
||||
contract Government {
|
||||
|
||||
// Global Variables
|
||||
uint32 public lastCreditorPayedOut;
|
||||
uint public lastTimeOfNewCredit;
|
||||
uint public profitFromCrash;
|
||||
address[] public creditorAddresses;
|
||||
uint[] public creditorAmounts;
|
||||
address public corruptElite;
|
||||
mapping (address => uint) buddies;
|
||||
uint constant TWELVE_HOURS = 43200;
|
||||
uint8 public round;
|
||||
|
||||
function Government() {
|
||||
// The corrupt elite establishes a new government
|
||||
// this is the commitment of the corrupt Elite - everything that can not be saved from a crash
|
||||
profitFromCrash = msg.value;
|
||||
corruptElite = msg.sender;
|
||||
lastTimeOfNewCredit = block.timestamp;
|
||||
}
|
||||
|
||||
function lendGovernmentMoney(address buddy) returns (bool) {
|
||||
uint amount = msg.value;
|
||||
// check if the system already broke down. If for 12h no new creditor gives new credit to the system it will brake down.
|
||||
// 12h are on average = 60*60*12/12.5 = 3456
|
||||
if (lastTimeOfNewCredit + TWELVE_HOURS < block.timestamp) {
|
||||
// Return money to sender
|
||||
msg.sender.send(amount);
|
||||
// Sends all contract money to the last creditor
|
||||
creditorAddresses[creditorAddresses.length - 1].send(profitFromCrash);
|
||||
corruptElite.send(this.balance);
|
||||
// Reset contract state
|
||||
lastCreditorPayedOut = 0;
|
||||
lastTimeOfNewCredit = block.timestamp;
|
||||
profitFromCrash = 0;
|
||||
// <yes> <report> DENIAL_OF_SERVICE
|
||||
creditorAddresses = new address[](0);
|
||||
// <yes> <report> DENIAL_OF_SERVICE
|
||||
creditorAmounts = new uint[](0);
|
||||
round += 1;
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
// the system needs to collect at least 1% of the profit from a crash to stay alive
|
||||
if (amount >= 10 ** 18) {
|
||||
// the System has received fresh money, it will survive at leat 12h more
|
||||
lastTimeOfNewCredit = block.timestamp;
|
||||
// register the new creditor and his amount with 10% interest rate
|
||||
creditorAddresses.push(msg.sender);
|
||||
creditorAmounts.push(amount * 110 / 100);
|
||||
// now the money is distributed
|
||||
// first the corrupt elite grabs 5% - thieves!
|
||||
corruptElite.send(amount * 5/100);
|
||||
// 5% are going into the economy (they will increase the value for the person seeing the crash comming)
|
||||
if (profitFromCrash < 10000 * 10**18) {
|
||||
profitFromCrash += amount * 5/100;
|
||||
}
|
||||
// if you have a buddy in the government (and he is in the creditor list) he can get 5% of your credits.
|
||||
// Make a deal with him.
|
||||
if(buddies[buddy] >= amount) {
|
||||
buddy.send(amount * 5/100);
|
||||
}
|
||||
buddies[msg.sender] += amount * 110 / 100;
|
||||
// 90% of the money will be used to pay out old creditors
|
||||
if (creditorAmounts[lastCreditorPayedOut] <= address(this).balance - profitFromCrash) {
|
||||
creditorAddresses[lastCreditorPayedOut].send(creditorAmounts[lastCreditorPayedOut]);
|
||||
buddies[creditorAddresses[lastCreditorPayedOut]] -= creditorAmounts[lastCreditorPayedOut];
|
||||
lastCreditorPayedOut += 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
msg.sender.send(amount);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fallback function
|
||||
function() {
|
||||
lendGovernmentMoney(0);
|
||||
}
|
||||
|
||||
function totalDebt() returns (uint debt) {
|
||||
for(uint i=lastCreditorPayedOut; i<creditorAmounts.length; i++){
|
||||
debt += creditorAmounts[i];
|
||||
}
|
||||
}
|
||||
|
||||
function totalPayedOut() returns (uint payout) {
|
||||
for(uint i=0; i<lastCreditorPayedOut; i++){
|
||||
payout += creditorAmounts[i];
|
||||
}
|
||||
}
|
||||
|
||||
// better don't do it (unless you are the corrupt elite and you want to establish trust in the system)
|
||||
function investInTheSystem() {
|
||||
profitFromCrash += msg.value;
|
||||
}
|
||||
|
||||
// From time to time the corrupt elite inherits it's power to the next generation
|
||||
function inheritToNextGeneration(address nextGeneration) {
|
||||
if (msg.sender == corruptElite) {
|
||||
corruptElite = nextGeneration;
|
||||
}
|
||||
}
|
||||
|
||||
function getCreditorAddresses() returns (address[]) {
|
||||
return creditorAddresses;
|
||||
}
|
||||
|
||||
function getCreditorAmounts() returns (uint[]) {
|
||||
return creditorAmounts;
|
||||
}
|
||||
}
|
||||
28
dataset/denial_of_service/send_loop.sol
Normal file
28
dataset/denial_of_service/send_loop.sol
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* @source: https://consensys.github.io/smart-contract-best-practices/known_attacks/#dos-with-unexpected-revert
|
||||
* @author: ConsenSys Diligence
|
||||
* @vulnerable_at_lines: 24
|
||||
* Modified by Bernhard Mueller
|
||||
*/
|
||||
|
||||
pragma solidity 0.4.24;
|
||||
|
||||
contract Refunder {
|
||||
|
||||
address[] private refundAddresses;
|
||||
mapping (address => uint) public refunds;
|
||||
|
||||
constructor() {
|
||||
refundAddresses.push(0x79B483371E87d664cd39491b5F06250165e4b184);
|
||||
refundAddresses.push(0x79B483371E87d664cd39491b5F06250165e4b185);
|
||||
}
|
||||
|
||||
// bad
|
||||
function refundAll() public {
|
||||
for(uint x; x < refundAddresses.length; x++) { // arbitrary length iteration based on how many addresses participated
|
||||
// <yes> <report> DENIAL_OF_SERVICE
|
||||
require(refundAddresses[x].send(refunds[refundAddresses[x]])); // doubly bad, now a single failure on send will hold up all funds
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user