Next Article in Journal
Averaging Principle for ψ-Capuo Fractional Stochastic Delay Differential Equations with Poisson Jumps
Previous Article in Journal
The Results of Common Fixed Points in b-Metric Spaces
 
 
Font Type:
Arial Georgia Verdana
Font Size:
Aa Aa Aa
Line Spacing:
Column Width:
Background:
Article

TxMirror: When the Dynamic EVM Stack Meets Transactions for Smart Contract Vulnerability Detection

Key Laboratory of Aerospace Information Security and Trusted Computing, Ministry of Education, School of Cyber Science and Engineering, Wuhan University, Wuhan 430070, China
*
Author to whom correspondence should be addressed.
Symmetry 2023, 15(7), 1345; https://doi.org/10.3390/sym15071345
Submission received: 27 May 2023 / Revised: 18 June 2023 / Accepted: 27 June 2023 / Published: 1 July 2023
(This article belongs to the Section Computer)

Abstract

:
Smart contract vulnerability can be exploited to cause serious financial loss. While there are many logic-based techniques for detecting vulnerabilities, few have focused on the dynamic stack of the Ethereum virtual machine (EVM) in the process of transactions. This motivates us to raise an intriguing question: What will happen when the dynamic EVM stack meets a transaction for smart contract vulnerability detection? To answer it, we propose a novel data-driven framework, dubbed TxMirror, to detect smart contract vulnerability at the bytecode level by simulating transactions symmetrically. Beyond logic-based wisdom, TxMirror customizes EVM for smart contract vulnerability detection, and stores its dependency between the stack data and logic relation in a new manner, that is, all the data are stored in a double link forest and can index the logic that creates them; it directly inspects customized EVM stack data in a transaction without replaying history transactions repeatedly or recording EVM bytecode-level traces. Furthermore, it extends detection rules defined by user interests, possessing good adaptability for developers. Extensive experiments demonstrate that TxMirror effectively detects attacks and vulnerabilities in unpredictable smart contracts.

1. Introduction

The smart contract has been applied in many scenarios [1,2,3]. However, the security of a smart contract has always been a major issue. Smart contract vulnerability [4] has been plagued by security incidents [5,6] due to two major issues. First, smart contract vulnerability detection, easily affected by in-built features, such as nested calls and complex data types, is more difficult than ordinary bytecodes, such as reentrancy and integer overflow. Second, deployed smart contracts are not allowed to be patched even if they are vulnerable, leading to the difficulties of anticipating possible states and environments that the code may encounter in the future. This provides an intriguing and practical question of how to present effective smart contract vulnerability detection.
A lot of efforts [7] are made in order to prevent such vulnerabilities. Durieux et al. [8] used nine kinds of automation tools to detect 428,337 vulnerable smart contracts and found that only 42% of vulnerabilities were detected. The existing methods can be roughly cast into two categories. One kind of work [9] utilized classical program analysis to identify vulnerabilities, which can discover vulnerabilities before smart contracts are deployed and address security issues at the root. However, they fundamentally rely on several fixed expert rules, while the manually defined patterns bear the inherent risk of being error-prone and some complex patterns are non-trivial to be covered. Meanwhile, some deep vulnerabilities are hard to be triggered. Therefore, Zhang et al. [10] proposed another kind of work detecting vulnerabilities in transactions, which solves this problem by detecting real transaction attacks. As shown in Figure 1, however, this method ignores the data attribute, so it may miss data sensitivity vulnerabilities. Additionally, it needs to traverse the logic repeatedly, leading to detection inefficiency.
In this paper, we propose TxMirror, an extendable and data-driven framework analyzing smart contract vulnerability by simulating transactions symmetrically. The key idea of our approach is to inspect customized EVM stack data in the process of the transactions in order to detect new smart contract vulnerabilities and attacks; in particular, TxMirror is able to quickly detect data sensitive vulnerabilities by data index. In addition, because TxMirror replays the transaction completely, this symmetry guarantees that TxMirror and EVM have identical transaction results, which means TxMirror has the potential to be designed as a new EVM. This design is inspired by TxSpector [10], which is a logic-driven program analysis tool on Ethereum transactions. The challenges of performing transaction analysis, however, are twofold: First, it is hard for us to accurately describe the dependencies between smart contract instructions through data indexing since the data storage structure is extremely cumbersome. Second, while a smart contract is executed, we can hardly judge to which data type that generated data belongs. Therefore, extracting and analyzing EVM stack data in transactions requires innovative approaches to improve performance.
TxMirror addresses these challenges as follows. On the one hand, our framework can figure out new vulnerabilities and attacks from the stack data of a customized virtual machine. On the other hand, its dependency between the stack data and logic relation can be stored in a new way, where the logic relation between the opcodes can be effectively collected for smart contract vulnerability detection. It is noted that few dynamic analysis tools can detect such data-sensitive vulnerabilities because of integer overflow through the data type of each variable at the bytecode level. Additionally, TxMirror supports the extension of some detection rules defined by users. To the best of our knowledge, TxMirror is the first extendable data-driven framework to perform smart contract vulnerability analysis.
In short, our contribution is as follows:
  • We propose TxMirror, the first data-driven framework of a customized virtual machine for inspecting stack data in transactions, instead of using classical program analysis techniques to identify vulnerabilities at the bytecode level.
  • Our framework speeds up smart contract vulnerability detection through a customized design of a virtual machine, which is apt to be applied to new Ethereum development.
  • TxMirror has the ability to detect some vulnerabilities more precisely, compared with other tools. In our experiments, TxMirror detects five kinds of attacks, including integer overflow, stack overflow, reentrancy attack, suicide attack, and exception disorder, and three vulnerabilities, including timestamp dependency, misuse of origin, and unchecked call.

2. Related Work

Tools for smart contracts. Most of these tools [11,12,13,14,15,16,17,18] are oriented to the smart contract itself, and the detection of vulnerabilities caused by smart contract interaction is weak. Symbolic execution [19,20,21,22,23] is perhaps the most popular approach. Chang et al. [24] proposed a method called Scompile to automatically identify the key program path in the smart contract. Using static analysis technology [25], Securify [17] detects vulnerability automatically, which is based on a decompiler that symbolically encodes the dependency graph, abstract interpretation, and compliance and violation pattern checks. Vandal [26] analyzes the smart contract bytecode, which is based on semantic logic relation conversion. Slither [27] customized an intermediate language SlitherIR and carried out all static analysis work at this level. Using formal verification [28], ZEUS [29] compiles smart contracts written in high-level languages into a low-level intermediate language LLVM IR [30], and checks the security by using the symbolic model and constrained Horn clauses [31]. Bhargavan et al. [32] proposed a smart contract analysis framework that translates Ethereum instructions into a type-dependent functional programming language. Permenev et al. [33] developed a formal verification program VERX that can prove the functional characteristics of an Ethereum smart contract. Fuzzing [34,35,36] is another simple yet effective method. It generates random transaction data that can be called by the contract to expose the vulnerabilities. Additionally, the neural network is also applied to detect smart contract vulnerabilities. Zhang et al. [37] and Liu et al. [38] constructed contract graphs to train graph neural networks to detect vulnerabilities. In addition, Liu et al. [39] also proposed combining deep learning and expert patterns to analyze the source code to detect vulnerabilities.
Tools for transactions. In recent years, new types of transaction-oriented tools have become a new trend in smart contract vulnerability detection. Sereum [40] realizes complex reentrancy vulnerability detection by using dynamic taint tracking and data-flow analysis. ECFChecker [41] is a dynamic monitor for effectively callback-free (ECF) Ethereum smart contract verification. Both tools focus on only one specific type of vulnerability detection. Zhang et al. proposed TxSpector [10], which replays historical transactions and records EVM bytecode-level traces to detect attacks. It mainly realizes the detection of reentrancy, unchecked call, and suicidal vulnerability, which our tool can also detect but uses different methods. They also leverage a datalog approach to detect vulnerabilities and allow users to specify customized rules. However, in order to save storage space and obtain more intuitive results, we do not use datalog. Perez et al. [42] also performed bytecode-level transaction analysis to detect vulnerabilities; they proposed a datalog-based formulation for performing analysis over EVM execution traces. The comparison between TxMirror and other tools in terms of detectable vulnerabilities is shown in Table 1.

