On Decentralized Finance (DeFi): Exploring the Major Security Analysis Tools used to Detect or Minimize Potential Attacks on the Smart Contract.
In our previous articles (part 1 and part 2), we explained in detail the decentralized finance applications, potential use cases, security vulnerabilities, and described some real attacks related to smart contract security vulnerabilities from the perspective of (DeFi). In this article, we explore the major security analysis tools used to detect or minimize attacks on smart contracts. Most of these tools are mainly utilized for static and dynamic analysis of smart contract codes. We also explore other recommendations from known best practice on how to minimize such attacks.
1. Smart contact security analysis tools
Slither is a smart contract code static analysis framework . It has rapid and reliable security detection algorithms for potential bugs. Slither can be used for automatic vulnerability discovery, automated optimization detection, code interpretation, and assisted code review, among other things. For example a multi-stage approach is initiated for the security analysis. From the contract source code, the Solidity compiler generates a Solidity Abstract Syntax Tree (AST), which is used as an input to Slither. During the early stages of the contract, Slither obtains essential contract information such as the inheritance graph, Control-flow graph (CFG), and so on .
MythX is a vulnerability scanner for EVM-based smart contracts. It includes static, dynamic, and symbolic execution approaches, among others. MythX’s major goal is to help DApp developers create smart contracts in order to make the platform safer. MythX does not fulfill the requirements on its own; instead, it is used in conjunction with development tools like Truffle and Remix. These security tools are not only compatible with the Ethereum platform; developers working on Tron, Vechain, Quorum, Roostock, and a few other EVM-based platforms can also use them to discover problems in smart contracts. To examine smart contract code, MythX goes through three stages. First, developers must submit their code; second, a comprehensive set of analysis tools must be triggered; and, finally, an analysis report demonstrating any flaws must be generated.
Mythril is a security tool that analyzes smart contracts written by Solidity. Mythril, an open-source tool, takes advantage of the symbolic execution technique in order to determine the errors in code. The examination of security flaws involves executing smart contract bytecode in a custom built EVM. Mythril goes through four major working stages to accomplish its security analysis. When a flaw in a program is discovered, the input transactions are analyzed to determine the possible reasons. This security method helps to deduce the main cause of the program vulnerability, and also mitigate exploitation. If a developer produces the source code of the contract, Mythril is able to locate the bugs within the code.
Manticore is a Solidity audit tool that performs a symbolic analysis of smart contracts. The main functions of manticore involve tracing inputs that terminate a program, logging instruction-level implementation, and providing access to its analysis engine through Python API. It has a dynamic symbolic execution feature which analyzes binaries as well as Ethereum smart contracts. The primary attributes in Manticore’s architecture comprise the Core Engine, Native Execution Modules, and Ethereum Execution Modules. The Satisfiability Modulo Theories (SMT-LIB) module, Event System, and API are regarded as secondary attributes.
Securify is a smart contract security analyzer tool . Securify is an automated tool able to determine whether the contract performs accordingly, based on the provided attributes. Securify is an open-source product whose security analysis function goes through two stages to perform the required task. Up to this point, around 18000 contracts have been submitted to Securify for security analysis. Securify accepts EVM bytecode for security analysis. Contracts written in Solidity are also accepted as an input, however, the code needs to be compiled to EVM bytecode for the security process to be effected. When a security violation is triggered, Securify produces a command which induces the violation pattern to match. Similarly, when both the violation and compliance pattern do not match, it generates a warning. The security analysis technique of Securify is unique when compared with other tools such as Oyente and Mythril. While Oyente and Mythril symbolically enumerate distinct paths of a contract, Securify utilizes static analysis to analyze every path of the smart contract.
SmartCheck is an automated extensive vulnerability analysis tool for Solidity smart contracts . SmartCheck is an open-source engine which not only points out the vulnerabilities in the smart contract code but also clarifies the cause of the vulnerabilities with proper description and recommendation. SmartCheck was implemented by utilizing XPath [xpa] queries on the intermediate representation (IR) to detect vulnerability patterns. SmartCheck protects any analyzed code that has been converted to IR and elements associated with it are determined with XPath matching.
A security experiment was initiated by SmartCheck on over 4600 valid contracts. It was determined that 86.6% of the contacts comprised zero balance, whereas a single contract consisted of a balance of only 38.4% of the total balance. The SmartCheck analysis indicated that 99.9% of analyzed contracts contained some kind of security flaw, with 63.2% of contracts being severely vulnerable.
Echidna is an EVM smart fuzzer that identifies bugs in Solidity code. This tool only requires the Solidity propositions to conduct deep analysis for bugs and provides a clear user interface (UI) to simplify its output. Echidna utilizes different combinations of inputs until it manages to break the provided property. Echidna contains a few similar attributes to Manticore, which allows it to function at the EVM level. In addition, it can also be consolidated to continuous integration (CI) in order to identify code bugs whilst development is in process. A myriad of tools are supplied by Echidna in order to compose custom analyses for dealing with complicated contracts. This tool utilizes stack, therefore, the required dependency will be based on the solc version that the contract employs.
Oyente is a symbolic execution tool for finding smart contract security flaws. Oyente analyses Ethereum smart contracts for security flaws that could lead to possible attacks. Oyente not only finds dangerous bugs, but it also looks at every possible execution path. In an experiment conducted by Oyente on 19,366 smart contracts, 8,833 of them were found to be susceptible. The symbolic execution approach uses a mathematical formula to reflect the characteristics of an execution path. OYENTE compares the new formula to formulae that contain common bugs to see if both formulas are valid at the same time.
Vandal is another security analysis framework for smart contracts. Vandal comprises an analysis pipeline which transforms EVM bytecode into semantic logic relations. Vandal is a very fast and efficient security analysis tool that has examined over 95% of 141000 smart contracts with an average run-time overhead of only 4.15 seconds. The low overhead beats the overall performance of major existing security analysis tools. The security design of Vandal comprises a declarative language called Soufflé. Performing security analysis in a declarative language helps security analysts with the prototype of the latest analysis.
Zeus is a practical framework to examine the validity of smart contracts . It takes advantage of abstract interpretation, and symbolic model checking for analyzing the safety of smart contracts. The Zeus prototype has tested over 22400 smart contracts, showing that about 94.6% of these contracts are vulnerable. Zeus accepts the smart contract code and generates the authentic version in an XACML-styled template. The smart contract code and the policy specifications are translated to LLVM bitcode to enhance the contract’s behavior. Zeus performs static analysis of the furnished smart contract code to append the assert statement policy at the right spot of the program.
It is a visualization security tool used to generate a DOT graph for maintaining secured control flow of solidity contract. Its significant role is to detect and highlight possible security vulnerabilities.
1.12 Ethereum graph debugger
It is an EVM debugging tool used to display or represent the overall program control flow in graphical analysis.
illustrate Smart Contact Security Analysis Tools Versus Detected Attacks
Notably, these are the most popular smart contract analysis tools used, despite the fact that there are other analysis tools used to analyze the smart contract codes.
2. Some Recommendations Based on well-known Best Practices for Securing Smart Contract Vulnerability Attacks.
Most of the blockchain platforms have numerous security issues that hackers can exploit. Yet, it is possible to solve these issues at the stage of smart contract development. The best way to overcome these issues is by undertaking the best practices with no possibility of introducing any vulnerabilities or unexpected events.
It is essential to follow the best practices for writing secure smart contracts in different platforms and programming languages.
2.1 Best Practices for Handling Solidity Smart Contracts Security
2.1.1 Handling the funds
There are multiple options to handle and collect the funds throughout the development of a crowdsale smart contract. Here are some ways to manage the funds.
In contract: During the crowdsale, the funds are kept in a contract. These funds are transferred to the developer’s address after the crowdsale gets over.
Forwarding: It is another way to transfer the funds to a multisig wallet instead of storing them temporarily in a contract. So, funds are kept in an intermediate multisig contract with a time lock facility to maintain the funds in an immovable state till the end of the crowdsale .
2.1.2 Make use of Fallback Functions and Race Conditions
It is preferred to call the fallback functions when no functions match and has accessibility to 2300 gas when called from .send() or .transfer(). Logging an event in a fallback function can help you to get ether from .send() or .transfer().
Calling external contracts may often take over the control flow and make changes to data. This type of bug can lead to DAO collapse 
2.1.3 Make a proper use of assert( ), require ( ) and revert ( ) functions
It is essential to understand the correct usage of assert, require and revert functions. In general, assert and require functions are helpful to check for conditions and throw an exception if conditions are not met. To be more precise, use the assert function to test for internal errors and check invariants. On the other hand, the require() function ensures whether the valid conditions like inputs or state variables are met. Require() functions can be used to validate return values from calls to external contracts.
2.1.4 Label the functions and state variables
Marking the visibility makes it simple to spot false assumptions about who can call a function or access a variable. External, internal, public, or private functions are defined. Understanding the differences between them can help you use them correctly for a certain task. When big arrays of data are received, external functions are generally invoked. To generate an automatic getter function, the public functions are called internally or via messages. Internal functions and state variables, on the other hand, are only accessed internally. For the duration of the contract, private functions and state variables are visible.
2.1.5 Use events to track the contract activity
Monitoring the smart contracts with events is one way to secure them. It is possible to track all the contract transactions, but the message calls are not recorded in the blockchain. Therefore, only input parameters remain visible and not the actual changes made into the state. Hence, events can help trigger the functions in the user interface. Consider a sample code given below.
· Here, a Game contract will make an internal call to Charity.donate(). An event is a correct way to log something that happened in the contract. Earlier events remain in the blockchain with the other contract data and they become available for future audit perspectives. Here is an improvement to the example shown above, using events to provide a history of Charity’s donations. This transaction does not appear in Charity’s external transaction list but remains visible in the internal transactions.
· Use modifiers only for checks.
The code represented in a modifier gets executed before the function body. Therefore, any modifications in the state or external calls break the check-effects-interaction design pattern. The developers cannot notice such statements as the code for a modifier is far from function declaration. Consider the following example, where an external call in modifier results in a reentrancy.
Here, the Registry contract is prone to cause a reentrancy attack by calling Election.vote() inside isVoter(). The modifiers help replace duplicate condition checks in multiple functions like isOwner() or make use of require or revert inside the function. It will ensure the readability and auditability of smart contract codes.
· Prevent rounding the integer division.
When integer division occurs, it rounds down to the nearest value of an integer. If more accuracy is required, it is better to use a multiplier or store the numerator and denominator values. These stored values can help in calculating the result of the numerator /denominator in off-chain mode.
· Tradeoffs between interfaces and abstract contracts.
The interfaces and abstract contracts are effective in providing a customizable and reusable approach for smart contracts. Although interfaces resemble abstract contracts, they lack in some functions, cannot access storage or inherit other interfaces. They help design the contracts before implementation. When a contract inherits from the abstract contract, it must implement all the other functions by overriding it.
2.2 Best practices for Ethereum Smart Contracts Security
The most extensively utilized platform is Ethereum. It is critical to follow best practices for smart contract security when implementing smart contracts on Ethereum.
a.) Mark untrusted contracts
It is essential to specify your variables, methods, and contract interfaces during any interaction with external contracts. It applies to the functions which call external contracts.
b.) Prevent state changes after external calls
While using raw calls or contract calls, there is a possibility that malicious code may get executed. Although the external contract is not malicious, the malicious code may undergo execution by any contract it calls. The malicious code can hijack the control flow and result in causing vulnerabilities due to reentrancy. Therefore, while making a call to an untrusted external contract, prevent the state changes right after the call. This pattern is known as the check-effects-interaction pattern.
c.) Error-Handling in External calls
The low-level call methods in solidity, which work on raw addresses, never throw an exception but return to a false value when an exception is encountered. On the contrary, the contract calls result in propagating a throw automatically on discovering any throw function like doSomething(). So, when you prefer to choose low-level call methods, ensure to handle the possibility of call failure by monitoring the return value.
d.) Prefer pull over push for external calls
The external calls are prone to accidental failure. It is generally applicable in payments, where the users can withdraw or pull the funds automatically instead of pushing funds. It also minimizes the issues associated with the gas limit.
It is better to isolate each external call into its transaction, which the call recipient initiates.
e.) Avoid using delegatecall functions to untrusted code
The delegatecall helps to call the functions from other contracts if they are related to the caller contract. So, the callee can change the state of the calling address. This step is highly insecure and may lead to the destruction of the contract and loss of balance.
When Worker.doWork() is called with the address of deployed destructor contract in terms of argument, the worker contract undergoes self-destruction. Hence, it is necessary to delegate the execution only to trusted contracts and not to a user-supplied address for enabling secure transactions.