HCTF2018智能合约两则Writeup
pragma solidity ^0.4.24; * @title SafeMath * @dev Math operations with safety checks that revert on 2018-11-12 17:25:35 Author: lorexxar.cn(查看原文) 阅读量:427 收藏

pragma solidity ^0.4.24;

* @title SafeMath

* @dev Math operations with safety checks that revert on error

*/

library SafeMath {

* @dev Multiplies two numbers, reverts on overflow.

*/

function mul(uint256 a, uint256 b) internal pure returns (uint256) {

if (a == 0) {

return 0;

}

uint256 c = a * b;

require(c / a == b);

return c;

}

* @dev Integer division of two numbers truncating the quotient, reverts on division by zero.

*/

function div(uint256 a, uint256 b) internal pure returns (uint256) {

require(b > 0);

uint256 c = a / b;

return c;

}

* @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).

*/

function sub(uint256 a, uint256 b) internal pure returns (uint256) {

require(b <= a);

uint256 c = a - b;

return c;

}

* @dev Adds two numbers, reverts on overflow.

*/

function add(uint256 a, uint256 b) internal pure returns (uint256) {

uint256 c = a + b;

require(c >= a);

return c;

}

}

* @title Standard ERC20 token

*

* @dev Implementation of the basic standard token.

* https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md

* Originally based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol

*/

contract ERC20{

using SafeMath for uint256;

mapping (address => uint256) public balances;

uint256 public _totalSupply;

* @dev Total number of tokens in existence

*/

function totalSupply() public view returns (uint256) {

return _totalSupply;

}

* @dev Gets the balance of the specified address.

* @param owner The address to query the balance of.

* @return An uint256 representing the amount owned by the passed address.

*/

function balanceOf(address owner) public view returns (uint256) {

return balances[owner];

}

function transfer(address _to, uint _value) public returns (bool success){

balances[msg.sender] = balances[msg.sender].sub(_value);

balances[_to] = balances[_to].add(_value);

return true;

}

}

contract B2GBToken is ERC20 {

string public constant name = "test";

string public constant symbol = "test";

uint8 public constant decimals = 18;

uint256 public constant _airdropAmount = 1000;

uint256 public constant INITIAL_SUPPLY = 20000000000 * (10 ** uint256(decimals));

mapping(address => bool) initialized;

* @dev Constructor that gives msg.sender all of existing tokens.

*/

constructor() public {

initialized[msg.sender] = true;

_totalSupply = INITIAL_SUPPLY;

balances[msg.sender] = INITIAL_SUPPLY;

}

function AirdropCheck() internal returns (bool success){

if (!initialized[msg.sender]) {

initialized[msg.sender] = true;

balances[msg.sender] = _airdropAmount;

_totalSupply += _airdropAmount;

}

return true;

}

}

contract Bet2Loss is B2GBToken{

uint constant MIN_JACKPOT_BET = 0.1 ether;

uint constant MIN_BET = 1;

uint constant MAX_BET = 100000;

uint constant MAX_MODULO = 100;

uint constant BET_EXPIRATION_BLOCKS = 250;

address constant DUMMY_ADDRESS = 0xACB7a6Dc0215cFE38e7e22e3F06121D2a1C42f6C;

address public owner;

address private nextOwner;

uint public maxProfit;

address public secretSigner;

uint128 public jackpotSize;

uint128 public lockedInBets;

struct Bet {

uint betnumber;

uint8 modulo;

uint40 placeBlockNumber;

uint40 mask;

address gambler;

}

mapping (uint => Bet) bets;

event FailedPayment(address indexed beneficiary, uint amount);

event Payment(address indexed beneficiary, uint amount);

event Commit(uint commit);

event GetFlag(

string b64email,

string back

);

constructor () public {

owner = msg.sender;

secretSigner = DUMMY_ADDRESS;

}

modifier onlyOwner {

require (msg.sender == owner, "OnlyOwner methods called by non-owner.");

_;

}

function setSecretSigner(address newSecretSigner) external onlyOwner {

secretSigner = newSecretSigner;

}

function placeBet(uint betMask, uint modulo, uint betnumber, uint commitLastBlock, uint commit, bytes32 r, bytes32 s, uint8 v) external payable {

AirdropCheck();

Bet storage bet = bets[commit];

require (bet.gambler == address(0), "Bet should be in a 'clean' state.");

require (balances[msg.sender] >= betnumber, "no more balances");

require (modulo > 1 && modulo <= MAX_MODULO, "Modulo should be within range.");

require (betMask >= 0 && betMask < modulo, "Mask should be within range.");

require (betnumber > 0 && betnumber < 1000, "BetNumber should be within range.");

require (block.number <= commitLastBlock, "Commit has expired.");

bytes32 signatureHash = keccak256(abi.encodePacked(commitLastBlock, commit));

require (secretSigner == ecrecover(signatureHash, v, r, s), "ECDSA signature is not valid.");

uint possibleWinAmount;

possibleWinAmount = getDiceWinAmount(betnumber, modulo);

lockedInBets += uint128(possibleWinAmount);

require (lockedInBets <= balances[owner], "Cannot afford to lose this bet.");

balances[msg.sender] = balances[msg.sender].sub(betnumber);

emit Commit(commit);

bet.betnumber = betnumber;

bet.modulo = uint8(modulo);

bet.placeBlockNumber = uint40(block.number);

bet.mask = uint40(betMask);

bet.gambler = msg.sender;

}

function settleBet(uint reveal) external {

AirdropCheck();

uint commit = uint(keccak256(abi.encodePacked(reveal)));

Bet storage bet = bets[commit];

uint placeBlockNumber = bet.placeBlockNumber;

require (block.number > placeBlockNumber, "settleBet in the same block as placeBet, or before.");

require (block.number <= placeBlockNumber + BET_EXPIRATION_BLOCKS, "Blockhash can't be queried by EVM.");

settleBetCommon(bet, reveal);

}

function settleBetCommon(Bet storage bet, uint reveal) private {

uint betnumber = bet.betnumber;

uint mask = bet.mask;

uint modulo = bet.modulo;

uint placeBlockNumber = bet.placeBlockNumber;

address gambler = bet.gambler;

require (betnumber != 0, "Bet should be in an 'active' state");

bytes32 entropy = keccak256(abi.encodePacked(reveal, placeBlockNumber));

uint dice = uint(entropy) % modulo;

uint diceWinAmount;

diceWinAmount = getDiceWinAmount(betnumber, modulo);

uint diceWin = 0;

if (dice == mask){

diceWin = diceWinAmount;

}

lockedInBets -= uint128(diceWinAmount);

sendFunds(gambler, diceWin == 0 ? 1 wei : diceWin , diceWin);

}

function getDiceWinAmount(uint amount, uint modulo) private pure returns (uint winAmount) {

winAmount = amount * modulo;

}

function sendFunds(address beneficiary, uint amount, uint successLogAmount) private {

transfer(beneficiary, amount);

emit Payment(beneficiary, successLogAmount);

}

function PayForFlag(string b64email) public payable returns (bool success){

require (balances[msg.sender] > 10000000);

emit GetFlag(b64email, "Get flag!");

}

}


文章来源: https://lorexxar.cn/2018/11/12/hctf2019_contract_wp/
如有侵权请联系:admin#unsafe.sh