├── LICENSE ├── README.md ├── contracts ├── Migrations.sol └── VulnerableOne.sol ├── migrations └── .gitignore ├── package-lock.json ├── package.json ├── test ├── VulnerableOne.js └── helpers │ └── expectThrow.js └── truffle.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Smartz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DVESC 2 | Damn Vulnerable Ethereum Smart Contract 3 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.4; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | modifier restricted() { 8 | if (msg.sender == owner) _; 9 | } 10 | 11 | constructor() public { 12 | owner = msg.sender; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /contracts/VulnerableOne.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.4.23; 2 | 3 | import "zeppelin-solidity/contracts/math/SafeMath.sol"; 4 | 5 | /* 6 | TZ: contract creator becomes the first superuser. Then he adds new users and superusers. Every superuser can add new users and superusers; 7 | If user sends ether, his balance is increased. Then he can withdraw eteher from his balance; 8 | */ 9 | 10 | 11 | contract VulnerableOne { 12 | using SafeMath for uint; 13 | 14 | struct UserInfo { 15 | uint256 created; 16 | uint256 ether_balance; 17 | } 18 | 19 | mapping (address => UserInfo) public users_map; 20 | 21 | // [HINT] [WARNING] can store bool value in UserInfo struct (only if there is no need for separate structure for other reasons) 22 | mapping (address => bool) is_super_user; 23 | 24 | address[] users_list; 25 | 26 | modifier onlySuperUser() { 27 | require(is_super_user[msg.sender] == true); 28 | _; 29 | } 30 | 31 | event UserAdded(address new_user); 32 | 33 | constructor() public { 34 | set_super_user(msg.sender); 35 | add_new_user(msg.sender); 36 | } 37 | 38 | // [HINT] [CRITICAL] forgotten critical access modifier onlySuperUser 39 | function set_super_user(address _new_super_user) public { 40 | is_super_user[_new_super_user] = true; 41 | } 42 | 43 | function pay() public payable { 44 | require(users_map[msg.sender].created != 0); 45 | users_map[msg.sender].ether_balance += msg.value; 46 | } 47 | 48 | function add_new_user(address _new_user) public onlySuperUser { 49 | require(users_map[_new_user].created == 0); 50 | // [HINT] [WARNING] no check of 0x0 address (0x0 can become a valid member of users_map) 51 | // [HINT] [SEVERE] event can be fired but user is not added yet 52 | emit UserAdded(_new_user); 53 | users_map[_new_user] = UserInfo({ created: now, ether_balance: 0 }); 54 | users_list.push(_new_user); 55 | } 56 | 57 | // [HINT] [CRITICAL] forgotten critical access modifier onlySuperUser 58 | function remove_user(address _remove_user) public { 59 | require(users_map[msg.sender].created != 0); 60 | delete(users_map[_remove_user]); 61 | bool shift = false; 62 | // [HINT] [SEVERE] loop can be out of gaz for seeking and copying addresses of asers 63 | // [HINT] [SEVERE] in the end of loop last element will be doubled, forgotten remove of it 64 | for (uint i=0; i { 2 | try { 3 | await promise; 4 | } catch (error) { 5 | // TODO: Check jump destination to destinguish between a throw 6 | // and an actual invalid jump. 7 | const invalidOpcode = error.message.search('invalid opcode') >= 0; 8 | // TODO: When we contract A calls contract B, and B throws, instead 9 | // of an 'invalid jump', we get an 'out of gas' error. How do 10 | // we distinguish this from an actual out of gas event? (The 11 | // testrpc log actually show an 'invalid jump' event.) 12 | const outOfGas = error.message.search('out of gas') >= 0; 13 | const revert = error.message.search('revert') >= 0; 14 | assert( 15 | invalidOpcode || outOfGas || revert, 16 | "Expected throw, got '" + error + "' instead", 17 | ); 18 | return; 19 | } 20 | assert.fail('Expected throw not received'); 21 | }; 22 | -------------------------------------------------------------------------------- /truffle.js: -------------------------------------------------------------------------------- 1 | require('babel-register'); 2 | require('babel-polyfill'); 3 | 4 | module.exports = { 5 | networks: { 6 | development: { 7 | host: "localhost", 8 | port: 8545, 9 | network_id: "*" // Match any network id 10 | } 11 | }, 12 | 13 | solc: { 14 | optimizer: { 15 | enabled: true, 16 | runs: 200 17 | } 18 | } 19 | }; 20 | --------------------------------------------------------------------------------