近年来,各个大型CTF(Capture The Flag,中文一般译作夺旗赛,在网络安全领域中指的是网络安全技术人员之间进行技术竞技的一种比赛形式)比赛中都有了区块链攻防的身影,而且出现的题目绝大多数都是区块链智能合约攻防。此系列文章我们主要以智能合约攻防为中心,来剖析智能合约攻防的要点,前两篇我们分享了合约反编译,反汇编的基础内容。后续的文章中,我们会继续分享CTF比赛中智能合约常见题型(重入,整数溢出,空投,随机数可控等)及解题思路,相信会给读者带来不一样的收获。
上篇文章中我们分享了CTF比赛中常考的整数溢出漏洞题型,其中用到了变量覆盖等多种攻击技巧,需要读者仔细推敲。本篇文章我们继续分享CTF比赛中的空投题型,也就是薅羊毛。在系列文章整数溢出题型中,也用到了空投,但只是调用一次空投达到触发其他漏洞的判断条件,并没有进行批量获取空投。
本篇我们以2020年NSSC CTF上skybank题目为例,分享智能合约薅羊毛的题型,该题型也是多次出现在CTF的赛场。相对于之前的系列文章内容,本篇薅羊毛题型更容易理解。
题目地址:https://ropsten.etherscan.io/address/0xe6bebc078bf01c06d80b39e0bb654f70c7b0c273#code
查看合约题目,合约存在0.62ether,没有给出合约源码,如下图:
由于拿到题目后只有合约的opcode,所以需要进行逆向,这里我们推荐Online Solidity Decompiler在线网站(https://ethervm.io/decompile),具体逆向时的源码还原我们不再赘述,需要学习的同学可移步系列文章[反编译篇](http://mp.weixin.qq.com/s?__biz=MzU1OTc2MzE2Mg==&mid=2247485572&idx=1&sn=d3a985c38b531785127f9eb7920debab&chksm=fc131331cb649a274188e80f22b1ba5f81dbb5bc0a444ade4322c5c1fb96ebc469902b015c7f&scene=21#wechat_redirect),[反汇编篇](http://mp.weixin.qq.com/s?__biz=MzU1OTc2MzE2Mg==&mid=2247485578&idx=1&sn=6200ec07f9098d4e705f8740d0c5406d&chksm=fc13133fcb649a291181f993bbebbb5e45c28908a1a1462b0ca27c0f0f197a96865cb1034f66&scene=21#wechat_redirect)。
以下为逆向后的合约代码:
pragma solidity ^0.4.24;
contract skybank{
mapping(address => uint) public balances;
event sendflag(string base64email,string md5namectf);
bytes20 addr = bytes20(msg.sender);
function ObtainFlag(string base64email,string md5namectf){
require(balances[msg.sender] >= 1000000000);
emit sendflag(base64email,md5namectf);
}
function gether() public {
require(balances[msg.sender] == 0);
balances[msg.sender] += 10000000;
}
function Transfer(address to, uint bur) public {
require(bur == balances[msg.sender]);
balances[to] += bur;
balances[msg.sender] -= bur;
}
}
先来看题目最终的判断函数ObtainFlag():
function ObtainFlag(string base64email,string md5namectf){
require(balances[msg.sender] >= 1000000000);