3. Design of TxMirror

Smart contracts themselves have the capability to call another account presenting on the Ethereum blockchain. A contract is vulnerable if it has been flagged by a static analysis tool as such, which means that some contracts may be vulnerable because of a false-positive. Similar to computer software, it is so difficult to estimate what fraction of discovered vulnerabilities are exploited in practice. In addition, some hidden vulnerabilities of a smart contract are difficult to be triggered, so code-based methods are unable to solve this question. Therefore, this paper proposes a transaction-based detection method to detect some vulnerabilities through users’ or attackers’ transactions.
TxMirror is a data-driven analysis tool that detects vulnerabilities and attacks. It contains a virtual machine to simulate transaction execution, similar to the execution of computer software, but they are not the same. The design of TxMirror is shown in Figure 2.
  • Input/Output: Transaction information from the blockchain is received by a transaction crawler, which includes transaction debug information, sender information, receiver information, etc. Usually, the crawler connects the Ethereum, and crawls the transaction from the Ethereum, using the remote procedure call (RPC) eth.get transaction and debug.trace transaction to obtain the transaction information.
  • Virtual Machine: The simulation machine imitates the virtual machine design, so it includes the opcode analyzer, the virtual data stack, the virtual call stack, and the registers. It is a design between the EVM and the computer bottom layer, which supports a new way of executing smart contracts. The simulation machine analyzes the information and executes the transaction with a special data and logic storage structure.
  • Detection Rules: There are detection rules set up in the analyzer. When the data information changes or some opcodes are executed, the analyzer will analyze the data and index the logic with the corresponding rules.
  • Analyzer: The analyzer checks all the data from the stack for detection. After the transaction is executed completely, the analyzer will generate a report to show whether any attacks have occurred or vulnerabilities have been detected.
After the transaction information is received, it will be sent to the virtual machine. The virtual machine will analyze the running process and simulate the transaction in a different way. During the simulating process, TxMirror judges the type of each data based on contextual logic. After the data is popped out of the stack, it will not be used anymore. In TxMirror, it contains not only a value but also other information, for instance, the data type and the related logic. This data will not be freed immediately but will be sent to the analyzer. The analyzer matches the data information and defined detection rules to discover attacks and vulnerabilities, which are written into the report.

4. Transaction Simulation

Although transaction-based vulnerability detection can find some attacks or vulnerabilities through the analysis of the transaction process, current works have a low detection efficiency and a high false positive detection rate. In order to simulate the transaction scenario triggered by the attack, and record all the data attributes and transaction changes in the process of the transactions, we designed a new storage structure and transaction simulation.

4.1. New Storage Structure

All opcodes [43] can create or use data. Data attributes generated by smart contracts include data value size, data type, data dependency, data generation logic, etc. In TxMirror, the data and code logic of a smart contract have been stored in a special data structure. All of the data values created during the execution are stored in the form of a tuple (value, size, signed, overflow, creation, father, children, codelist):
  • value: the data value.
  • size: the size of the byte of the data between 1 and 32.
  • signed: a bool variable representing whether the data is a signed number.
  • overflow: a bool variable indicating whether the data is out of range.
  • creation: records the opcode that creates the data.
  • father: a pointer to the father data that creates it.
  • children: a list that appends the pointer of the new data that it creates.
  • codelist:a list that records all the logic indexed by its father.
We initialized the size as 32 and the signed as 0 for each data value. When the execution of the smart contract is simulated, TxMirror will predict the type of each data according to the context logic and judge whether the data overflows. When data is created by other data and its father is not popped out of the stack, the father will point to the data that creates it and its father’s children will record it. Obviously, the data will be stored in the form of a two-way-point forest, which is shown in Figure 3. We have analyzed all the opcodes in smart contracts and found that only the DUP opcodes can change the father and children. When data is created by other data, it will record the creation opcode and all of the opcodes in the codelist of the data that creates it and stores them in its codelist. After this, the new data indexes all the logic that occurred in the process of its creation. There is dependence between this logic because it creates data. It is worth noting that we just record the opcodes but ignore their order because the order has no influence on the detection. Additionally, if data inherits other data, their size is the maximum size of these data, and the new data is signed if one of them is signed.
There are several purposes for storing data in this way. Firstly, we can easily judge the type of each data in order to detect integer overflow. Secondly, we can analyze all the logical dependence through just one simulation. Thirdly, this storage structure can make the detection of attacks and vulnerabilities more convenient.

4.2. Transaction Process Simulation

TxMirror can execute a smart contract, and all the data are in the form shown in Section 4.1. Because we collect the data from external regions and EVM memory, there is no need to simulate the EVM memory or storage slot. However, the data stack and the call stack are necessary. Additionally, when TxMirror imitated, we set the esp and ebp registers to store the pointers pointing to the top and bottom of the data stack, so a new way is proposed by simulating the transaction execution of smart contracts.

4.2.1. Simulation Process

When a smart contract calls another smart contract, a new data stack will be constructed in the EVM, and the address of the called smart contract will be pushed into the call stack. However, in TxMirror, we reserve the call stack, but all the smart contracts use a common data stack. That is, no data stack will be constructed when a smart contract calls another. There are two registers storing pointers. One is named ebp, which stores a pointer pointing to the bottom of the data stack. The other is called esp and points to the top of the data stack. When TxMirror is initialized, −1 will be pushed into the data stack. When TxMirror begins to analyze a transaction, it will push the sender address and the callee address into the call stack. The sender must be an external account. It is worth noting that only the callee address will be pushed into the call stack in the EVM but we push two.
Furthermore, the opcodes in smart contracts are limited. Each opcode pushes data into the stack or pops data out of the stack. TxMirror strictly meets the operation of all the opcodes in the EVM except call-related opcodes. In Figure 4, we provide an example of a simulation including the ADD, CALL, and RETURN opcodes. Before executing ADD, there are n data in the data stack. After executing it, the Data n 1 and Data n are popped out of the data stack and add up to Data n + 1 , which is pushed into the data stack. This process is the same as the operation of the ADD opcode in the EVM except for changing esp.
The call operation is different from the call-related opcodes in smart contracts but is similar to the call of functions in the computer. In the computer, when a function is called, it will first push the return address into the stack. Then, it will push the value of ebp. Lastly, the value of ebp will be changed into the value of esp. After this operation, the stack will create a new stack space to run the function. TxMirror is a little different from this process. As shown in Figure 4, because we have simulated the call stack and we can obtain the next opcode pc after a smart contract returns, there is no need to push any return address into the data stack. Alternatively, because there are many different call-related opcodes and each needs a different amount of arguments, we push the number of arguments into the data stack in order to judge the different call methods. In particular, the CALL opcode and CALLCODE opcode need seven arguments. The DELEGATECALL opcode and STATICCALL need six arguments. The CREATE2 opcode needs four arguments and the CREATE opcode needs three arguments. Then, we push the value of ebp and change ebp into esp. Lastly, the address of the called new smart contract is pushed into the call stack, which is stored in the second cell from the top of the data stack before calling.
The returning process is also shown in Figure 4. When a smart contract returns, we need to destroy its stack space and pop an address at the top of the call stack. In order to achieve this, we need to change the value of esp to the value of ebp and pop all the data generated during the execution of the smart contract. Then, we pop the integer where esp is pointing to ebp. Next, we pop the integer at the top of the data stack, which means the number of arguments the call used. Lastly, we pop these arguments and push the returned data into the data stack. For the opcodes creating the smart contract, this is the address of the new smart contract. For the others, it is zero or one, which indicates whether the smart contract executes successfully.
The purpose of simulating the execution is to analyze the attributes of each data point and all of the logical dependence. Redesigning the calling and returning process aims to detect reentry attacks better, which is explained in Section 5.2.

