Smart contract vulnerability detection method and system based on hybrid fuzz testing optimization

By using a hybrid fuzz testing optimization method, combined with static analysis, symbolic execution, and taint analysis, the problems of high false positive rate and low complex branch coverage in smart contract vulnerability detection are solved, comprehensive vulnerability detection of smart contracts is achieved, and detection accuracy and coverage are improved.

CN119337385BActive Publication Date: 2025-09-26YANTAI UNIV
View PDF 0 Cites 0 Cited by

Patent Information

Application Number
CN202411845270.2
Authority / Receiving Office
CN · China
Patent Type
Patents(China)
Current Assignee / Owner
Filing Date
2024-12-16
Publication Date
2025-09-26
Estimated Expiration
2044-12-16

AI Technical Summary

Technical Problem

Existing smart contract vulnerability detection methods suffer from high false positive rates and an inability to comprehensively detect complex branch vulnerabilities, especially for smart contracts under blockchain technology. Traditional methods such as symbolic execution and fuzz testing have limitations in path explosion and random test case generation, and cannot effectively detect special vulnerabilities such as gas limits and permission configuration errors.

Method used

A hybrid fuzz testing optimization method is adopted, combining static analysis, symbolic execution and taint analysis to generate a test case set and perform fuzz testing. Complex branches are handled through symbolic execution, and constraint solving and taint analysis are used to detect permission control, transaction order dependency and denial of service smart contract vulnerabilities.

Benefits of technology

It improves the accuracy and coverage of vulnerability detection, can effectively explore deep branches, reduce the amount of calculation, comprehensively detect complex vulnerabilities in smart contracts, and reduce the false alarm rate.

✦ Generated by Eureka AI based on patent content.

Smart Images

  • Figure CN119337385B_ABST
    Figure CN119337385B_ABST
Patent Text Reader

Abstract

The present invention relates to the field of network security and vulnerability detection technology, specifically a smart contract vulnerability detection method and system based on hybrid fuzz testing optimization, which performs static analysis on compiled EVM bytecode to generate a first test case set, performs fuzz testing, and introduces taint analysis to track the propagation of taints in the instruction stream. During the fuzz testing process, according to the length change of the instruction count set within the execution number threshold, the symbolic execution process is triggered when the length change value is 0. During the symbolic execution process, a constraint cache reuse strategy is adopted to solve the obtained constraint expression, and the solution result is cached and reused, so that the symbolic execution can quickly generate the use case value of reaching complex branches, and feed it back to the fuzzy engine to assist it in exploring new paths to capture more deep-seated vulnerabilities; at the same time, test predictions are designed for three smart contract vulnerabilities: permission control, transaction sequence dependency, and denial of service, so that vulnerability detection is more accurate.
Need to check novelty before this filing date? Find Prior Art

Description

Technical Field

[0001] The present invention relates to the fields of network security and vulnerability detection technology, and specifically to a smart contract vulnerability detection method and system based on hybrid fuzz testing optimization. Background Art

[0002] In recent years, smart contracts have been widely used in various fields, and smart contracts supported by blockchain technology have made it possible to conduct trusted transactions in a decentralized or third-party-free environment.

[0003] Unlike traditional software security issues, due to the inherent immutability of blockchain technology, smart contracts cannot be modified once deployed, even if there are undeniable errors in their code. Therefore, the most effective vulnerability detection method currently is to thoroughly review smart contracts after they are deployed on-chain to identify and fix vulnerabilities.

[0004] Currently, various vulnerability detection techniques have been proposed to improve contract security, including symbolic execution, formal verification, and other static analysis methods. However, each method has its limitations. Symbolic execution symbolizes program variables to explore all possible execution paths, which can lead to a path explosion problem, thus affecting vulnerability detection effectiveness. Formal verification uses rigorous mathematical language and logic to describe smart contracts, enabling rigorous mathematical reasoning and verification. Effectively modeling necessary information, such as EVM instructions, is a major challenge for this technology. Because static analysis cannot actually execute every path, these methods often produce high false positive rates.

[0005] As a dynamic detection technology, fuzz testing rarely generates false positives, making it a major advantage in vulnerability detection. However, some vulnerabilities are only triggered when a specific function call sequence is met. Furthermore, relying solely on randomly generated test cases struggles to cover some complex branches within a contract, making fuzz testing unable to uncover vulnerabilities deep within these branches. Due to the unique mechanisms of smart contracts, they can present vulnerabilities that differ from those of conventional software. For example, denial-of-service smart contract vulnerabilities caused by block gas limits are not detected by some fuzzers, making it difficult to fully guarantee contract security. Summary of the Invention

[0006] The present invention provides a smart contract vulnerability detection method and system based on hybrid fuzzy testing optimization.

[0007] The technical solutions of the present invention are as follows:

[0008] A smart contract vulnerability detection method based on hybrid fuzz testing optimization includes the following steps:

[0009] S1. Obtain the source code of the smart contract, compile it to obtain EVM bytecode, perform static analysis on the EVM bytecode, and obtain the ABI interface parameter type and function call sequence based on the read and write dependencies between functions in the bytecode and the source code corresponding to the functions;

[0010] S2. Generate a first test case set based on the ABI interface parameter type and function call sequence, perform fuzz testing on the EVM bytecode based on the first test case set, obtain the number of all instructions covered by each test case during instruction execution, and construct an instruction count set; perform symbolic execution processing when the length change of the instruction count set within a set execution number threshold is 0,

[0011] The symbolic execution processing operation specifically includes: setting the branch when the instruction count set length change value is 0 as the target branch point, obtaining only the arithmetic instructions and logical instructions of all branch constraints on each execution path when the instruction is executed to the target branch point, converting them into constraint expressions through symbolic processing, and collecting the constraint expressions to construct a path constraint set;

[0012] Perform constraint solving after negating the constraint expression, cache and reuse the constraint expression and its solution results in the constraint solving process, obtain a specific input value that satisfies the branch constraint condition of the target branch point, update the specific input value into the first test case set as a new test case, obtain a second test case set, execute S2 in a loop, expand the second test case set, and terminate the loop until a set time is reached, then execute S3;

[0013] S3. Set different test oracles for different smart contract vulnerabilities, including permission control, transaction order dependency, and denial of service smart contract vulnerabilities; based on the test oracles, use the second test case set combined with taint analysis to perform smart contract vulnerability detection to obtain vulnerability detection results.

[0014] Furthermore, the taint analysis in S3 is specifically to perform taint analysis on the EVM bytecode based on the set taint propagation rules to obtain the propagation of taint data in the instruction stream, specifically:

[0015] Obtain function call parameters and transaction data instructions in the EVM bytecode, including CALLDATALOAD, CALLDATACOPY, SLOAD, CALLER, ORIGIN, and CALLVALUE instructions, and mark the instructions and their return values ​​as tainted;

[0016] Set CALL, SSTORE, JUMPI, ISZERO, SELFDESTRUCT, and DELEGATECALL instructions as taint sinks;

[0017] When different instructions are executed, the taint propagation is tracked based on the taint propagation rules, specifically:

[0018] For unary or multi-ary arithmetic instructions and logical instructions, if any operand contains taint, the result value obtained after executing the instruction will be marked as tainted.

[0019] For instructions that query the blockchain status and instructions that do not affect the execution and status of the contract, they are marked as fixed instructions that are not considered tainted.

[0020] For instructions that read data from memory or storage, if the instruction contains taint, the result value read is marked as tainted;

[0021] Based on the propagation of taints to taint sinks, the propagation path of taints in the instruction stream of EVM bytecode is obtained, and the vulnerability detection results are obtained based on the propagation path.

[0022] Specifically, in S2, constraint expressions and their solution results are cached and reused during constraint solving. The specific operations are as follows: a visited set is constructed based on the visited constraint expressions, a dictionary is constructed based on the solved constraint expressions and their solution results for caching, and the corresponding unique hash value of each constraint expression after the inversion operation is obtained as the key:

[0023] When solving a constraint expression, if the corresponding key exists in the dictionary, the solution in the dictionary is reused, otherwise the constraint solution is reset;

[0024] Traverse all constraint expressions except the last one in the path constraint set, add unvisited constraint expressions to the visited set, perform constraint solving after negating them, and cache the solution results in the dictionary.

[0025] Specifically, the test prediction set in S3 for the vulnerability of the permission control smart contract is as follows:

[0026] For permission control smart contract vulnerabilities caused by permission configuration errors and lack of permission authorization check control, the test prediction is set as: ErrorPermission∨(ExistDangerousI∧NoPCP).

