一、漏洞概述
1000 Guess是一款基于以太坊的随机数竞猜游戏。 1000 Guess中的simplelottery
智能合约实现的‘_addguess’
函数存在安全漏洞,该漏洞源于程序使用公共可读取的变量生成随机值。攻击者可利用该漏洞一直获取奖励。
下面为CVE编号的详细内容。
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-12454
1000 Guess
作为以太坊的精彩读博游戏被爆出存在存储随机数预测漏洞。此合约通过生成随机数来预测获得大奖的钱包地址。在生成随机数的过程中,该合约通过sha256计算合约中的变量与当前数据块的信息。然而根据区块链的概念,链上的信息均是公开的,所有用户均可以获得。于是攻击者可以对此进行获取并进行投机取巧的操作。在本文中我将对合约进行详细介绍,并对此合约漏洞进行复现操作。
二、合约分析
合约代码如下地址:https://etherscan.io/address/0x386771ba5705da638d889381471ec1025a824f53#code
/**
* Source Code first verified at https://etherscan.io on Saturday, November 25, 2017
(UTC) */
pragma solidity ^0.4.11;
contract simplelottery {
enum State { Started, Locked }
State public state = State.Started;
struct Guess{
address addr;
//uint guess;
}
uint arraysize=1000;
uint constant maxguess=1000000;
uint bettingprice = 1 ether;
Guess[1000] guesses;
uint numguesses = 0;
bytes32 curhash = '';
uint _gameindex = 1;
uint _starttime = 0;
modifier inState(State _state) {
require(state == _state);
_;
}
address developer = 0x0;
address _winner = 0x0;
event SentPrizeToWinner(address winner, uint money, uint gameindex, uint lotterynumber, uint starttime, uint finishtime);
event SentDeveloperFee(uint amount, uint balance);
function simplelottery()
{
if(developer==address(0)){
developer = msg.sender;
state = State.Started;
_starttime = block.timestamp;
}
}
function setBettingCondition(uint _contenders, uint _bettingprice)
{
if(msg.sender != developer)
return;
arraysize = _contenders;
if(arraysize>1000)
arraysize = 1000;
bettingprice = _bettingprice;
}
function findWinner(uint value)
{
uint i = value % numguesses;
_winner = guesses[i].addr;
}
function getMaxContenders() constant returns(uint){
return arraysize;
}
function getBettingPrice() constant returns(uint){
return bettingprice;
}
function getDeveloperAddress() constant returns(address)
{
return developer;
}
function getDeveloperFee() constant returns(uint)
{
uint developerfee = this.balance/100;
return developerfee;
}
function getBalance() constant returns(uint)
{
return this.balance;
}
function getLotteryMoney() constant returns(uint)
{
uint developerfee = getDeveloperFee();
uint prize = (this.balance - developerfee);
return prize;
}
function getBettingStatus()
constant
returns (uint, uint, uint, uint, uint, uint, uint)
{
return ((uint)(state), _gameindex, _starttime, numguesses, getLotteryMoney(), this.balance, bettingprice);
}
function finish()
{
if(msg.sender != developer)
return;
_finish();
}
function _finish() private
{
state = State.Locked;
uint block_timestamp = block.timestamp;
uint lotterynumber = (uint(curhash)+block_timestamp)%(maxguess+1);
findWinner(lotterynumber);
uint prize = getLotteryMoney();
uint numwinners = 1;
uint remain = this.balance - (prize*numwinners);
_winner.transfer(prize);
SentPrizeToWinner(_winner, prize, _gameindex, lotterynumber, _starttime, block_timestamp);
// give delveoper the money left behind
developer.transfer(remain);
SentDeveloperFee(remain, this.balance);
numguesses = 0;
_gameindex++;
state = State.Started;
_starttime = block.timestamp;
}
function () payable
{
_addguess();
点击收藏 | 0
关注 | 1