4.2.2. Data Type Judgment

The data type is an important criterion for judging smart contract vulnerability, such as the size, the sign, and so on. The data pushed into the EVM stack is divided into four types:
  • An unsigned number less than 32 bytes.
  • A signed number less than 32 bytes.
  • An unsigned 32-byte number.
  • A signed 32-byte number.
Because all the data are stored in the form of a forest, and each data is stored on a two-way-point tree, if we judge the type of one data point, we can ensure the type of all the data on the tree where the data is located. Then, we can change the type of all the data on the tree and ensure the range of the data can represent to check whether integer overflow happens in the data.
There are some opcodes that only aim at signed numbers. Examples are SIGNEXTEND, SDIV, and SMOD. If these opcodes are executed, all of the data on the tree must be signed. However, if a data point is not executed by these opcodes, we cannot confirm it as unsigned data. For example, SIGNEXTEND is used to extend the size of a signed integer to 32 bytes with the sign bit before a signed integer performs the calculations. However, each cell in the data stack is 32 bytes. For a type four integer, although it is signed, it will not be executed by the SIGNEXTEND opcode before it performs any calculations. So, we cannot distinguish type three and type four according to SIGNEXTEND. In this case, we default to data type three. If it is calculated as a negative number, it must be type four. In addition, if type three data is calculated with other signed data, we change them to type four too.
In addition to the data sign, the data size has to be considered, so the data type judgment rules are as follows:
  • There are 32 PUSH opcodes from PUSH1 to PUSH32 in smart contracts, which can help us confirm the size of the data. For example, if the data is pushed into the data stack by PUSH29, we can ensure that this data occupies 29 bytes.
  • The SIGNEXTEND opcode can help confirm not only the sign but also the size. There are two arguments for SIGNEXTEND. One is the data extended and the other is N-1, where N is the size of the data. For example, when two-byte data executes SIGNEXTEND, the top data in the data stack is one and the second is the data itself.
  • For the data coming from external regions, if it is not 32-byte, an AND opcode will be inserted to eliminate the unnecessary bits. One of the operation numbers is the origin data and the other is a constant p, where p is in the form of 16 N + 1 -1. N is the size of the data. For example, if data from the storage slot is 1 byte, the smart contract will insert AND value 0xFF to eliminate the high 31 bytes. Therefore, if the data is operated on by this, we can confirm its size.
When the type of data is confirmed or changed, we will verify whether integer overflow happens. If we find it overflows, the overflow attribute will be changed into True. However, the fact that the data’s overflow attribute is True does not mean that the transaction happens with integer overflow, which we will explain in Section 5.1.

5. Detection Rules

In our work, we propose nine rules to detect five kinds of attacks, including integer overflow, reentrancy attack, stack overflow, suicide attack, and exception disorder, and three kinds of vulnerabilities, including timestamp dependence, misuse of origin, and unchecked call. For some of them, we provide the pseudocode.

5.1. Integer Overflow

The type of each data point limits its range. If the value of the data goes beyond the range it can represent, it overflows. Although there are overflow attributes in each data point, the True value does not mean the transaction happens with overflowing. It is related to the compilers. For example, in order to push 0xFFFFFF into the stack, some of the compilers use the PUSH3 0xFFFFFF, but some use the opcodes in Figure 5. Firstly, the EVM will push 0x3 and 0x100 into the stack. Then, it uses EXP to perform the power calculation obtaining 0x1000000. Next, it pushes 0x1 and swaps the position of the two data. At last, it uses SUB to obtain 0xFFFFFF. Although it seems cumbersome, when it pushes larger numbers, the size of the opcodes will be smaller. According to the rules of inheriting, because the size of 0x3 is one and 0x100 is two, the size of 0x1000000 is two, which happens with overflow. These data are compiled into the smart contract bytecode and the overflow is designed deliberately, which should not be judged as an overflow attack. Therefore, we need to exclude the internal data when checking integer overflow. Additionally, some solutions may be considered separately. For some early compilers, when data from external regions needs to be reduced to one, it does not use the SUB opcode. It pushes zero and uses the NOT opcode to obtain the biggest number in the smart contracts. Then, the data adds this biggest number to the happening overflow to reduce it to one. However, it is designed deliberately, so we need to exclude this solution too.
Algorithm 1 shows the pseudocode of checking integer overflow. We checked each data point that popped out of the data stack. s1 represents the set of the opcodes that push external data into the stack. Among them, SLOAD pushes the data from the storage slot. CALLDATALOAD pushes the arguments from the user input and MLOAD pushes the data returned from the other smart contracts. s2 is the set containing calculating opcodes that may lead to integer overflow. s is a set containing the indexed logic of the data. If ss1 , it means this data is created by data from external regions. If ss2 , it means this data is created by the data executing calculating opcodes. If the data is directly or indirectly from external regions and is executed by calculating opcodes, and if the value is beyond the range it can represent, we think the transaction involves integer overflow, which is judged in lines 5 to 9.
Algorithm 1 The rule of checking integer overflow
Input: 
the data popped out of the data stack
Output: 
if happening integer overflow
  1:
function CheckIO( d a t a )
  2:
       s 1 { S L O A D , C A L L D A T A L O A D , M L O A D }
  3:
       s 2 { A D D , S U B , M U L , E X P }
  4:
       s { d a t a . c r e a t i o n , d a t a . c o d e l i s t }
  5:
      if  s s 1  and  s s 2  then
  6:
            if  d a t a . o v e r f l o w = T r u e  then
  7:
                 return  T r u e
  8:
            end if
  9:
      end if
10:
      return  F a l s e
11:
end function

5.2. Reentrancy Attack

Reentrancy attack has very typical characteristics. One of them is that, after calling a smart contract, it will be called again before it returns. Based on this, we propose two detection rules to detect reentrancy attacks. These are shown in Algorithms 2 and 3.
Algorithm 2 Rule 1 of checking reentrancy attack
Input: 
the opcode and the call stack
Output: 
if happening reentrancy attack
  1:
S i g n F a l s e
  2:
function CheckRA1( o p c o d e , c a l l s t a c k )
  3:
      if opcode is calling a contract then
  4:
            if called address in the c a l l s t a c k  then
  5:
                  S i g n T r u e
  6:
            end if
  7:
      end if
  8:
      if  o p c o d e = S S T O R E  and  S i g n = T r u e  then
  9:
            return  T r u e
10:
      end if
11:
      return  F a l s e
12:
end function
Algorithm 3 Rule 2 of checking reentrancy attack
  1:
function CheckRA2( s t a c k , o p c o d e )
  2:
      if opcode is calling a contract then
  3:
             l the number of stack space
  4:
             s l each stack space in stack
  5:
             l a s t s p a c e s l [ l ]
  6:
            for  i 1 to l 1  do
  7:
                 if  l a s t s p a c e . l e n g t h = s l [ i ] . l e n g t h  then
  8:
                       if corresponding data’s logic in two space are all the same then
  9:
                             return  T r u e
10:
                       end if
11:
                 end if
12:
            end for
13:
      end if
14:
      return  F a l s e
15:
end function
Algorithm 2 shows the first rule for checking for a reentrancy attack. The Sign defined in line one is a global variable. If the opcode is calling a contract, such as CALL, DELEGATECALL, we check whether the new address of the contract is in the call stack. If it is in the call stack, it means the contract has been called and not returned, and we change the Sign to True. Then, if it executes SSTORE, which means the state variables change, we confirm that a reentrancy attack happened and return True.
Algorithm 3 shows the second rule of checking for a reentrancy attack. In this rule, we input the data stack and the opcodes. As we have mentioned, each contract will receive a new stack space, so the data stack in TxMirror is made up of many stack spaces, which can be ensured by esp and ebp. When the reentrancy attack happens, there must be two identical stack spaces. Based on this, the rule is also to monitor all the opcodes that are executing. If the opcode is calling a contract, before creating a new stack space, it divides the data stack into many stack spaces. The last stack space corresponds to the running contract, which is defined in line five. We compare the last stack space with each forward stack space. If the length of the two stack spaces is the same, we need to perform further inspection, as shown in lines 7 to 11. For each data in the last stack space, we compare the logic it indexes with the logic of the corresponding data in the other stack space. Note that we just compare the logic and do not compare the value of the data because the value of some data may not be the same, although they experience the same logic. An example is the data created by GAS. If the logic indexed by these data are all the same, there must be a reentrancy attack happening and the function returns True in line nine. Otherwise, it returns False. In order to check more precisely for a reentrancy attack, we push the number of the arguments and reserve them until returning.