[0027] The first sub-oracle ErrorPermission detects whether there is a permission configuration error in the smart contract. When the name of the non-standard constructor that sets the owner permission function of the smart contract is inconsistent with the name of the smart contract, ErrorPermission is judged to be true;

[0028] The second sub-oracle ExistDangerousI detects whether there is a lack of permission authorization check in the smart contract, that is, whether there is tainted data from unauthorized users propagated to the SELFDESTRUCT and DELEGATECALL instructions. If so, ExistDangerousI is judged to be true;

[0029] The third sub-prediction NoPCP detects whether there is a permission constraint mode, and if so, judges NoPCP to be false;

[0030] When ErrorPermission is true or ExistDangerousI and NoPCP are true at the same time, the test prediction is true, and there is a permission control smart contract vulnerability.

[0031] Furthermore, the authority constraint mode is determined to determine whether the following taint analysis process exists:

[0032] Use the marked tainted instructions SLOAD and CALLER to load the smart contract owner address and the smart contract caller address respectively, and compare the two addresses to determine whether they are equal.

[0033] If they are equal, the execution continues via the JUMPI operation of the taint sink instruction.

[0034] If they are not equal, the JUMPI operation jumps to REVERT to end the execution;

[0035] If the above taint analysis process exists, it is determined that a permission constraint mode exists.

[0036] Specifically, the test prediction set in S3 for the denial of service smart contract vulnerability is:

[0037] For the denial of service smart contract vulnerability caused by gas limit and external call failure, the test prediction is: ExistUnLoop∨(ExistCallException∧UnhandledPreTermination),

[0038] Among them, the sub-prophecy ExistUnLoop detects whether the smart contract contains an unbounded loop condition that can be determined by external input. If so, ExistUnLoop is true; the sub-prophecy ExistCallException detects whether the smart contract has an exception of an external call failure. If so, ExistCallException is true; the sub-prophecy UnhandledPreTermination detects whether the exception is handled before the smart contract terminates. If not, UnhandledPreTermination is true;

[0039] When ExistUnLoop is true or ExistCallException and UnhandledPreTermination are true at the same time, the test prediction is true, and there is a denial of service smart contract vulnerability.

[0040] Furthermore, whether the smart contract contains an unbounded loop condition that can be determined by external input is determined as follows:

[0041] Based on the external input taint, when it propagates to the JUMPI instruction and the ISZERO instruction, the ISZERO instruction takes the top element of the stack and performs a conditional judgment on it. If the judgment is true, it guides the JUMPI instruction to jump and judge whether the position of the JUMPI instruction jump is the same as the previous jump position.

[0042] If they are the same, the JUMPI instruction is determined to jump back to the loop body, and there is an unbounded loop condition that can be determined by external input.

[0043] Specifically, the test prophecy set in S3 for the transaction order dependency smart contract vulnerability is: set the test prophecy ExistConflictingTransactions. If there is a read-write conflict in the storage location of the same variable in the smart contract, and the same variable is modified by transactions from different senders, the test prophecy is true, and a transaction order dependency smart contract vulnerability exists.

[0044] In S2, the number of all instructions covered by each test case during instruction execution is obtained, and an instruction count set is constructed. Specifically, during the fuzz testing process, a program counter is set to point to the address of the currently executed instruction of the EVM bytecode, a program counter value is obtained, and an instruction count set is constructed based on the program counter value; the instruction execution path of each test case is traversed, and the program counter value of each executed instruction is updated to the instruction count set.

[0045] The present invention also provides a smart contract vulnerability detection system based on hybrid fuzzy testing optimization, comprising:

[0046] Static analysis module: used to obtain the source code of the smart contract, compile it to obtain EVM bytecode, perform static analysis on the EVM bytecode, and obtain the ABI interface parameter type and function call sequence based on the read and write dependencies between functions in the bytecode and the source code corresponding to the functions;

[0047] Fuzzy processing module: used to generate a first test case set based on the ABI interface parameter type and function call sequence, perform fuzz testing on the EVM bytecode based on the first test case set, obtain the number of all instructions covered by each test case during instruction execution, and construct an instruction count set; according to the length change of the instruction count set within the set execution number threshold, perform symbolic execution processing when the length change value is 0,

[0048] The symbolic execution processing operation specifically includes: setting the branch when the instruction count set length change value is 0 as the target branch point, obtaining only the arithmetic instructions and logical instructions of all branch constraints on each execution path when the instruction is executed to the target branch point, converting them into constraint expressions through symbolic processing, and collecting the constraint expressions to construct a path constraint set;

[0049] After negating the constraint expression, a constraint solving operation is performed. During the constraint solving, the constraint expression and its solution are cached and reused to obtain a specific input value that satisfies the branch constraint condition of the target branch point. The specific input value is updated as a new test case to the first test case set to obtain a second test case set. The fuzzy processing module is executed in a loop to expand the second test case set until a set time is reached, the loop is terminated, and the vulnerability detection module is executed.

[0050] Vulnerability detection module: used to set different test oracles for different smart contract vulnerabilities, including permission control, transaction sequence dependency, and denial of service smart contract vulnerabilities; based on the test oracles, the second test case set is used in combination with taint analysis to perform smart contract vulnerability detection and obtain vulnerability detection results.

[0051] The beneficial effects of the present invention are:

[0052] 1. The present invention statically analyzes the compiled EVM bytecode to generate a first test case set, performs fuzz testing, and introduces taint analysis to track the propagation of taints in the instruction stream. During the fuzz testing process, symbolic execution is triggered when the length change of the instruction count set within the execution count threshold is zero. By combining the advantages of fuzz testing and symbolic processing, when the fuzz test encounters difficult-to-cover branches, symbolic execution can be used to solve solutions that meet complex path conditions. This solution is fed back to the fuzz test as a new second test case set to help it explore deeper branches.

[0053] 2. During symbolic execution, this invention employs a constraint cache reuse strategy to solve acquired constraint expressions and cache and reuse the solution results, significantly reducing computational complexity. This enables symbolic execution to rapidly generate use case values ​​for complex branches and feeds these values ​​back to the fuzzing engine to help it explore new paths and capture more complex vulnerabilities.

[0054] 3. This paper combines the characteristics of three smart contract vulnerabilities, namely permission control, transaction order dependency, and denial of service, which are ignored by most fuzzers, and designs accurate test predictions. It specifically detects and determines permission control smart contract vulnerabilities caused by permission configuration errors and denial of service smart contract vulnerabilities caused by gas restrictions, which are not specifically considered by other fuzz tests. BRIEF DESCRIPTION OF THE DRAWINGS

[0055] In the attached figure:

[0056] Figure 1 This is a simplified code snippet of a real smart contract;

[0057] Figure 2 This is an example of a permission control smart contract vulnerability caused by a lack of authorization check;

[0058] Figure 3 A smart contract fragment with a denial of service smart contract vulnerability;

[0059] Figure 4 A smart contract fragment with a transaction order dependency smart contract vulnerability;

[0060] Figure 5 is the average real-time coverage for small contracts;

[0061] Figure 6 is the average real-time coverage for large-scale contracts. DETAILED DESCRIPTION

[0062] Exemplary embodiments of the present disclosure will be described in more detail below with reference to the accompanying drawings.

[0063] Example

[0064] This embodiment provides a smart contract vulnerability detection method based on hybrid fuzz testing optimization, see Figure 1 , including the following steps:

[0065] S1. Obtain the source code of the smart contract, compile it to obtain EVM bytecode, perform static analysis on the EVM bytecode, and obtain the ABI interface parameter type and function call sequence based on the read and write dependencies between functions in the bytecode and the source code corresponding to the functions.

[0066] Smart contracts written in high-level programming languages ​​must be compiled into bytecode before they can be run on the EVM. The EVM interprets bytecode in units of bytes, with each byte corresponding to an EVM instruction or an operation. In EVM bytecode, instructions manipulate data from the stack, memory, or storage. The stack and memory are temporary storage, while storage is persistent.

[0067] A smart contract is a self-executing program that must be compiled and deployed on the blockchain in bytecode format before it can be accessed. Once deployed, each contract is assigned a unique address, known as the contract address. This information is publicly available, allowing any user to interact with the contract by initiating transactions based on the contract's Application Binary Interface (ABI). The ABI is generated during the compilation process and defines the interface specifications for user interaction with the contract. When a user initiates a transaction to invoke a contract, the ABI first encodes the function information to be called (such as the function signature and corresponding parameters) into a format understandable by the EVM.

