Page 287 - 《软件学报》2021年第6期
P. 287

王小兵  等:面向 MSVL 的智能合约形式化验证                                                        1861


             define r: r_flag=1;  //定义命题 r
             fin(!m) and alw(!(q) or r) and alw(!(p and r) or (som q))
             /〉
             运行 UMC4M 检测器的结果如图 14 所示,验证结果为模型满足性质,总用时 653ms.

                                           MC vote.p vote.m
                                             $$$$$$$$$$$$$$$$$

                                             ThreadPool init success!!!

                                             Verification Result: Val id!!!
                                           Release ThreadPoo1 success!!!

                                             The run time is: 653ms
                                 Fig.14    Verification results of the vote smart contract
                                         图 14   投票智能合约验证结果
         4.2   银行转账合约的建模与验证
             本小节以具体的银行转账智能合约与常见的重入攻击漏洞为例,给出 SOL2M 对转账合约与重入攻击进行
         建模的详细流程以及验证过程.建模时,在银行转账合约中抽象加入了重入攻击操作,即将转账合约与重入攻击
         代码抽象为合约.如图 15 所示,其中,deposit 函数的功能是用户把钱存入银行,withDraw 函数实现了转账功能,
         用户通过 withDraw 函数与 send 函数从银行取钱.Attack 函数实现了重入攻击的功能,其具体步骤为:首先,攻击
         者调用 Attack 函数,通过 deposit 函数向银行转账合约中存入一些以太币;之后调用 withDraw 函数,从银行转账
         合约中取钱,使用 require 语句判断用户余额以及银行总余额是否足够;最后,调用 send 函数给用户地址转账.问
         题出现在第 10 行与第 11 行:合约执行 send 操作后修改用户余额,当合约发送以太币给攻击合约时会执行回退
         函数,建模过程中使用 fallback 模拟,其中会再次调用 withDraw 函数取钱.当执行 require 语句时,由于第 11 行还
         未执行,用户余额未改变,require 语句顺利通过,银行转账合约继续向攻击合约转账.不断重复这些操作,攻击者
         可以从合约中提取所有以太币.
                              1   pragma solidity>=0.4.22<0.6.0;
                              2    contract ReTry {
                              3       mapping(address>=uint) public userBalance;

                              4       uint public Limit=1;
                              5       uint public bankbalance=0;
                              6       function withDraw(address sender,uint toWithdraw) public {

                              7         uint amount=userBalance[sender];

                              8         require(amount>=toWithdraw);
                              9         if (amount>0) {

                              10          send(sender,toWithdraw);
                              11          userBalance[sender]−=toWithdraw;

                              12        }
                              13    }
                              14      function deposit(address sender,uint value) public {

                              15        userBalance[sender]+=value;
                              16        bankbalance+=value;
                              17    }
                              18      function send(address sende  r,uint toWithdraw) public {
                              19        msg.value+=toWithdraw;
                              20        fallback(sender);
                              21    }
                              22      function Attack(address sender) public {
                              23        deposit(sender,1);
                              24        withDraw(sender,1);
                              25    }

                              26      function fallback(address sender) public {
                              27        require(bankbalance>0);
                              28        withDraw(sender,1);
                              29    }
                              30 }
                                       Fig.15    Bank transfer smart contract
                                          图 15   银行转账智能合约
   282   283   284   285   286   287   288   289   290   291   292