5.3. Stack Overflow

There are only 1024 cells in the data stack for each smart contract. In general, the 1024 cells are enough for a smart contract. However, the attacker may push more than 1024 data points into the data stack to perform an attack. In the virtual hardware in TxMirror, we can obtain the length of the data stack by esp-ebp. Therefore, we can monitor the length of the stack all the time to check stack overflow.

5.4. Suicide Attack

We check whether a smart contract verifies the permission before destroying itself. This is shown in function AllowSuicide in Algorithm 4. The input arguments are the data popped out of the data stack and the opcode being executed. Because of the call of a smart contract, we provide each called contract a sign to mark whether it verifies the permission; this is stored in AllowSuicideList defined in line one. We initialize it with False because there is a smart contract running first. When calling a new smart contract, we initialize a new sign with False. When returning, the last sign in the list will be popped, which is shown in lines 11 to 16. Then, we monitor all the data out of the data stack too. s records the logic of the data. If JUMPI is executed, and the CALLER and EQ opcodes are indexed by the data, it means the permission has been verified. In that case, we change the last sign in AllowSuicideList to True to indicate that this smart contract can commit suicide.
Function CheckSA in Algorithm 4 provides the rule for checking for suicide attacks. It monitors the data and opcodes too. If the opcode is SELFDESTRUCT, we check the sign in the AllowSuicideList. If the last sign marking the contract is False, it means it has not verified the permission and a suicide attack happens. Then, it returns True; otherwise, it returns False.
Algorithm 4 The rule of checking suicide attack
Input: 
the data popped out of the data stack and opcode
Output: 
if happening suicide attack
  1:
A l l o w S u i c i d e L i s t [ F a l s e ]
  2:
function CheckSA( d a t a , o p c o d e )
  3:
      AllowSuicide( d a t a , o p c o d e )
  4:
      if  o p c o d e = S E L F D E S T R U C T  and  A l l o w S u i c i d e L i s t [ 1 ] = F a l s e  then
  5:
            return  T r u e
  6:
      end if
  7:
      return  F a l s e
  8:
end function
  9:
 
10:
function AllowSuicide( d a t a , o p c o d e )
11:
      if opcode is calling a contract then
12:
             A l l o w S u i c i d e L i s t . a p p e n d ( F a l s e )
13:
      end if
14:
      if opcode is returning a contract then
15:
             A l l o w S u i c i d e L i s t . p o p ( )
16:
      end if
17:
      if  o p c o d e = J U M P I  then
18:
             s { d a t a . c r e a t i o n , d a t a . c o d e l i s t }
19:
            if  C A L L E R in s and  E Q in s then
20:
                  A l l o w S u i c i d e [ 1 ] T r u e
21:
            end if
22:
      end if
23:
end function

5.5. Exception Disorder

When the programmer designs a smart contract, the exception is easy to be ignored. When handling the exception, there may be some unexpected logic. The attackers may use this vulnerability to steal money. When we crawl the information from the blockchain, we can obtain the error information at the same time. In theory, after an exception happens, it is unallowable to change the state variables because the code has an error. If the attacker wants to steal money through this vulnerability, he must change the state variables after an exception happens. While simulating the transaction, if there are SSTORE opcodes after an exception happens, there must be an exception disorder and may be an attack.
Algorithm 5 provides the rule for checking for an exception disorder. The input is the exception sign in the transaction that we crawl, as well as the opcodes. There is a global variable Sign to present whether an exception is happening. If an exception happens, the Sign is changed into True as shown in lines 3 to 5. When executing SSTORE, it means the state variable is being changed and that, if an exception has happened, it must be an exception disorder and the function will return True, which is shown in lines 6 to 8.
Algorithm 5 The rule of checking exception disorder
Input: 
whether happening exceptions and the opcode
Output: 
if happening exception disorder
  1:
S i g n F a l s e
  2:
function CheckED( e x c e p t i o n , o p c o d e )
  3:
      if  e x c e p t i o n = T r u e  then
  4:
             S i g n T r u e
  5:
      end if
  6:
      if  o p c o d e = S S T O R E  and  S i g n = T r u e  then
  7:
            return  T r u e
  8:
      end if
  9:
      return  F a l s e
10:
end function

5.6. Timestamp Dependency

Some smart contracts depend on the timestamp. However, the miner could control the time of packing the transactions to control the timestamp. Then, the malicious miners could control some judging conditions depending on the timestamp to achieve some purposes. Therefore, if there are judging conditions that depend on the timestamp, there must be a timestamp dependence vulnerability in the smart contract.
Algorithm 6 shows the rule of checking for timestamp dependence. It inputs the data popped out of the data stack and the opcode, and outputs whether a timestamp dependence vulnerability exists. s1 is the set of all the comparing opcodes. s is the set of the logic of the data. When executing the JUMPI, we monitor the data. If there is a TIMESTAMP, while also comparing the opcodes in it at the same time, we can say that this transaction may be controlled by miners and that the smart contract demonstrates a timestamp dependence vulnerability.
Algorithm 6 The rule of checking timestamp dependence
Input: 
the data popped out of the data stack and the opcode
Output: 
if existing timestamp dependency
  1:
function CheckTD( d a t a , o p c o d e )
  2:
       s 1 { E Q , L T , G T , S L T , S G T , I S Z E R O }
  3:
       s { d a t a . c r e a t i o n , d a t a . c o d e l i s t }
  4:
      if  o p c o d e = J U M P I  then
  5:
            if  T I M E S T A M P in s and  s s 1  then
  6:
                 return  T r u e
  7:
            end if
  8:
      end if
  9:
      return  F a l s e
10:
end function

5.7. Misuse of Origin

The tx.origin could obtain the beginning account of a transaction, which corresponds to the ORIGIN opcode in the compilation level. In general, this opcode is used to verify the identity. However, due to the vulnerability of the design, some malicious smart contracts may induce a user to run it to obtain and pass the verification. While doing this, there must be more than two contracts in the call stack and happening verifying.
Algorithm 7 shows the rule for checking for the misuse of origin. It inputs the call stack, the data, and the opcode. Similar to Algorithm 6, s1 is the set of all the comparing opcodes and s is the set of the data logic. When executing JUMPI, we verify whether ORIGIN is in s and if there are comparing opcodes. At the same time, we have to notice whether it is the first contract running in this transaction. Because we initialize the call stack with two addresses, if the length of the call stack is more than two, there must be a misuse of origin, although maybe it is not being attacked.
Algorithm 7 The rule of checking the misuse of origin
Input: 
the call stack, the data, and the opcode
Output: 
if existing the misuse of origin
  1:
function CheckMO( c a l l s t a c k , d a t a , o p c o d e )
  2:
       s 1 { E Q , L T , G T , S L T , S G T , I S Z E R O }
  3:
       s { d a t a . c r e a t i o n , d a t a . c o d e l i s t }
  4:
      if  o p c o d e = J U M P I  then
  5:
            if  O R I G I N in s and  s s 1  then
  6:
               if  c a l l s t a c k . l e n g t h > 2  then
  7:
                     return  T r u e
  8:
               end if
  9:
            end if
10:
      end if
11:
      return  F a l s e
12:
end function

5.8. Unchecked Call