[0068] The actual execution of smart contracts occurs within the EVM. The blockchain stores the contract code but does not itself execute the contract. After a transaction is initiated by a user, it enters the transaction pool and awaits confirmation. Upon receiving a transaction request, the contract code is retrieved from the blockchain using the contract address. The function signature and parameters provided by the user in the transaction are then parsed to determine the function to be called, completing the contract execution. Finally, the execution results and status changes are packaged into a block and broadcast to the network. Once other nodes confirm the transaction's validity through consensus, the new status or results are permanently recorded on the blockchain.

[0069] Therefore, when detecting smart contract vulnerabilities, the source code of the smart contract is first compiled to obtain EVM bytecode, and the EVM bytecode is statically analyzed in a static analyzer. Based on the read and write dependencies between functions in the bytecode and the source code corresponding to the functions, the ABI interface parameter types and function call sequences are obtained.

[0070] S2. Generate a first test case set based on the ABI interface parameter type and function call sequence, perform fuzz testing on the EVM bytecode based on the first test case set, obtain the number of all instructions covered by each test case during instruction execution, and construct an instruction count set; perform symbolic execution processing when the length change of the instruction count set within a set execution number threshold is 0,

[0071] The symbolic execution processing operation specifically includes: setting the branch when the instruction count set length change value is 0 as the target branch point, obtaining only the arithmetic instructions and logical instructions of all branch constraints on each execution path when the instruction is executed to the target branch point, converting them into constraint expressions through symbolic processing, and collecting the constraint expressions to construct a path constraint set;

[0072] After negating the constraint expression, constraint solving is performed. In the constraint solving, the constraint expression and its solution result are cached and reused to obtain a specific input value that meets the branch constraint condition of the target branch point. The specific input value is updated as a new test case to the first test case set to obtain a second test case set. S2 is executed in a loop to expand the second test case set until the set time is reached, the loop is terminated, and S3 is executed.

[0073] The processing process is described in detail below. First, the first test case set is generated based on the ABI interface parameter type and function call sequence. After obtaining the ABI interface parameter type and function call sequence in step S1, the fuzzer generates a series of random test cases for the function to be called according to the ABI interface parameter type and enters the fuzz engine module to start fuzz testing the EVM bytecode. The contract execution analyzer records and tracks the actual execution of these test cases. It monitors the status of the fuzzer fuzz test and starts symbolic execution in appropriate scenarios to generate new test cases to assist in the execution of the fuzz test. The specific steps are described as follows:

[0074] The fuzzing engine first generates a series of test cases as initial seeds to fuzz the smart contract. During contract execution, code coverage and constraint-solving results from symbolic execution are used as feedback to select, crossover, and mutate the seeds to generate new inputs. Constructing the initial seed is a critical step in influencing fuzzing effectiveness, as a good seed can generate potential mutations to reach deeper paths and discover vulnerabilities.

[0075] When generating test cases for smart contracts, the fuzzing engine must consider two key aspects: transaction-compliant parameter types and valid transaction sequences. The smart contract Application Binary Interface (ABI) specification specifies how to construct the byte data sent as transaction data when calling smart contract functions. By statically analyzing the smart contract and extracting the number and types of parameters from its corresponding ABI interface, the fuzzing engine generates test cases that meet the transaction requirements, known as the first test case set, based on the different parameter types. For fixed-length parameters (e.g., uint256), random values ​​are generated based on the parameter type and the specified number of bytes or bits. For non-fixed-length parameters (e.g., string, uint32[]), the length of the generated data is first determined and then padded with random elements to simulate a variety of possible input conditions. Furthermore, high-quality test cases rely on valid transaction sequences. The state of a smart contract changes gradually through the execution of multiple transactions, and some vulnerabilities are often only triggered under specific contract states. By analyzing the smart contract bytecode and examining the read and write dependencies between functions, a set of transaction sequences is determined. This test case generation strategy, which complies with both transaction parameter types and transaction sequences, enables the fuzzing engine to more comprehensively test different states and paths of the contract, making it more likely to discover potential vulnerabilities.

[0076] After generating the first test case set, the EVM bytecode is fuzz tested based on the first test case set. During the fuzz testing process, the number of instructions covered by each test case is recorded to construct an instruction count set. Specifically, the smart contract runs in the EVM as bytecode. During the fuzz testing process, the program counter is set to point to the address of the currently executed instruction in the EVM bytecode. The program counter is a key register when executing instructions, and it points to the address of the currently executed instruction. By tracking the value of the program counter, it is possible to accurately understand which instructions the smart contract has executed, and then obtain the program counter value. The instruction count set is constructed based on the program counter value. The instruction execution path of each test case is traversed, and the program counter value of each executed instruction is updated to the instruction count set.

[0077] Furthermore, some vulnerabilities in smart contracts are often caused by complex logical errors, which are often hidden in deep paths within the code. When faced with strictly constrained branches, fuzz testing alone has an extremely low probability of reaching new paths through mutation, and this wastes a significant amount of testing resources. To achieve coverage of more complex branches, this paper proposes a hybrid fuzz testing method combined with symbolic execution. After fuzz testing covers shallow branches, this method uses symbolic execution to explore paths missed by fuzz testing and generate inputs that meet specific branch conditions.

[0078] In this step, fuzz testing is used to obtain the number of all instructions covered by each test case during instruction execution. An instruction count set is constructed based on the length change of the instruction count set within the set execution number threshold. Symbolic execution processing is performed when the length change value is 0.

[0079] A key issue is when to initiate the symbolic execution module. To mitigate the path explosion problem in branch symbolic execution, this paper dynamically monitors the contract code execution status. When code coverage reaches a bottleneck and cannot be significantly improved, the symbolic execution module is initiated. By limiting symbolic execution to exploring paths that are difficult for fuzz testing to reach, a balance is achieved between high coverage and solution difficulty.

[0080] Specifically, maintain a set C defined as an instruction count set to store the program counter values ​​of executed instructions. Traverse the execution traces of each test case and add the program counter value of each instruction to the instruction count set. By calculating the length of the instruction count set, it is determined whether the coverage of the contract by the test case has changed. If the length of the instruction count set does not change within the set execution count threshold, and the length change value is 0, it is considered that the program has encountered a complex branch during fuzz testing, causing the execution state to stagnate. At this time, it is necessary to start the symbolic execution engine to solve the specific branch conditions to update the test case. The switching between fuzz testing and symbolic execution is shown in Table 1.

[0081] Table 1 Switching algorithm between fuzz testing and symbolic execution

[0082]

[0083] The processing of symbolic execution is introduced in detail below. The symbolic execution processing operation in this embodiment is specifically as follows: the branch when the instruction count set length change value is 0 is set as the target branch point, only the arithmetic instructions and logical instructions of all branch constraints on each execution path when the instruction is executed to the target branch point are obtained, and they are symbolically processed and converted into constraint expressions, and the constraint expressions are collected to construct a path constraint set.

[0084] Symbolic execution uses the current fuzz test case input as the concrete value to perform both actual and symbolic execution on the smart contract, collecting symbolic path constraints during execution. When execution reaches the target branch point, the constraint is negated and the constraint solver is called to solve the constraint, looking for possible inputs that trigger this branch.

[0085] Constraint generation requires parsing the instructions and parameters of all branch constraints involved in each execution path. Traditional symbolic execution focuses on each execution instruction in a smart contract, jumping to the vulnerability detection module when encountering certain instructions to detect vulnerabilities. The main purpose of this invention is to use symbolic execution to generate a set of values ​​that satisfy complex branch conditions. Vulnerabilities are then detected through efficient fuzz testing. Specifically, a lightweight symbolic execution engine is used, focusing only on arithmetic instructions (such as ADD, SUB, MUL) and logical instructions (such as AND, OR, XOR, NOT) in branch constraints. The problem is converted into a set of constraint expressions. Functions such as BitVector() in the Z3 solver are then used to model EVM instructions. The arithmetic instructions in the branch constraints are symbolically processed and converted into constraint expressions. The path constraints are then solved in real time to determine whether the path is feasible. After the solution is completed, the symbolic values ​​are replaced with concrete values ​​and fed into the seed pool of the fuzz engine to update the test case.