When a smart contract returns, it will return a bool variable about whether the contract is executed successfully. We must verify this data to judge if it is continuing to be executed. However, the programmer may be too lazy to verify it and this causes a significant vulnerability.
Algorithm 8 shows the rule for checking for an unchecked call. There is a global variable Unchecked defined in line one by zero, which represents the number of unchecked calls. When calling a new smart contract, the Unchecked adds one. Then, it will check whether a call is checked by WhetherCheck. s1 is the set of call-related opcodes. If JUMPI is executed, and its argument is created by the returned bool data, it means one of the calls is checked so Unchecked reduces by one, which is shown in lines 18 to 22. After the simulation finishes, if the Unchecked is not zero, it means there is at least one call not being checked, so it returns True, which is shown in lines 7 to 11. Otherwise, it returns False.
Algorithm 8 The rule of checking unchecked call
Input: 
the data popped out of the data stack and the opcode
Output: 
if unchecked call exists
  1:
U n c h e c k e d 0
  2:
function CheckUC( d a t a , o p c o d e )
  3:
      if  o p c o d e is calling a contract then
  4:
             U n c h e c k e d + +
  5:
      end if
  6:
      WhetherCheck( d a t a , o p c o d e )
  7:
      if the transaction is finished simulating then
  8:
            if  U n c h e c k e d 0  then
  9:
               return  T r u e
10:
            end if
11:
      end if
12:
      return  F a l s e
13:
end function
14:
 
15:
function WhetherCheck( d a t a , o p c o d e )
16:
       s 1 { C A L L , D E L E G A T E C A L L , C A L L C O D E , S T A T I C C A L L ,
 
                    R E T U R N , S T O P , R E V E R T }
17:
       s { d a t a . c r e a t i o n , d a t a . c o d e l i s t }
18:
      if  o p c o d e = J U M P I  then
19:
            if  s s 1  then
20:
                  U n c h e c k e d
21:
            end if
22:
      end if
23:
end function

6. Experiments

6.1. Experiment Design

We performed our experiments with 4V 8GB CPU running on Ubuntu 20.04. We realized TxMirror with Python 3.8 and used Mythril [21], Vandal [26], TxSpector [10], and the tool of Perez et al. [42] to perform experiment comparison. Mythril and Vandal were used to check the vulnerabilities from the bytecode. TxSpector and the tool of Perez are similar to ours and they were used to analyze the transactions to identify attacks and vulnerabilities. In addition to the crawler in TxMirror, we also used eth.getCode to obtain the bytecode of the smart contract. We randomly crawled the transactions and the bytecodes of related smart contracts between the 2,000,000th and 2,400,000th blocks on Ethereum. We obtained 359,293 items of transaction information and 10,620 smart contract bytecodes. They took up 711 GB and were stored in a mobile hard drive. We did not store them in the database because it needed to modify the source code of Ethereum and other researchers or users may find it difficult to use TxMirror.
In our experiment, we compared TxMirror with other tools in terms of checking results and efficiency. Firstly, we ran all of the tools again, including checking results and time consumed. While running TxMirror, in addition to collecting the hash of suspicious transactions, we also recorded the related smart contracts performing these transactions. Secondly, we summarized these results and counted the common results between TxMirror and other tools. In particular, we obtained the amount of common suspicious smart contracts flagged by Mythril and Vandal compared with TxMirror. We also counted the total of common suspicious transactions between TxMirror and other tools. Thirdly, we compared the time of these tools and verified the efficiency of TxMirror.

6.2. Result Analysis

There are integer overflow, reentrancy attacks, suicide attacks, timestamp dependence, misuse of origin, and unchecked call. The checked results of these tools are listed in Table 2. From the table, it is found that it does not mean it suffers attacks if a smart contract contains some vulnerabilities.

6.2.1. Results of Integer Overflow

There were 6356 transactions flagged by TxMirror, which was more than other tools. Compared with Mythril, there were 310 smart contracts flagged by Mythril, 80 of which were flagged by TxMirror. The Perez tool checked 4828 transactions, of which 3658 were also flagged by TxMirror, equal to 75.8% of the results using Perez. We next analyzed the transactions flagged by TxMirror but unflagged by the Perez tool. We found that most of the different results came from extracting data from a storage slot. In order to save space, the data in a storage slot was stored compactly, which meant there may be more than one data point stored in a slot. Therefore, it may have cleared up some bits after extraction, which is when the overflow may have happened. We have excluded the situations mentioned in Section 5.1, but some may have used MUL opcode to clear extra bits [44], where the real overflow may have suffered the same logic. If we excluded this situation, TxMirror may have missed some real overflow. In order to check all the overflow, we allowed this false positive.

6.2.2. Results of Reentrancy Attack

All of the tools could check reentrancy. TxMirror flagged 1587 transactions with a reentrancy attack. Mythril checked 50 smart contracts and 7 were also checked by TxMirror. Vandal flagged 1918 smart contracts and 88 were also flagged by TxMirror. Mythril combines more checking methods and has more strict checking rules, so its results were far fewer than Vandal. TxSpector flagged 614 transactions and 97.9% of them were also flagged by TxMirror because the rule of TxSpector is similar to Algorithm 2 mentioned in Section 5.2. Because there are two rules for reentrancy attack in TxMirror, its results were far more than TxSpector. We analyzed the transactions TxMirror flagged that TxSpector did not flag and found that most of the different results were from Algorithm 3. Although we did not check whether or not the state variables were changed in Algorithm 3, which indicates whether this kind of reentrancy attack has meanings or not, the smart contract was used to carry out transactions; if there is completely the same logic in a transaction, it is suspicious and needs to be checked artificially. The results of reentrancy attack using Perez’s tool were much greater than TxMirror. Perez’s tool flagged 2139 transactions but only 918 were also flagged by TxMirror, which amounted to only 42.9%. We analyzed them and found that the Perez tool had looser checking rules. Some smart contracts are called multiple times before returning but they do not change the state variables or experience the same logic; it also flags them as reentrancy attacks. However, we think Perez’s tool is the most justifiable in terms of security because it can check all of the reentrancy attacks.

6.2.3. Results of Suicide Attack

In TxMirror, we checked 4 transactions with suicide attacks because they had not verified the identity before destroying the smart contracts. Mythril checked 19 and 1 of them was flagged by TxMirror. Vandal checked 1007 and no smart contract was flagged by TxMirror. TxSpector flagged 2, both of which were flagged by TxMirror. There were still 2 transactions flagged by TxMirror but ignored by TxSpector. In these transactions, an external account inputted an argument to compare with some data to verify identity. However, because the compared data was stored in the storage slot or bytecode and everyone could obtain it [45], we did not think this verification was efficacious.

6.2.4. Results of Timestamp Dependence

We used only Mythril to check timestamp dependence. TxMirror flagged 14,899 transactions and Mythril flagged 53 smart contracts, 32 of which had the transactions flagged by TxMirror. In TxMirror, we did not allow timestamps to be compared with other data. In terms of high-level language, we did not allow timestamp as a judging condition. However, we analyzed the flagged transactions and found that, if a transaction needed a timestamp, it was most likely to compare with other data. Few transactions used timestamps to perform timing. However, because a malicious miner can control the time of packing a transaction, we think our checking results were reasonable.

6.2.5. Results of Misuse of Origin

TxMirror flagged 273 transactions while Mythril flagged 43 and Vandal flagged 110. No smart contract was flagged in common with Mythril and only 1 was flagged in the results of Vandal. The reason there was so large a difference is that it was difficult to trigger the origin vulnerability. However, TxSpector flagged 113 transactions, while no transaction was also flagged by TxMirror. We analyzed both of their results and found that TxSpector allowed the address generated by ORIGIN to be compared with other data but did not allow it to be stored as a state variable. In TxMirror, this address was allowed to be stored in a storage slot but could not be compared with other data. Clearly, TxMirror and TxSpector have completely converse rules to check the misuse of origin because we had a completely different comprehension for this vulnerability.

6.2.6. Results of Unchecked Call