[0086] During symbolic execution, constraint expressions are collected to construct a path constraint set, and these constraint expressions are added to the solver to determine whether they are satisfyable. Since different paths may share some of the same constraints, i.e., constraint expressions, similar or identical constraints may appear on different paths. In programs containing loops or arrays, the same path may be traversed multiple times. By caching and reusing the solution results of these paths, the amount of computation can be greatly reduced. Each constraint solving problem can be represented as a triple P=<V,D,C> , where: V is a set of variables, represented by { v 1 , v 2 ,…, v n}, the value of the test case is closely related to the values ​​of these variables; D is the set of variable value domains, that is, the value range of each variable. Specifically, each variable v i The value must be within its range d i The possible value range of each variable is D={d1,d2,…,d n}; C is a set of constraints. Each constraint is a logical expression about variables, defining the relationship between variables that needs to be satisfied. Each constraint c i ∈C contains one or more variables.

[0087] The constraint expression is further negated and then the constraint solution is performed. During the constraint solution, the constraint expression and its solution results are cached and reused to obtain the specific input value that satisfies the branch constraint conditions of the target branch point. The details are as follows:

[0088] During the symbolic execution process, a constraint set C={c1,c2,…,c n} That is the path constraint set mentioned above. Different paths may share some of the same constraint expressions c i If the constraint expression c i If a constraint has already been solved in a previous path, the system can check the cache to determine whether the previous solution can be reused. This can avoid repeated calculations of the same or similar constraints during the solution. Therefore, a constraint solution result reuse strategy is adopted during symbolic execution. Specifically, the constraint expression and its solution are cached and reused in the form of hash values.

[0089] The operation steps are as follows: build an visited set based on the visited constraint expressions, build a dictionary based on the solved constraint expressions and their solution results for caching, and obtain the corresponding unique hash value as the key based on each constraint expression after the inversion operation:

[0090] When solving a constraint expression, if the corresponding key exists in the dictionary, the solution in the dictionary is reused, otherwise the constraint solution is reset;

[0091] Traverse all constraint expressions except the last one in the path constraint set, add unvisited constraint expressions to the visited set, perform constraint solving after negating them, and cache the solution results in the dictionary.

[0092] The symbolic execution process using the constrained cache reuse strategy is shown in Table 2.

[0093] Table 2 Symbolic execution process using the constrained cache reuse strategy

[0094]

[0095] The corresponding processing procedure in Table 2 can be further described as follows: First, an empty set (visited_constraints) is initialized to store visited constraint expressions, and a dictionary (Ccache) is created to record solved constraint expressions and their solutions. Next, the negated constraint (negated_branch) of the current branch constraint expression is calculated, and a unique hash value (cache_key) is generated as the dictionary key. Next, the Ccache is checked to see if cache_key exists. If so, the solver state (solver) in the dictionary is reused. Otherwise, the solver is reset, and the constraint solution is reset. Next, all constraint expressions in the path constraint set except the last one are traversed. Each constraint is simplified and checked to see if it has been visited. If not, it is added to the visited set, negated, and then the constraint solution is performed. The solution result is cached in the dictionary. The solver is then called to solve the problem. If the solution is successful, the solution result is obtained, and the solver state in the dictionary is updated. Regardless of whether the new constraint solution uses the cached results, the final results will be stored in the dictionary for reuse in subsequent symbolic execution processes. Finally, a set of solution results (Result) is returned.

[0096] Specifically, the Z3 solver is used to perform symbolic execution and collect path constraints to solve the problem. Specific input values ​​can be generated for complex branches in the smart contract. The specific input values ​​are updated as new test cases to the first test case set to obtain the second test case set. The new second test case set is then fed back to the fuzz tester. In this way, the fuzz engine can break through the bottleneck of being limited to shallow branches and explore vulnerabilities in deep branches.

[0097] Fuzz testing can quickly generate a large number of unexpected test cases for the program under test to cover as many program paths as possible to discover vulnerabilities. However, some branches with strict conditions are difficult to cover using fuzz testing mutation strategies alone. Symbolic execution excels at solving branch paths that are difficult to explore through fuzz testing mutation due to the large search space. However, its constraint solving process takes a certain amount of time. Therefore, in this step, the advantages of both are combined. When fuzz testing encounters a branch that is difficult to cover, symbolic execution is used to solve a solution that can meet the complex path conditions and feedback it to fuzz testing as a new test case to help it explore deeper branches.

[0098] S3. Set different test oracles for different smart contract vulnerabilities, including permission control, transaction order dependency, and denial of service smart contract vulnerabilities; based on the test oracles, use the second test case set combined with taint analysis to perform smart contract vulnerability detection to obtain vulnerability detection results.

[0099] In this step, to determine whether an attacker can introduce malicious data to compromise smart contract security, taint analysis technology is also introduced during smart contract vulnerability detection to monitor the flow of data during contract execution. The core purpose of taint analysis is to track the flow of potentially malicious or untrusted data (i.e., "taints") within a program, a process directly driven by EVM instructions. Therefore, taint tracking is performed at the EVM instruction level. The core components of taint analysis include taint sources, taint propagation rules, and taint sinks, which respectively define the starting point, flow, and endpoint of data to be detected. The following describes the marking and configuration of taints, taint sinks, and taint propagation rules.

[0100] Taint marking: Some EVM instructions read data from the external environment or untrusted input. If this data contains malicious content, it is easy to cause security vulnerabilities in the contract. Obtain function call parameters and transaction data instructions in the EVM bytecode, including CALLDATALOAD, CALLDATACOPY, SLOAD, CALLER, ORIGIN, and CALLVALUE instructions, and mark the instructions and their return values ​​as tainted;

[0101] Therefore, EVM instructions that introduce user data are considered as taint sources, as shown in Table 3. These instructions are mainly related to reading contract function parameters and transaction-related data (such as the sender and the amount in the transaction).

[0102] Table 3 Instructions defined as taint sources

[0103]

[0104] Among them, the EVM instructions CALLDATALOAD and CALLDATACOPY read external parameters; the SLOAD instruction reads internal data from the storage of the smart contract and is also defined as a pollution source because this internal data may have been polluted by untrusted input; CALLER and ORIGIN return the address of the current contract caller and the address of the initial initiator of the current transaction respectively. Therefore, in order to prevent external untrusted callers from manipulating contracts and using unreliable authentication mechanisms, these instructions and their return values ​​are marked as tainted.

[0105] For the marking of taint sinks: set CALL, SSTORE, JUMPI, ISZERO, SELFDESTRUCT and DELEGATECALL instructions to taint sinks;

[0106] If key operations such as transfer, storage, or jump are affected by tainted data, this indicates that an attacker may be able to manipulate the execution of the contract by constructing malicious data, thereby changing its state and damaging the contract. Logical instructions such as ISZERO are used to process conditional judgments, and they will have a direct impact on the execution path of the loop; and conditional jump instructions such as JUMPI, based on the results of the logical instructions, decide whether to continue executing the loop. In this embodiment, the CALL, SSTORE, JUMPI, and ISZERO instructions are set as tainted sinks. In addition, if the instructions SELFDESTRUCT and DELEGATECALL are manipulated by unauthorized users, they may have extremely adverse effects on the contract. For example, an attacker can control the SELFDESTRUCT instruction and pass his own account address as a parameter; the DELEGATECALL instruction may call a harmful contract maliciously designed by the attacker, so the SELFDESTRUCT and DELEGATECALL instructions are also defined as tainted sinks. The detailed description of these instructions is shown in Table 4.

[0107] Table 4

[0108]

[0109] Setting of taint propagation rules: Based on the set taint propagation rules, the EVM bytecode is tainted and analyzed to obtain the propagation of tainted data in the instruction stream. When different instructions are executed, the taint propagation is tracked based on the taint propagation rules. Specifically:

[0110] Rule 1: For unary or multi-ary arithmetic instructions or logical instructions, if any operand contains taint, the result value obtained after executing the instruction will be marked as tainted.

[0111] Assume that instruction I has n operands, expressed as t(v) = I( op 1 , op 2 ,…… op n ), the taint status of each operand can be expressed as follows:

[0112] ,

[0113] in, Indicates the i operands, =1 means the operand is marked as tainted, =0 means that the operand is not marked as tainted.

[0114] Rule 2: Instructions that query the blockchain status and do not affect the contract execution and status are marked as fixed instructions that are not considered tainted.

[0115] For instructions that query the blockchain status (such as TIMESTAMP) and those that do not affect the contract execution and contract status (such as LOGn instructions), these instructions will not cause taint propagation in the taint propagation analysis. LOGn instructions are used to generate event logs. Although these data will be permanently stored on the blockchain, they do not affect the execution of the contract and these log data cannot be directly accessed within the contract. Therefore, instructions with similar functions are recorded as These instructions do not cause taint propagation, which helps reduce the complexity of taint propagation and the degree of over-pollution.

[0116] Rule 3: For instructions that read data from memory or storage, if the instruction contains taint, the result value read is marked as tainted.

[0117] For example, = MLOAD( m i ) indicates that the MLOAD instruction loads the data from the memory address Read data at Indicates the taint state of the memory address. If the memory address The data is tainted, then the result is also marked as 1. Similarly, the SLOAD instruction that reads data from storage also follows this rule, using Indicates storage address The stain state.

[0118] Based on the propagation of taints to taint sinks, the propagation path of taints in the instruction stream of EVM bytecode is obtained, and a security report is generated based on the propagation path to obtain the vulnerability detection results.

[0119] Taking into account the complex memory management of EVM, this embodiment specifically adopts a key-value pair data structure to realize the propagation of taints between the stack, memory, and storage. The key of each key-value pair represents the location of the taint, and the value contains the input parameter set that triggers the taint. For the convenience of description, three key-value pairs are used and named t_InStack, t_InMemory, and t_InStorage respectively. EVM uses the stack to store temporary calculation data and instruction operands. t_InStack is used to record whether the data at each stack location is tainted. If subsequent operations use the data at this location, the result will also be marked as tainted and recorded through the key-value pair structure. Similarly, t_InMemory and t_InStorage are used to record whether the data at each location in the memory and storage is tainted, respectively.

[0120] For example, the MSTORE instruction indicates that a value is stored from the stack to memory. When the MSTORE instruction is executed, the taint engine first pops the taint corresponding to the stack value from the key-value pair t_InStack. It then associates this taint with the memory address corresponding to the value and stores it in the corresponding location in the key-value pair t_InMemory. In this way, the data at the corresponding address in memory is assigned the same taint tag, achieving the transfer of the taint from the stack to memory.

[0121] Table 5 lists the three main taint propagation rules improved in this embodiment.

[0122] Table 5 Taint propagation rules

[0123]

[0124] In this paper, we also designed three different test oracles for three different smart contract vulnerabilities: permission control, transaction order dependency, and denial of service. Based on these test oracles, we used a second test case set combined with taint analysis to detect smart contract vulnerabilities and obtain vulnerability detection results. A detailed description of the designed test oracles is as follows:

[0125] Test oracles are used in smart contract fuzz testing to identify vulnerabilities in contracts. Currently, research using fuzz testing to detect vulnerabilities in permission control smart contracts, denial of service smart contracts, and transaction order dependency smart contracts is incomplete. Therefore, in this example, we develop three test oracles tailored to the characteristics of these three vulnerabilities and provide detailed descriptions.

[0126] Regarding permission-controlled smart contract vulnerabilities, permission control is an effective permission strategy that prevents unauthorized users from manipulating contract assets. Smart contracts typically use various permission constraints to limit the caller's address or attributes. If permission constraints are incorrectly configured or key operations lack permission control, this can lead to permission-controlled smart contract vulnerabilities (ACs), resulting in loss of contract assets. Generally, permission-controlled smart contract vulnerabilities fall into two categories: incorrect permission configuration and missing authorization checks.

[0127] For cases where permission configuration errors lead to permission control smart contract vulnerabilities, such as Figure 1 The following code snippet is a simplified representation of a real smart contract. In this code snippet, the state variable owner in line 2 stores the address of the contract owner. frozenAccount in line 3 uses a mapping to store a frozen account that cannot perform certain operations. The onlyOwner modifier is used to check whether the contract caller is the owner. The onlyOwner modifier is used to protect the freezeAccount() function. The UBSecToken() function initializes the contract owner and several other variables. This function performs the functions of a constructor in this contract. In Solidity, each contract can only define one constructor. This function is automatically run once when the contract is deployed to initialize parameters, including the owner's address. The developer made a significant mistake here, naming the constructor UBSecToken instead of the contract name BAFCToken. This makes the special-purpose constructor a normal function callable by anyone. This means that anyone can become the contract owner by calling UBSecToken() and perform operations beyond their normal permissions. Although freezeAccount() in line 11 uses the onlyOwner modifier for permission checking, an attacker can hijack the contract ownership before this happens and freeze any account in the contract. A vulnerability caused by a misconfigured permissions configuration where anyone can equip themselves with the elevated permissions of a contract owner.

[0128] For cases where the lack of authorization checks leads to vulnerabilities in permission control smart contracts, such as Figure 2 As shown in the figure, the statement "selfdestruct(msg.sender)" involves a special and dangerous instruction, SELFDESTRUCT, known as the self-destruct instruction. Once executed, this instruction removes the contract from the blockchain and sends all assets in the contract balance to the address provided as the instruction parameter (msg.sender). Therefore, only authorized users (such as the contract owner) should be allowed to call the removeContract() function. Furthermore, unauthorized users cannot arbitrarily set the parameters of the self-destruct instruction.

[0129] The test prediction for the vulnerability of the permission control smart contract is as follows:

[0130] For permission control smart contract vulnerabilities caused by permission configuration errors and lack of permission authorization check control, the test prediction is set as: ErrorPermission∨(ExistDangerousI∧NoPCP).

[0131] The first sub-oracle ErrorPermission detects whether there is a permission configuration error in the smart contract. When the name of the non-standard constructor that sets the owner permission function of the smart contract is inconsistent with the name of the smart contract, ErrorPermission is judged to be true;

[0132] The second sub-oracle ExistDangerousI detects whether there is a lack of permission authorization check in the smart contract, that is, whether there is tainted data from unauthorized users propagated to the SELFDESTRUCT and DELEGATECALL instructions. If so, ExistDangerousI is judged to be true;

[0133] The third sub-prediction NoPCP detects whether there is a permission constraint mode, and if so, judges NoPCP to be false;

[0134] When ErrorPermission is true or ExistDangerousI and NoPCP are both true, the test prediction is true, indicating that there is a permission control smart contract vulnerability.

[0135] The third sub-oracle determines the permission constraint mode. It uses taint analysis to determine whether the contract execution process is protected by the permission constraint mode. Specifically, it determines whether the following taint analysis process exists:

[0136] Use the marked tainted instructions SLOAD and CALLER to load the smart contract owner address and the smart contract caller address respectively, and compare the two addresses through the EQ operation to determine whether they are equal. If they are equal, the tainted sink instruction JUMPI operation is used to continue execution; if they are not equal, the JUMPI operation jumps to REVERT to end execution;

[0137] If the above taint analysis process exists, it is determined that a permission constraint mode exists.

[0138] Not all dangerous instructions can be exploited by attackers to cause damage to the contract. In the source code of smart contracts, developers often use permission constraint patterns to control the accessibility of functions containing dangerous instructions. require (msg.sender == owner) is the most common permission constraint pattern. The require statement is used to check a condition and throw an exception if the check fails. In this permission constraint pattern, msg.sender is the smart contract caller, and owner is the smart contract owner address. In other words, only when the caller is the owner of the smart contract can it pass the permission check. This is an effective protection measure to prevent vulnerabilities in permission-controlled smart contracts, as shown below:

[0139] require(msg.sender==owner),

[0140] During fuzz testing, by analyzing the flow of tainted data, we can identify whether the permission check logic relies on unvalidated inputs (msg.sender) and whether these inputs affect key decision points of the contract (such as JUMPI).

[0141] Denial of Service (DOS) vulnerabilities in smart contracts can occur in a variety of ways, such as when a smart contract is executed and unexpected circumstances occur that prevent the contract program from running properly, leading to transaction failures. Figure 3 Shows a code snippet of a smart contract deployed on the blockchain.

[0142] Figure 3This is a smart contract snippet. It sets a prize pool, jackpot, for each game. Users can participate by purchasing tickets and guessing the price. At the end of the game, the winner is selected based on the amount of money spent using the pickTheWinner() function. Users can participate by calling the buyTicket function on line 8. The buyTicket function stores each participant's address (player) and amount (betPrice) in the mapping order. After deducting 20% ​​of the user's amount as a participation fee, it adds the remaining amount to the prize pool, jackpot[game], for the current game. The contract owner can call the start() function to specify the winning price (winPrice). If the number of participants in the current game is not null (order[game].length>0), the pickTheWinner() function on line 18 is called, which distributes the entire prize pool equally to each winner, i.e., the participant whose amount matches the winPrice specified by the contract owner. However, this function contains two different denial-of-service smart contract vulnerabilities: gas limit and external call failure.