TxMirror flagged 21,328 unchecked calls. This was the most among the tools. Mythril flagged 171 smart contracts, 56 of which were also flagged by TxMirror. Vandal flagged 5801, of which 4026 were also flagged by TxMirror. TxSpector checked 17,115 transactions that had unchecked calls, 16,996 of which were also flagged by TxMirror, which equaled 99.3% of the results of TxSpector. However, there were 4332 transactions flagged by TxMirror but ignored by TxSpector. We analyzed them and found they transformed tokens to external accounts [46]. Although transforming to external accounts did not execute smart contracts, it also returned a bool variable to represent whether or not this transaction was successful. TxSpector may think these calls did not need to be checked, but we checked them because they had the risk of failure too.

6.3. Efficiency Analysis

Experiment time is listed in Table 3. Mythril and Vandal analyzed 10,620 smart contracts. TxSpector, TxMirror, and Perez’s tool analyzed 357,293 transactions. The number of transactions was more than 30 times the number of smart contracts. However, Mythril used almost 57 h to analyze the smart contracts, while Vandal used less than 6 h. For the tools for checking transactions, TxSpector uses 52 h, which was much more than TxMirror and Perez’s tool. Perez’s tool used almost 20 h and TxMirror used only 4.5 h. Because we had stored the data in a mobile hard drive, the tools used a lot of time to read the data into memory. In addition, the monitoring program may have affected efficiency. Therefore, we calculated the average time each tool needed to analyze data. From the table, TxMirror was 0.48 s less than TxSpector and 0.15 s less than Perez’s tool for each transaction. It is obvious that TxMirror has better efficiency than other tools. In order to measure the real speed of TxMirror, we selected 10,000 transactions randomly from our dataset and stored them locally. We used TxMirror to analyze them directly, and it only used 21 s. That is, TxMirror could analyze more than 400 transactions per second.

7. Discussion

Compared with traditional logic analysis methods, there are many advantages of TxMirror. Firstly, TxMirror is more efficient. Logic analysis methods store all of the logic until the analysis finishes. They can inquire about all of the logic at any time. However, they need to waste a lot of time inquiring about the logic to obtain the dependence among the opcodes. TxMirror is designed as a simulator to analyze transactions, which enables the related logic to be indexed by the data. Therefore, we can obtain the dependence among the opcodes easily, which makes TxMirror at least four times faster than other methods. Secondly, TxMirror has more accurate detection for certain attacks and vulnerabilities, for example, suicide attacks because TxMirror can analyze the attributes of all the data. Last but not least, TxMirror has a high application value. Other tools can just be run standalone. However, because TxMirror contains a virtual machine, it can be combined with Ethereum to detect smart contracts while running them with few influences on the transaction speed. When an attack or a vulnerability is detected, it can notify miners not to package this transaction to prevent economic losses, which is something that the other tools cannot achieve.
However, there are also some disadvantages when compared with other tools because TxMirror does not store all the logic dependence permanently. Firstly, we cannot provide separate APIs for each attack or vulnerability. If we provide separate APIs, it means we need to simulate the transactions one time for each attack or vulnerability, which wastes too much time. Secondly, this may lead to missing attacks and vulnerabilities. We proposed a complex algorithm to solve this problem, which makes realizing TxMirror difficult.
There is also a limitation in TxMirror. TxMirror can only detect the attacks and vulnerabilities triggered during the running process. If the attack happens before the smart contract starts to run, it will not be detected, for example, the short address attack. This is a common problem for detecting methods based on transactions.

8. Conclusions

This paper proposed a new data-driven analyzing framework for smart contract security. Through simulating the whole execution of transactions, the tool can dynamically analyze vulnerabilities in a hybrid of smart contract calling and detects attacks and vulnerabilities in terms of transactions. In this paper, our tool detected eight kinds of attacks and vulnerabilities by experimenting with some available smart contracts. Compared with other state-of-the-art tools, our conducted experiment showed that TxMirror detects more kinds of smart contract vulnerabilities, has higher accuracy for certain vulnerabilities, and uses less time. In the future, we will make more contributions to this topic.

Author Contributions

Conceptualization, Y.Z.; methodology, Y.Z.; Software, Y.Z.; validation, Y.Z.; formal analysis, Y.Z. and C.L.; investigation, Y.Z., Y.W. and C.L.; data curation, Y.Z., Y.W. and C.L.; writing—original draft, Y.Z.; writing—review and editing, R.Y. and Y.Z.; visualization, Y.Z. and Y.W.; supervision, R.Y.; project administration, R.Y.; funding acquisition, R.Y. All authors have read and agreed to the published version of the manuscript.

Funding

This research was funded by the National Science Foundation of China (NO. 42071431), the Key National Research and Development of China Plan (NO. 2020YFB1805400), and the Key Research and Development Plan of Hubei Province (No. 2020BAB101).

Data Availability Statement

The data presented in this study are not available, because they are applied in another project.

Conflicts of Interest

The authors declare no conflict of interest.