[0143] Furthermore, for the first type of denial of service smart contract vulnerability caused by Gas limitation, Figure 3 The pickTheWinner() function in the contract distributes the prize from the jackpot using a for loop terminated by orders[game].length. It's important to note that orders is a dynamic mapping determined by external input. When a large number of players participate in the game, the gas cost of executing the loop will exceed the block limit, causing the loop to fail and no winner will receive their prize. Furthermore, the amount in the jackpot will be permanently frozen because there are no other functions in the contract that can transfer funds.

[0144] For the second type of denial of service smart contract vulnerability caused by external call failure, Figure 3 The function pickTheWinner() in the contract also involves an external call, using transfer() to transfer funds to the winner. If one of the winners wants to launch a DoS attack on this contract, they can add the revert() function to the fallback() function of their attacking contract, deliberately causing the call to fail. The other winners will then not receive their prizes, and the attacker will also achieve their goal of freezing all prizes and halting normal contract operation. If an external call exception occurs during contract execution and is not properly handled before execution terminates, it can lead to a denial of service smart contract vulnerability.

[0145] Therefore, for the denial of service smart contract vulnerability caused by gas limit and external call failure, the test prediction is set as: ExistUnLoop∨(ExistCallException∧UnhandledPreTermination).

[0146] Among them, the sub-prophecy ExistUnLoop detects whether the smart contract contains an unbounded loop condition that can be determined by external input. If so, ExistUnLoop is true; the sub-prophecy ExistCallException detects whether the smart contract has an exception of an external call failure. If so, ExistCallException is true; the sub-prophecy UnhandledPreTermination detects whether the exception is handled before the smart contract terminates. If not, UnhandledPreTermination is true;

[0147] When ExistUnLoop is true or ExistCallException and UnhandledPreTermination are both true, the test prediction is true, indicating a denial of service smart contract vulnerability.

[0148] In the specific denial of service smart contract vulnerability detection, the execution of the CALL instruction of the external call is first triggered. The result returned by the call is pushed to the stack. Then, combined with taint analysis, the valid exception results are recorded, and the prediction ExistCallException is triggered. During contract execution, the exception is tracked to see whether each failed external call flows into the JUMPI instruction to determine whether the exception has been handled. If the jump condition is true, the corresponding exception is removed from the record, proving that these exceptions have been handled during execution. When executing the termination instruction (such as REVERT, RETURN, STOP, SUICIDE, SELFDESTRUCT), CSOptiHyFuzz checks whether the exception record is empty. If there are still unhandled exceptions in the record, it means that the exception was not handled before termination, and the UnhandledPreTermination sub-prediction is triggered.

[0149] In the sub-oracle ExistUnLoop, it is necessary to determine whether the smart contract contains unbounded loop conditions that can be determined by external input. When the bounds of loop iterations are determined by user input, this can lead to denial-of-service smart contract vulnerabilities caused by gas limits. In smart contracts, when developers use function parameters to pass user input values, they generally impose reasonable limits to prevent excessive loop iterations. Therefore, user input passed directly as function parameters is generally not a direct source of vulnerabilities. However, special attention should be paid to loop conditions constructed by external users using dynamic data structures such as arrays and maps. These structures grow over time and through user interaction and can be manipulated by contract users. An attacker could use them to construct unbounded loops and exhaust the contract's gas, preventing the contract from continuing to execute or processing other important operations.

[0150] Although fuzz testing will report transaction termination when the specified gas limit is exceeded during contract execution, this often requires a large amount of resources to achieve this termination condition. If testing resources are limited, this will result in a certain degree of underreporting. Therefore, when fuzzing contracts with test cases, we also use taint analysis to determine whether there are unbounded loops in the contract code. The specific process is as follows:

[0151] Based on the external input taint, when it propagates to the JUMPI instruction and the ISZERO instruction, the ISZERO instruction takes the top element of the stack and performs a conditional judgment on it. If the judgment is true, it guides the JUMPI instruction to jump and judge whether the position of the JUMPI instruction jump is the same as the previous jump position.

[0152] If they are the same, the JUMPI instruction is determined to jump back to the loop body, and there is an unbounded loop condition that can be determined by external input.

[0153] Taint analysis is used to track whether the data introduced by the pollution source reaches the loop condition. If an external user can change the execution result of the ISZERO instruction through the pollution source (such as user input), it is possible to change the number of executions of the loop.

[0154] Regarding the transaction order dependency (TOD) vulnerability, this occurs when the behavior of a smart contract depends on the order in which transactions are executed. This dependency can be exploited maliciously to create unfair trading outcomes. Transactions initiated by users are not immediately executed but wait for inclusion in a block. Typically, transactions offering higher gas fees are prioritized, giving attackers the opportunity to disrupt the normal order of transactions. Figure 4A contract snippet with a TOD vulnerability is shown. This contract implements the buying and selling of goods. Specifically, if there is sufficient inventory, the user calls the buy() function to purchase a certain quantity of goods and pays the seller the corresponding amount (price*amount). However, if, before this transaction is confirmed, the contract owner (owner) initiates a transaction as the seller with a higher gas price and raises the price (price) using setPrice(), the user will pay a higher amount based on the new price (_newPrice).

[0155] To detect a contract's TOD vulnerability, we need to determine whether a function can modify a global variable that affects the contract's state, and whether the function's output depends on the order of transactions. To address this, we designed a test oracle, ExistConflictingTransactions, which performs two checks: first, checking for read-write conflicts at the storage location of the same variable, and second, checking whether the variable has been modified by exchanges with different senders. If a read-write conflict exists at the storage location of the same variable in the smart contract, or if the variable has been modified by exchanges with different senders, the test oracle evaluates to true, indicating a transaction-order-dependent smart contract vulnerability.

[0156] During the execution of the test case, check whether the current instruction is SSTORE, which performs a storage operation on the variables in the function. If the data stored is tainted data, record its storage location. When it is detected that the instruction is an SLOAD instruction that reads the variable, record the location of the data it reads and determine whether this location is the same as the location previously written by SSTORE, that is, determine if the data read by the SLOAD operation depends on the previous SSTORE operation. If the current instruction is CALL, further confirm whether the external call has modified the previously recorded storage location, and verify whether the transaction initiator of the modification is consistent. If the external transaction involved in the CALL instruction affects the storage location of the previously recorded SSTORE operation, this may indicate that changes in the transaction order can cause the storage variable to be modified by different transactions.

[0157] The present invention also provides a smart contract vulnerability detection system based on hybrid fuzzy testing optimization, comprising:

[0158] Static analysis module: used to obtain the source code of the smart contract, compile it to obtain EVM bytecode, perform static analysis on the EVM bytecode, and obtain the ABI interface parameter type and function call sequence based on the read and write dependencies between functions in the bytecode and the source code corresponding to the functions;

[0159] Fuzzy processing module: used to generate a first test case set based on the ABI interface parameter type and function call sequence, perform fuzz testing on the EVM bytecode based on the first test case set, obtain the number of all instructions covered by each test case during instruction execution, and construct an instruction count set; according to the length change of the instruction count set within the set execution number threshold, perform symbolic execution processing when the length change value is 0,

[0160] The symbolic execution processing operation specifically includes: setting the branch when the instruction count set length change value is 0 as the target branch point, obtaining only the arithmetic instructions and logical instructions of all branch constraints on each execution path when the instruction is executed to the target branch point, converting them into constraint expressions through symbolic processing, and collecting the constraint expressions to construct a path constraint set;

[0161] After negating the constraint expression, a constraint solving operation is performed. During the constraint solving, the constraint expression and its solution are cached and reused to obtain a specific input value that satisfies the branch constraint condition of the target branch point. The specific input value is updated as a new test case to the first test case set to obtain a second test case set. The fuzzy processing module is executed in a loop to expand the second test case set until a set time is reached, the loop is terminated, and the vulnerability detection module is executed.

[0162] Vulnerability detection module: used to set different test oracles for different smart contract vulnerabilities, including permission control, transaction sequence dependency, and denial of service smart contract vulnerabilities; based on the test oracles, the second test case set is used in combination with taint analysis to perform smart contract vulnerability detection and obtain vulnerability detection results.

[0163] Experimental content