References

  1. Aldyaflah, I.M.; Wenbing, Z.; Himanshu, U.; Leonel, L. The Design and Implementation of a Secure Datastore Based on Ethereum Smart Contract. Appl. Sci. 2023, 13, 5282. [Google Scholar] [CrossRef]
  2. Chinnasamy, P.; Ashwag, A.; Mudassir, K.; Khan, M.; Raja, A.A.; Ajmeera, K.; Jyothi, C.B. Smart Contract-Enabled Secure Sharing of Health Data for a Mobile Cloud-Based E-Health System. Appl. Sci. 2023, 13, 3970. [Google Scholar] [CrossRef]
  3. Alanzi, H.; Mohammad, A. Towards Improving Privacy and Security of Identity Management Systems Using Blockchain Technology: A Systematic Review. Appl. Sci. 2022, 12, 12415. [Google Scholar] [CrossRef]
  4. Wood, G. Ethereum: A secure decentralised generalised transaction ledger. Ethereum Proj. Yellow Pap. 2014, 151, 1–32. [Google Scholar]
  5. Mehar, M.I.; Shier, C.L.; Giambattista, A.; Gong, E.; Fletcher, G.; Sanayhie, R.; Kim, H.M.; Laskowski, M. Understanding a revolutionary and flawed grand experiment in blockchain: The DAO attack. J. Cases Inf. Technol. 2019, 21, 19–32. [Google Scholar] [CrossRef] [Green Version]
  6. Etherscan: The BEC. 2018. Available online: https://etherscan.io/address/0xc5d105e63711398af9bbff092d4b6769c82f793d (accessed on 9 February 2018).
  7. Atzei, N.; Bartoletti, M.; Cimoli, T. A Survey of Attacks on Ethereum Smart Contracts (sok). In Proceedings of the International Conference on Principles of Security and Trust, Uppsala, Sweden, 22–29 April 2017; Springer: Berlin/Heidelberg, Germany, 2017; pp. 164–186. [Google Scholar]
  8. Durieux, T.; Ferreira, J.F.; Abreu, R.; Cruz, P. Empirical Review of Automated Analysis Tools on 47,587 Ethereum Smart Contracts. In Proceedings of the ACM/IEEE 42nd International Conference on Software Engineering, Seoul, Republic of Korea, 27 June–19 July 2020; pp. 530–541. [Google Scholar]
  9. Tsankov, P.; Dan, A.; Drachsler-Cohen, D.; Gervais, A.; Buenzli, F.; Vechev, M. Securify: Practical Security Analysis of Smart Contracts. In Proceedings of the 2018 ACM SIGSAC Conference on Computer and Communications Security, Toronto, ON, Canada, 15–19 October 2018; pp. 67–82. [Google Scholar]
  10. Zhang, M.; Zhang, X.; Zhang, Y.; Lin, Z. TXSPECTOR Uncovering Attacks in Ethereum from Transactions. In Proceedings of the 29th USENIX Security Symposium (USENIX Security 20), Boston, MA, USA, 12–14 August 2020; pp. 2775–2792. [Google Scholar]
  11. Krupp, J.; Rossow, C. teEther Gnawing at Ethereum to Automatically Exploit Smart Contracts. In Proceedings of the 27th USENIX Security Symposium (USENIX Security 18), Baltimore, MD, USA, 15–17 August 2018; pp. 1317–1333. [Google Scholar]
  12. Chen, J.; Xia, X.; Lo, D.; Grundy, J.; Luo, X.; Chen, T. Defectchecker: Automated smart contract defect detection by analyzing evm bytecode. IEEE Trans. Softw. Eng. 2021, 48, 2189–2207. [Google Scholar] [CrossRef]
  13. So, S.; Lee, M.; Park, J.; Lee, H.; Oh, H. VeriSmart: A Highly Precise Safety Verifier for Ethereum Smart Contracts. In Proceedings of the 2020 IEEE Symposium on Security and Privacy (SP), San Francisco, CA, USA, 18–21 May 2020; pp. 1678–1694. [Google Scholar]
  14. Tikhomirov, S.; Voskresenskaya, E.; Ivanitskiy, I.; Takhaviev, R.; Marchenko, E.; Alexandrov, Y. Smartcheck: Static Analysis of Ethereum Smart Contracts. In Proceedings of the 1st International Workshop on Emerging Trends in Software Engineering for Blockchain, Gothenburg, Sweden, 27 May 2018; pp. 9–16. [Google Scholar]
  15. Hildenbrandt, E.; Saxena, M.; Rodrigues, N.; Zhu, X.; Daian, P.; Guth, D.; Moore, B.; Park, D.; Zhang, Y.; Stefanescu, A.; et al. Kevm: A Complete Formal Semantics of the Ethereum Virtual Machine. In Proceedings of the 2018 IEEE 31st Computer Security Foundations Symposium (CSF), Oxford, UK, 9–12 July 2018; pp. 204–217. [Google Scholar]
  16. Schneidewind, C.; Grishchenko, I.; Scherer, M.; Maffei, M. ethor: Practical and Provably Sound Static Analysis of Ethereum Smart Contracts. In Proceedings of the2020 ACM SIGSAC Conference on Computer and Communications Security, Online, 9–13 November 2020; pp. 621–640. [Google Scholar]
  17. Grieco, G.; Song, W.; Cygan, A.; Feist, J.; Groce, A. Echidna: Effective, Usable, and Fast Fuzzing for Smart Contracts. In Proceedings of the ISSTA 2020—Proceedings of the 29th ACM SIGSOFT International Symposium on Software Testing and Analysis, Online, 18–22 July 2020; pp. 557–560. [Google Scholar]
  18. Torres, C.F.; Iannillo, A.K.; Gervais, A.; State, R. ConFuzzius: A Data Dependency-Aware Hybrid Fuzzer for Smart Contracts. In Proceedings of the 2021 IEEE European Symposium on Security and Privacy (EuroS&P), Vienna, Austria, 6–10 September 2021; pp. 103–119. [Google Scholar]
  19. Baldoni, R.; Coppa, E.; D’elia, D.C.; Demetrescu, C.; Finocchi, I. A survey of symbolic execution techniques. ACM Comput. Surv. 2018, 51, 50. [Google Scholar] [CrossRef] [Green Version]
  20. Luu, L.; Chu, D.H.; Olickel, H.; Saxena, P.; Hobor, A. Making Smart Contracts Smarter. In Proceedings of the 2016 ACM SIGSAC Conference on Computer and Communications Security, Vienna, Austria, 24–28 October 2016; pp. 254–269. [Google Scholar]
  21. Mythril: A Security Analysis Tool for EVM Bytecode. Available online: https://github.com/ConsenSys/mythril (accessed on 1 January 2021).
  22. Mossberg, M.; Manzano, F.; Hennenfent, E.; Groce, A.; Grieco, G.; Feist, J.; Brunson, T.; Dinaburg, A. Manticore: A User-Friendly Symbolic Execution Framework for Binaries and Smart Contracts. In Proceedings of the 2019 34th IEEE/ACM International Conference on Automated Software Engineering (ASE), San Diego, CA, USA, 11–15 November 2019; pp. 1186–1189. [Google Scholar]
  23. So, S.; Hong, S.; Oh, H. SmarTest Effectively Hunting Vulnerable Transaction Sequences in Smart Contracts through Language Model—Guided Symbolic Execution. In Proceedings of the 30th USENIX Security Symposium (USENIX Security 21), Vancouver, BC, Canada, 11–13 August 2021; pp. 1361–1378. [Google Scholar]
  24. Chang, J.; Gao, B.; Xiao, H.; Sun, J.; Cai, Y.; Yang, Z. sCompile: Critical Path Identification and Analysis for Smart Contracts. In International Conference on Formal Engineering Methods; Springer: Berlin/Heidelberg, Germany, 2019; pp. 286–304. [Google Scholar]
  25. Zhou, E.; Hua, S.; Pi, B.; Sun, J.; Nomura, Y.; Yamashita, K.; Kurihara, H. Security Assurance for Smart Contract. In Proceedings of the 2018 9th IFIP International Conference on New Technologies, Mobility and Security (NTMS), Paris, France, 26–28 February 2018; pp. 1–5. [Google Scholar]
  26. Brent, L.; Jurisevic, A.; Kong, M.; Liu, E.; Gauthier, F.; Gramoli, V.; Holz, R.; Scholz, B. Vandal: A scalable security analysis framework for smart contracts. arXiv 2018, arXiv:1809.03981. [Google Scholar]
  27. Feist, J.; Grieco, G.; Groce, A. Slither: A Static Analysis Framework for Smart Contracts. In Proceedings of the 2019 IEEE/ACM 2nd International Workshop on Emerging Trends in Software Engineering for Blockchain (WETSEB), Montreal, QC, Canada, 27 May 2019; pp. 8–15. [Google Scholar]
  28. Park, D.; Zhang, Y.; Saxena, M.; Daian, P.; Roşu, G. A Formal Verification Tool for Ethereum VM Bytecode. In Proceedings of the 2018 26th ACM Joint Meeting on European Software Engineering Conference and Symposium on the Foundations of Software Engineering, Lake Buena Vista, FL, USA, 4–9 November 2018; pp. 912–915. [Google Scholar]
  29. Kalra, S.; Goel, S.; Dhawan, M.; Sharma, S. Zeus: Analyzing Safety of Smart Contracts. In Proceedings of the 25th Annual Network and Distributed System Security Symposium (NDSS 2018), San Diego, CA, USA, 18–21 February 2018; pp. 1–12. [Google Scholar]
  30. Lattner, C.; Adve, V. LLVM: A Compilation Framework for Lifelong Program Analysis & Transformation. In Proceedings of the International Symposium on Code Generation and Optimization, San Jose, CA, USA, 20–24 March 2004; pp. 75–86. [Google Scholar]
  31. McMillan, K.L. Interpolants and Symbolic Model Checking. In International Workshop on Verification, Model Checking, and Abstract Interpretation; Springer: Berlin/Heidelberg, Germany, 2007; pp. 89–90. [Google Scholar]
  32. Bhargavan, K.; Delignat-Lavaud, A.; Fournet, C.; Gollamudi, A.; Gonthier, G.; Kobeissi, N.; Kulatova, N.; Rastogi, A.; Sibut-Pinote, T.; Swamy, N.; et al. Formal Verification of Smart Contracts: Short Paper. In Proceedings of the 2016 ACM Workshop on Programming Languages and Analysis for Security, Vienna, Austria, 24 October 2016; pp. 91–96. [Google Scholar]
  33. Permenev, A.; Dimitrov, D.; Tsankov, P.; Drachsler-Cohen, D.; Vechev, M. Verx: Safety Verification of Smart Contracts. In Proceedings of the 2020 IEEE Symposium on Security and Privacy (SP), San Francisco, CA, USA, 18–21 May 2020; pp. 1661–1677. [Google Scholar]
  34. Jiang, B.; Liu, Y.; Chan, W.K. Contractfuzzer: Fuzzing Smart Contracts for Vulnerability Detection. In Proceedings of the 2018 33rd IEEE/ACM International Conference on Automated Software Engineering (ASE), Montpellier, France, 3–7 September 2018; pp. 259–269. [Google Scholar]
  35. He, J.; Balunović, M.; Ambroladze, N.; Tsankov, P.; Vechev, M. Learning to Fuzz from Symbolic Execution with Application to Smart Contracts. In Proceedings of the2019 ACM SIGSAC Conference on Computer and Communications Security, London, UK, 11–15 November 2019; pp. 531–548. [Google Scholar]
  36. Nguyen, T.D.; Pham, L.H.; Sun, J.; Lin, Y.; Minh, Q.T. sfuzz: An Efficient Adaptive Fuzzer for Solidity Smart Contracts. In Proceedings of the ACM/IEEE 42nd International Conference on Software Engineering, Seoul, Reoublic of Korea, 27 June–19 July 2020; pp. 778–788. [Google Scholar]
  37. Zhuang, Y.; Liu, Z.; Qian, P.; Liu, Q.; Wang, X.; He, Q. Smart Contract Vulnerability Detection Using Graph Neural Network. In Proceedings of the Twenty-Ninth International Joint Conference on Artificial Intelligence, Yokohama, Japan, 11–17 July 2020; pp. 3283–3290. [Google Scholar]
  38. Liu, Z.; Qian, P.; Wang, X.; Zhuang, Y.; Qiu, L.; Wang, X. Combining Graph Neural Networks With Expert Knowledge for Smart Contract Vulnerability Detection. IEEE Trans. Knowl. Data Eng. 2021, 35, 1296–1310. [Google Scholar] [CrossRef]
  39. Liu, Z.; Qian, P.; Wang, X.; Zhu, L.; He, Q.; Ji, S. Smart Contract Vulnerability Detection: From Pure Neural Network to Interpretable Graph Feature and Expert Pattern Fusion. arXiv 2021, arXiv:2106.09282. [Google Scholar]
  40. Rodler, M.; Li, W.; Karame, G.O.; Davi, L. Sereum: Protecting existing smart contracts against reentrancy attacks. arXiv 2018, arXiv:1812.05934. [Google Scholar]
  41. Grossman, S.; Abraham, I.; Golan-Gueta, G.; Michalevsky, Y.; Rinetzky, N.; Sagiv, M.; Zohar, Y. Online detection of effectively callback free objects with applications to smart contracts. Proc. ACM Program. Lang. 2017, 2, 48. [Google Scholar] [CrossRef] [Green Version]
  42. Perez, D.; Livshits, B. Smart Contract Vulnerabilities: Vulnerable Does Not Imply Exploited. In Proceedings of the 30th USENIX Security Symposium (USENIX Security 21), Vancouver, BC, Canada, 11–13 August 2021; pp. 1325–1341. [Google Scholar]
  43. Ethereum Virtual Machine Opcodes. Available online: https://ethervm.io (accessed on 1 May 2023).
  44. A False Positive Example of Integer Overflow. Available online: https://etherscan.io/tx/0xe2d590c8b82058d8c6c32fbbfadd542fa29544f592287111b3f4dcabd6500f1f (accessed on 16 September 2016).
  45. An Example of Using Arguments to Verify to Suicide. Available online: https://etherscan.io/tx/0x08164923d4082fd70e4154404ebab0048d18a42460905c539521fba6af655257 (accessed on 14 September 2016).
  46. An Example of Unchecked Call Transferring ETHs to External Accounts. Available online: https://etherscan.io/tx/0x138586bd5ef4bd5bacad3d09f7f7c72f608a1f77ae99ea8fb238b2ea4facfd50 (accessed on 15 September 2016).