[0164] In the experimental part, two aspects need to be focused on. One is whether the smart contract vulnerability detection method based on hybrid fuzz testing optimization proposed in this invention can achieve higher code coverage compared with existing methods; the other is whether the smart contract vulnerability detection method based on hybrid fuzz testing optimization used in this invention can more effectively detect permission control smart contract vulnerabilities, denial of service smart contract vulnerabilities and transaction order dependency smart contract vulnerabilities in smart contracts compared with other vulnerability detection methods.

[0165] The present invention was compared with the various vulnerability detection methods listed in Table 6. All of the methods listed in Table 6 use symbolic execution or fuzz testing techniques to detect vulnerabilities and are publicly available on GitHub. For symbolic execution-based vulnerability detection methods, Oyente and Mythril were selected for comparison. Oyente was the first method used for smart contract vulnerability detection and has been highly recognized as a groundbreaking work in the smart contract security field. Mythril differs from Oyente in that it uses dynamic symbolic execution to simulate the real-world execution of smart contracts. Furthermore, as an open-source community technology, Mythril has been continuously updated in recent years. For fuzz testing, sFuzz, a recently developed method, was selected. It uses a distance-based seed selection strategy to generate a large number of test cases and dynamically fuzz contracts to identify security vulnerabilities. The code coverage and effectiveness of the present invention and these methods were compared under the same configuration environment. The specific comparison methods involved in the experiment are shown in Table 6.

[0166] Table 6 Different vulnerability detection methods and the types of vulnerabilities they can detect

[0167]

[0168] In the experiment, two datasets of different sizes were used to evaluate the effectiveness of the smart contract vulnerability detection method optimized by hybrid fuzz testing in this embodiment. The primary objective of Dataset 1 was to test its performance in terms of contract code coverage. 1,000 smart contracts were selected from publicly available datasets. These were all real-world smart contracts from Etherscan, with source code available. To verify whether symbolic execution could assist fuzz testing in achieving higher code coverage when faced with complex branching, the number of EVM instructions per smart contract was calculated. The 1,000 smart contracts were then divided into small-scale and large-scale contracts based on the number of instructions. Table 7 shows the number of source code lines and instructions for all smart contracts in Dataset 1. Of these, 628 were small-scale contracts with fewer than 3,000 instructions, while 372 were large-scale contracts with more than 3,000 instructions. Generally speaking, contracts with more instructions involve more complex code branches and execution logic.

[0169] Table 7. Source code lines and instructions of all smart contracts in Dataset 1

[0170]

[0171] Dataset 2 aims to test the effectiveness of detecting access control vulnerabilities (AC), denial of service vulnerabilities (DoS), and transaction order dependency vulnerabilities (TOD) in smart contracts. The official Smartbugs dataset contains relatively few contracts labeled for these three vulnerabilities, making detection performance ineffective. Therefore, contracts obtained from the Etherscan website were added and manually labeled. The resulting expanded Dataset 2 contains a total of 129 contracts.

[0172] By comparing the detection results of various methods, we can measure whether there are security issues in smart contracts. Specifically, in the experiment, all problematic contracts were labeled as either true positives (TP) or false positives (FP). TP indicates a correct detection of a vulnerability in the contract, while FP indicates an incorrect detection of a smart contract vulnerability—that is, a tool reports an incorrect detection result even though the contract itself does not have a vulnerability. Furthermore, the number of false negatives (FN) was counted. FN indicates that the tool failed to detect a real vulnerability in the contract, i.e., a false negative. Based on the three statistical values ​​of TP, FP, and FN, each tool's false positive rate (FPR), false negative rate (FNR), and precision, recall, and F1-score were calculated to assess detection performance. Precision can be calculated as:

[0173] ,

[0174] ,

[0175] ,

[0176] ,

[0177] ,

[0178] in, n Represents the number of contracts.

[0179] Code coverage is an important evaluation metric in the field of fuzz testing. In the experiment, the real-time code coverage obtained in this example was compared with that of sFuzz, with a runtime of 60 seconds for both. The average code coverage of each contract was calculated over time. Figure 5 and Figure 6The real-time code coverage of the two methods for small-scale contracts and large-scale contracts is shown.

[0180] The method used in the present invention achieved the highest code coverage of 89% and 82% for small-scale and large-scale contracts, respectively. The coverage of sFuzz for all contracts was below 30%. It was also found that sFuzz converged too early. In a small-scale contract set, the coverage trend remained basically flat after 20 seconds. The smart contract vulnerability detection method based on hybrid fuzz testing optimization achieved a new breakthrough in coverage after 25 seconds. Analyzing the working principle behind it, it is speculated that this is because sFuzz adopts a seed selection strategy based on branch distance. The test case may gradually shorten the distance to certain branches, but it may not be able to capture the complex path to the global optimal solution, thus falling into the local optimal solution, resulting in the inability to further optimize. Differently, the smart contract vulnerability detection method based on hybrid fuzz testing optimization uses symbolic execution technology to generate new test cases by solving constraint expressions. It is not limited to the "evolution" of existing test cases, thereby avoiding falling into the local optimal solution under complex conditions. However, because it involves constraint solving, it takes more time to achieve higher code coverage.

[0181] To investigate whether hybrid fuzz testing-optimized smart contract vulnerability detection methods can more effectively detect permission control smart contract vulnerabilities, denial of service smart contract vulnerabilities, and transaction order-dependent smart contract vulnerabilities in smart contracts, we calculated the TP, FP, and FN for each vulnerability type based on the detection results reported by each method on Dataset 2. Furthermore, we calculated the FDR, FNR, precision, recall, and F1 score for each vulnerability type. The results are shown in Table 8. As can be seen from the table, compared with other methods, the hybrid fuzz testing-optimized smart contract vulnerability detection method correctly detected the most vulnerabilities and had the fewest false positives and false negatives. For example, for the denial of service smart contract vulnerability (DoS), its precision was 95.8%, a 20.8% improvement over Mythril. It is also noted that for the permission control smart contract vulnerability (AC), while sFuzz, which uses dynamic fuzzing, achieved zero false positives, its false negative rate was as high as 78.5%, detecting only one dangerous scenario: unauthorized delegate calls.

[0182] Table 8 Comparison of evaluation indicators of different vulnerability detection methods

[0183]

[0184] Compared to other detection methods, this invention can more effectively detect smart contract vulnerabilities. Analysis shows that this method achieves better detection results due to the following two factors: First, it combines symbolic execution with hybrid fuzz testing to improve code coverage, thereby catching more vulnerabilities. Second, it designs a more optimized test oracle and introduces taint analysis technology to reduce false positives.

[0185] In summary, this paper proposes a smart contract vulnerability detection method and system based on hybrid fuzz testing optimization to detect permission control vulnerabilities, denial of service vulnerabilities, and transaction sequence dependency vulnerabilities in smart contracts. First, static analysis of the smart contract is performed to obtain the ABI interface parameter types and transaction sequence to generate test cases for initiating fuzz testing. Taint analysis techniques are also used to track the propagation of data in the instruction stream. Changes in contract code coverage are monitored during the fuzzing process. When coverage stabilizes, dynamic symbolic execution is performed using the current test case as input. Constraints are then solved using a constraint cache reuse strategy, enabling symbolic execution to quickly generate test case values ​​that reach complex branches. These values ​​are then fed back to the fuzz engine to assist in exploring new paths. Finally, test oracles for permission control, transaction sequence dependency, and denial of service vulnerabilities are defined, and detailed vulnerability reports are generated by analyzing contract execution logs and taint records. Experiments are conducted on a dataset of over 1,000 real-world smart contracts to evaluate the vulnerability detection performance. Experimental results show that compared with other tools, the method used in this invention can detect more vulnerabilities and has a more accurate detection effect; at the same time, the average code coverage is as high as 85%, which is about three times that of the more advanced tool sFuzz.

Claims

1. A smart contract vulnerability detection method based on hybrid fuzz testing optimization, characterized in that: The following steps are involved: S1. Obtain the source code of the smart contract, compile it to obtain EVM bytecode, perform static analysis on the EVM bytecode, and obtain the ABI interface parameter type and function call sequence based on the read and write dependencies between functions in the bytecode and the source code corresponding to the functions; S2. Generate a first test case set based on the ABI interface parameter type and function call sequence, perform fuzz testing on the EVM bytecode based on the first test case set, obtain the number of all instructions covered by each test case during instruction execution, and construct an instruction count set; perform symbolic execution processing when the length change of the instruction count set within a set execution number threshold is 0, The symbolic execution processing operation specifically includes: setting the branch when the instruction count set length change value is 0 as the target branch point, obtaining only the arithmetic instructions and logical instructions of all branch constraints on each execution path when the instruction is executed to the target branch point, converting them into constraint expressions through symbolic processing, and collecting the constraint expressions to construct a path constraint set; Perform constraint solving after negating the constraint expression, cache and reuse the constraint expression and its solution results in the constraint solving process, obtain a specific input value that satisfies the branch constraint condition of the target branch point, update the specific input value into the first test case set as a new test case, obtain a second test case set, execute S2 in a loop, expand the second test case set, and terminate the loop until a set time is reached, then execute S3; S3. Setting different test oracles for different smart contract vulnerabilities, including permission control, transaction order dependency, and denial of service smart contract vulnerabilities; Based on the test oracle, the second test case set is used in combination with taint analysis to detect smart contract vulnerabilities and obtain vulnerability detection results.