Figure 1. The weakness of other tools.
Figure 1. The weakness of other tools.
Symmetry 15 01345 g001
Figure 2. The design of TxMirror.
Figure 2. The design of TxMirror.
Symmetry 15 01345 g002
Figure 3. Data storage form.
Figure 3. Data storage form.
Symmetry 15 01345 g003
Figure 4. An example of a simulation.
Figure 4. An example of a simulation.
Symmetry 15 01345 g004
Figure 5. An example to obtain 0xFFFFFF.
Figure 5. An example to obtain 0xFFFFFF.
Symmetry 15 01345 g005
Table 1. The analysis of related tools. TOD means transaction-ordering dependence. TD means timestamp dependence. RE means reentrancy. IO means integer overflow. SU means suicidal. UC means unchecked call. UB means unsecured balance. MO means misuse of origin. SO means stack overflow. ✔ means tools using symbolic execution. ● means tools using static analysis. ▲ means tools using fuzzing. ★ means tools of transaction.
Table 1. The analysis of related tools. TOD means transaction-ordering dependence. TD means timestamp dependence. RE means reentrancy. IO means integer overflow. SU means suicidal. UC means unchecked call. UB means unsecured balance. MO means misuse of origin. SO means stack overflow. ✔ means tools using symbolic execution. ● means tools using static analysis. ▲ means tools using fuzzing. ★ means tools of transaction.
TODTDMEREIOSUUCUBMOSO
Oyente
Mythril
Manticore
Securify
Vandal
Slither
ContractFuzzer
ILF
sFuzz
Sereum
ECFChecker
TxSpector
Perez’s
TxMirror
Table 2. The results of different tools. IO means integer overflow. RA means reentrancy attack. SA means suicide attack. TD means timestamp dependence. MO means misuse of origin. UC means unchecked call. A(B) means the tool flags A data and B of them are also flagged by TxMirror.
Table 2. The results of different tools. IO means integer overflow. RA means reentrancy attack. SA means suicide attack. TD means timestamp dependence. MO means misuse of origin. UC means unchecked call. A(B) means the tool flags A data and B of them are also flagged by TxMirror.
TotalError/TimeoutIORASATDMOUC
Mythril [21]10,62088310 (44)50 (7)19 (1)53 (32)43 (4)171 (56)
Vandal [26]0-1918 (88)1007 (0)-110 (1)5801 (4026)
TxSpector [10]357,293370-614 (601)2 (2)-113 (0)17,115 (16,996)
Perez et al. [42]04828 (3658)2139 (918)----
TxMirror063561587414,89927321,328
Table 3. The efficiency of different tools. The average means the processing time for each smart contract or transaction.
Table 3. The efficiency of different tools. The average means the processing time for each smart contract or transaction.
TotalTimeAverage (s)
Mythril10,62056 h 57 m 3 s19.30
Vandal5 h 41 m 41 s1.93
TxSpector357,29352 h 36 m 15 s0.53
Perez et al. [42]19 h 48 m 42 s0.20
TxMirror4 h 35 m 47 s0.05
Disclaimer/Publisher’s Note: The statements, opinions and data contained in all publications are solely those of the individual author(s) and contributor(s) and not of MDPI and/or the editor(s). MDPI and/or the editor(s) disclaim responsibility for any injury to people or property resulting from any ideas, methods, instructions or products referred to in the content.

Share and Cite

MDPI and ACS Style

Yu, R.; Zhang, Y.; Wang, Y.; Liu, C. TxMirror: When the Dynamic EVM Stack Meets Transactions for Smart Contract Vulnerability Detection. Symmetry 2023, 15, 1345. https://doi.org/10.3390/sym15071345

AMA Style

Yu R, Zhang Y, Wang Y, Liu C. TxMirror: When the Dynamic EVM Stack Meets Transactions for Smart Contract Vulnerability Detection. Symmetry. 2023; 15(7):1345. https://doi.org/10.3390/sym15071345

Chicago/Turabian Style

Yu, Rongwei, Yuhang Zhang, Yong Wang, and Chen Liu. 2023. "TxMirror: When the Dynamic EVM Stack Meets Transactions for Smart Contract Vulnerability Detection" Symmetry 15, no. 7: 1345. https://doi.org/10.3390/sym15071345

Note that from the first issue of 2016, this journal uses article numbers instead of page numbers. See further details here.

Article Metrics

Back to TopTop