2. The smart contract vulnerability detection method based on hybrid fuzz testing optimization according to claim 1 is characterized in that: The taint analysis in S3 is specifically to perform taint analysis on the EVM bytecode based on the set taint propagation rules to obtain the propagation of taint data in the instruction stream, specifically: Obtain function call parameters and transaction data instructions in the EVM bytecode, including CALLDATALOAD, CALLDATACOPY, SLOAD, CALLER, ORIGIN, and CALLVALUE instructions, and mark the instructions and their return values ​​as tainted; Set CALL, SSTORE, JUMPI, ISZERO, SELFDESTRUCT, and DELEGATECALL instructions as taint sinks; When different instructions are executed, the taint propagation is tracked based on the taint propagation rules, specifically: For unary or multi-ary arithmetic instructions and logical instructions, if any operand contains taint, the result value obtained after executing the instruction will be marked as tainted. For instructions that query the blockchain status and instructions that do not affect the execution and status of the contract, they are marked as fixed instructions that are not considered tainted. For instructions that read data from memory or storage, if the instruction contains taint, the result value read is marked as tainted; Based on the propagation of taints to taint sinks, the propagation path of taints in the instruction stream of EVM bytecode is obtained, and the vulnerability detection results are obtained based on the propagation path.

3. The smart contract vulnerability detection method based on hybrid fuzz testing optimization according to claim 1 is characterized in that: In S2, the constraint expressions and their solution results are cached and reused during constraint solving. The specific operations are as follows: a visited set is constructed based on the visited constraint expressions, a dictionary is constructed based on the constraint expressions that have been solved and their solution results for caching, and the corresponding unique hash value of each constraint expression after the inversion operation is obtained as the key: When solving a constraint expression, if the corresponding key exists in the dictionary, the solution in the dictionary is reused, otherwise the constraint solution is reset; Traverse all constraint expressions except the last one in the path constraint set, add unvisited constraint expressions to the visited set, perform constraint solving after negating them, and cache the solution results in the dictionary.

4. The smart contract vulnerability detection method based on hybrid fuzz testing optimization according to claim 1 is characterized in that: The test prediction set in S3 for the vulnerability of the permission control smart contract is as follows: For permission control smart contract vulnerabilities caused by incorrect permission configuration and lack of permission authorization check control, the test oracle set is: ErrorPermission ∨( ExistDangerousI ∧ NoPCP ), The first of these prophecies ErrorPermission Detect whether there is a permission configuration error in the smart contract. When the name of the non-standard constructor that sets the permission function of the smart contract owner is inconsistent with the name of the smart contract, judge ErrorPermission is true; The Second Sub-Prophecy ExistDangerousI Detect whether there is a lack of permission authorization check in the smart contract, that is, whether there is tainted data from unauthorized users propagated to the SELFDESTRUCT and DELEGATECALL instructions. If so, judge ExistDangerousI is true; The Third Son Prophecy NoPCP Check whether there is a permission constraint mode, if so, judge NoPCP is false; when ErrorPermission True or ExistDangerousI 、 NoPCP When both are true, the test prediction is true, and there is a vulnerability in the permission control smart contract.

5. The smart contract vulnerability detection method based on hybrid fuzz testing optimization according to claim 4 is characterized in that: The permission constraint mode is determined to determine whether the following taint analysis process exists: Use the marked tainted instructions SLOAD and CALLER to load the smart contract owner address and the smart contract caller address respectively, and compare the two addresses to determine whether they are equal. If they are equal, the execution continues via the JUMPI operation of the taint sink instruction. If they are not equal, the JUMPI operation jumps to REVERT to end the execution; If the above taint analysis process exists, it is determined that a permission constraint mode exists.

6. The smart contract vulnerability detection method based on hybrid fuzz testing optimization according to claim 1 is characterized in that: The test oracle set in S3 for the denial of service smart contract vulnerability is: For the denial of service smart contract vulnerabilities caused by gas limit and external call failure, the test oracle is set as follows: ExistUnLoop ∨( ExistCallException ∧ UnhandledPreTermination ), The neutron prophecy ExistUnLoop Check if the smart contract contains an unbounded loop condition that can be determined by external input. If so, ExistUnLoop True; prophecy ExistCallException Check whether the smart contract has an exception of external call failure. If so, ExistCallException True; prophecy UnhandledPreTermination Check whether the exception is handled before the smart contract terminates. If not, UnhandledPreTermination is true; when ExistUnLoop True or ExistCallException 、 UnhandledPreTermination When both are true, the test oracle is true and there is a denial of service smart contract vulnerability.

7. The smart contract vulnerability detection method based on hybrid fuzz testing optimization according to claim 6 is characterized in that: Whether the smart contract contains an unbounded loop condition that can be determined by external input is determined as follows: Based on the external input taint, when it propagates to the JUMPI instruction and the ISZERO instruction, the ISZERO instruction takes the top element of the stack and performs a conditional judgment on it. If the judgment is true, it guides the JUMPI instruction to jump and judge whether the position of the JUMPI instruction jump is the same as the previous jump position. If they are the same, the JUMPI instruction is determined to jump back to the loop body, and there is an unbounded loop condition that can be determined by external input.

8. The smart contract vulnerability detection method based on hybrid fuzz testing optimization according to claim 1 is characterized in that: The test oracle set in S3 for the transaction sequence dependency smart contract vulnerability is as follows: ExistConflictingTransactions ,If there is a read-write conflict in the storage location of the same variable in the smart contract, the same variable is modified by transactions from different senders, and the test prediction is true, there is a transaction order-dependent smart contract vulnerability.

9. The smart contract vulnerability detection method based on hybrid fuzz testing optimization according to claim 1 is characterized in that: In S2, the number of all instructions covered by each test case during instruction execution is obtained, and an instruction count set is constructed. Specifically, during the fuzz testing process, a program counter is set to point to the address of the currently executed instruction of the EVM bytecode, a program counter value is obtained, and an instruction count set is constructed based on the program counter value; the instruction execution path of each test case is traversed, and the program counter value of each executed instruction is updated to the instruction count set.

10. A smart contract vulnerability detection system based on hybrid fuzz testing optimization, characterized in that: include: Static analysis module: used to obtain the source code of the smart contract, compile it to obtain EVM bytecode, perform static analysis on the EVM bytecode, and obtain the ABI interface parameter type and function call sequence based on the read and write dependencies between functions in the bytecode and the source code corresponding to the functions; Fuzzy processing module: used to generate a first test case set based on the ABI interface parameter type and function call sequence, perform fuzz testing on the EVM bytecode based on the first test case set, obtain the number of all instructions covered by each test case during instruction execution, and construct an instruction count set; according to the length change of the instruction count set within the set execution number threshold, perform symbolic execution processing when the length change value is 0, The symbolic execution processing operation specifically includes: setting the branch when the instruction count set length change value is 0 as the target branch point, obtaining only the arithmetic instructions and logical instructions of all branch constraints on each execution path when the instruction is executed to the target branch point, converting them into constraint expressions through symbolic processing, and collecting the constraint expressions to construct a path constraint set; After negating the constraint expression, a constraint solving operation is performed. During the constraint solving, the constraint expression and its solution are cached and reused to obtain a specific input value that satisfies the branch constraint condition of the target branch point. The specific input value is updated as a new test case to the first test case set to obtain a second test case set. The fuzzy processing module is executed in a loop to expand the second test case set until a set time is reached, the loop is terminated, and the vulnerability detection module is executed. Vulnerability Detection Module: used to set different test oracles for different smart contract vulnerabilities, including permission control, transaction sequence dependency, and denial of service smart contract vulnerabilities; Based on the test oracle, the second test case set is used in combination with taint analysis to detect smart contract vulnerabilities and obtain vulnerability detection results.