A smart contract vulnerability detection method and system based on gray box fuzz testing
By building a control flow chart, generating a function call chain and analytical branches in a smart contract, combining random mutations and dynamic data flow feedback, the problems of resource waste and complex vulnerability detection in the existing technology are solved, and efficient and accurate smart contract vulnerability detection is achieved.
Patent Information
- Application Number
- CN202510051775.X
- Authority / Receiving Office
- CN · China
- Patent Type
- Patents(China)
- Current Assignee / Owner
- Filing Date
- 2025-01-14
- Publication Date
- 2025-03-18
- Estimated Expiration
- 2045-01-14
AI Technical Summary
The existing gray box fuzz testing technology has wasted resources, difficulty in identifying meaningful seeds in smart contract security testing, and lack of in-depth analysis of smart contract-specific state variables and data flows, making it difficult to discover complex vulnerabilities.
By building a control flow graph, identifying functions and state variables, generating function call chains, determining the order of call between functions, initializing transaction sequences, analyzing branches and performing energy allocation, random mutations or variations based on conditional branches, capture dynamic data flows to generate target test cases.
It significantly improves the efficiency and accuracy of smart contract vulnerability detection, can better handle complex contract logic, discover deep-level vulnerabilities, and improve branch coverage.
Smart Images

Figure CN119475360B_ABST
Abstract
Description
Technical Field
[0001] The present invention belongs to the technical field of smart contract vulnerability detection, and specifically relates to a smart contract vulnerability detection method based on grey box fuzz testing. Background Art
[0002] With the widespread application of smart contracts in blockchain technology, its security issues have become increasingly prominent. Once deployed, smart contracts cannot be modified, so it is crucial to conduct comprehensive security testing before deployment. However, traditional testing methods often have difficulty discovering deep vulnerabilities, especially those hidden in rare execution paths. In this context, fuzz testing, as an automated software testing technology, has attracted much attention because of its ability to efficiently generate a large number of test cases.
[0003] Gray-box fuzz testing has shown great potential in the field of smart contract security testing by combining the advantages of white-box and black-box testing. However, existing gray-box fuzz testing techniques still have some limitations. First, they tend to treat all branches of a program as equal, ignoring the fact that vulnerabilities are usually concentrated in a few key branches, resulting in a waste of resources. Second, traditional code coverage feedback mechanisms have difficulty in effectively identifying meaningful seeds that can trigger new program behaviors. Finally, existing technologies lack in-depth analysis of state variables and data flows that are unique to smart contracts, which limits their ability to discover complex vulnerabilities. Summary of the invention
[0004] In order to solve the problems raised by the background technology, the present invention provides a smart contract vulnerability detection method and system based on gray box fuzzy testing.
[0005] The technical solution of the present invention is as follows:
[0006] The present invention provides a smart contract vulnerability detection method based on gray box fuzz testing, comprising the following steps:
[0007] S1: Construct a control flow graph based on the bytecode of the smart contract to be tested;
[0008] Perform an abstract interpretation of the bytecode to obtain the identified functions, the state variables defined by the functions, the state variables used by the functions, and the check function of the constructor;
[0009] Based on the control flow graph, the function call chain is obtained according to the identified functions, the state variables defined by the functions, the state variables used by the functions, and the constructors;
[0010] S2: Based on the function call chain, determine the calling order between functions and obtain the generation sequence. After checking the generation sequence according to the data flow, obtain the function call sequence;
[0011] Determine the function parameters of the function call sequence and obtain the initial transaction sequence;
[0012] S3: Based on the execution path of the initial transaction sequence, determine the prefix subpath, determine the branch according to the prefix subpath, and if the branch contains a preset vulnerable instruction, record the branch as a vulnerable branch; traverse the execution path to obtain a set of vulnerable branches;
[0013] According to the energy allocation rule, energy is allocated to the vulnerability branches of the vulnerability branch set to obtain the target vulnerability branch;
[0014] S4: Based on the initial transaction sequence of the target vulnerability branch, perform random mutation or mutation based on conditional branches to obtain test cases;
[0015] Use instruction addresses as nodes and keys as state variables to capture the dynamic data flow of test cases;
[0016] Based on the captured dynamic data flow, if a test case shows a previously undetected data flow or covers an unvisited branch, the test case is recorded as a target test case;
[0017] Detect vulnerabilities based on targeted test cases.
[0018] In step S3, based on the execution path of the initial transaction sequence, a prefix subpath is determined, and a branch is determined according to the prefix subpath, specifically:
[0019] Based on the execution path of the initial transaction sequence, the subpath of the execution path is determined, and the subpath with the same starting point as the execution path is recorded as a prefix subpath. If the prefix subpath ends with a conditional statement, the prefix subpath is used as a branch of the execution path.
[0020] In step S4, random mutation is to insert a new transaction sequence, cancel a random transaction sequence, or exchange two random transaction sequences into the initial transaction sequence of the target vulnerability branch;
[0021] Based on the mutation of conditional branches, in order to parse the conditional branches in the initial transaction sequence of the target vulnerability branch, a linear equation is constructed and solved, and mutation is performed according to the linear equation.
[0022] In step S1, the bytecode is abstractly interpreted to obtain the identified function, the state variables defined by the function, the state variables used by the function, and the check function of the constructor, specifically:
[0023] Identify functions based on the transfer instructions in the control flow graph;
[0024] Using flow-sensitive and context-sensitive methods, the memory abstract value and storage abstract value are calculated to determine the source of the operands. Based on the SLOAD and SSTORE instructions, the state variables defined and used by each function are identified.
[0025] For a constructor in an identified function, if the constructor saves the deployer address to storage and the sender address flows into the conditional branch and is compared with the deployer address, the constructor is used as the constructor's check function.
[0026] In step S2, based on the function call chain, the calling sequence between functions is determined to obtain a generated sequence, which is specifically:
[0027] The identified functions, state variables defined by the functions, and state variables used by the functions in the function call chain are obtained. For each function, the calling sequence between the functions is determined according to the state variables defined by the function and the state variables used by the function to obtain a generated sequence.
[0028] In step S2, the function parameters of the function call sequence are determined to obtain the initial transaction sequence, which is specifically:
[0029] For each function in the function call sequence, if the function is a check function of the constructor, the sender of the function is set to the deployer; if the function is not a check function of the constructor, the sender of the function is randomly set to the deployer or the user;
[0030] The parameters of the set function are expressed as a byte stream. If an application binary interface exists, the parameter type and the byte stream length of the parameter are determined according to the application binary interface.
[0031] If no binary interface is present, the byte stream length of each parameter is set to a preset value.
[0032] In step S2, after obtaining and checking the generated sequence according to the data stream, a function call sequence is obtained, which is specifically:
[0033] Get the data stream of the generated sequence and compare it with the stored data stream. If the data stream covers the stored data stream, use the generated sequence as the function call sequence.
[0034] In step S1, a control flow graph is constructed according to the bytecode of the smart contract to be detected, specifically:
[0035] The bytecode of the smart contract to be tested is converted into assembly instructions, the assembly instructions are converted into intermediate representations, constant propagation analysis is performed, control flow transfer instructions are determined, and a control flow graph is constructed.
[0036] The present invention also provides a smart contract vulnerability detection system based on gray box fuzz testing, comprising:
[0037] Function call chain building module: used to build a control flow graph based on the bytecode of the smart contract to be tested;
[0038] Perform an abstract interpretation of the bytecode to obtain the identified functions, the state variables defined by the functions, the state variables used by the functions, and the check function of the constructor;
[0039] Based on the control flow graph, the function call chain is obtained according to the identified functions, the state variables defined by the functions, the state variables used by the functions, and the constructors;
[0040] Initial transaction sequence generation module: Based on the function call chain, determine the calling order between functions to obtain the generation sequence. After checking the generation sequence according to the data flow, obtain the function call sequence;
[0041] Determine the function parameters of the function call sequence and obtain the initial transaction sequence;
[0042] Target vulnerability branch determination module: Based on the execution path of the initial transaction sequence, determine the prefix subpath, determine the branch according to the prefix subpath, and if the branch contains a preset vulnerable instruction, record the branch as a vulnerability branch; traverse the execution path to obtain a set of vulnerability branches;
[0043] According to the energy allocation rule, energy is allocated to the vulnerability branches of the vulnerability branch set to obtain the target vulnerability branch;
[0044] Vulnerability detection module: Based on the initial transaction sequence of the target vulnerability branch, random mutation or mutation based on conditional branches is performed to obtain test cases;
[0045] Use instruction addresses as nodes and keys as state variables to capture the dynamic data flow of test cases;
[0046] Based on the captured dynamic data flow, if a test case shows a previously undetected data flow or covers an unvisited branch, the test case is recorded as a target test case;
[0047] Detect vulnerabilities based on targeted test cases.
[0048] Beneficial Effects
[0049] The present invention first analyzes the control flow graph to obtain key information such as function state variables; secondly, initializes the transaction sequence to generate a meaningful initial transaction sequence; then branch analysis and energy allocation under forward-looking analysis are performed, giving priority to vulnerable branches; finally, fuzzy testing based on data flow is performed, combining random mutations and mutations based on conditional branches to generate test cases, and using the data flow feedback mechanism to generate meaningful test cases as target test cases. By comprehensively utilizing branch analysis and energy allocation based on forward-looking analysis and feedback based on data flow, the efficiency and accuracy of smart contract vulnerability detection are significantly improved, which can better handle complex contract logic, discover deep-level vulnerabilities, and improve branch coverage. BRIEF DESCRIPTION OF THE DRAWINGS
[0050] Figure 1 Schematic diagram of the static analysis method in the embodiment.
[0051] Figure 2 Schematic diagram of energy distribution in the embodiment.
[0052] Figure 3 This is an example diagram of a smart contract in an embodiment.
[0053] Figure 4 Figure 2. Number of vulnerabilities found over time using four different detection methods.
[0054] Figure 5 The impact of different detection methods on code coverage and the number of vulnerabilities discovered.
[0055] Figure 6 (a) shows the comparison of instruction coverage over time. Figure 6 (b) shows the comparison of the number of vulnerabilities discovered over time. DETAILED DESCRIPTION
[0056] The following examples are intended to illustrate the present invention rather than to further limit the present invention.
[0057] The present invention provides a smart contract vulnerability detection method based on gray box fuzz testing, comprising the following steps:
[0058] S1: Construct a control flow graph based on the bytecode of the smart contract to be tested;
[0059] Perform an abstract interpretation of the bytecode to obtain the identified functions, the state variables defined by the functions, the state variables used by the functions, and the check function of the constructor;
[0060] Based on the control flow graph, a function call chain is obtained according to the identified functions, the state variables defined by the functions, the state variables used by the functions, and the constructors.
[0061] Preferably, a control flow graph is constructed according to the bytecode of the smart contract to be detected, specifically:
[0062] The bytecode of the smart contract to be tested is converted into assembly instructions (EVM instructions), the assembly instructions are converted into intermediate representation (IR), constant propagation analysis is performed, control flow transfer instructions are determined, and a control flow graph (CFG) is constructed.
[0063] Through the control flow transfer instructions, each function, including the constructor, can be identified. In addition, the call edges in the smart contract to be tested are analyzed to achieve inter-program analysis, which provides a basis for the subsequent comprehensive understanding of the contract behavior.
[0064] After the control flow graph (CFG) is built, the bytecode is abstractly interpreted to obtain the identified functions (Funcs), the state variables defined by the functions (Defs), the state variables used by the functions (Uses), and the check function of the constructor (SenderChecks), specifically:
[0065] Identify functions, including constructors, based on the transfer instructions in the control flow graph;
[0066] The flow-sensitive and context-sensitive methods are used to calculate the memory abstract value and the storage abstract value, determine the source of the operand, and identify the state variables defined and used by each function based on the SLOAD instruction and SSTORE instruction.
[0067] By carefully tracking the memory abstract value and the storage abstract value, it is possible to determine the origin of the operands and, in turn, identify the state variables defined by each function and the state variables used by the function.
[0068] In order to better approximate the abstract value, a product domain consisting of three domains is used. The integer domain is used to track constants and access state variables of primitive data types; a variant of the integer domain is used to abstract the output of the SHA-3 hash instruction to process state variables of composite data types; and the tainted domain is used to track the address flow of the deployer of the smart contract to be detected.
[0069] In addition, during the entire analysis process, special attention is paid to the keys of the SLOAD and SSTORE instructions, because the SLOAD and SSTORE instructions are directly related to the state variables defined and used by the function. By checking the SLOAD and SSTORE instructions, the Defs and Uses maps can be accurately updated, thereby completely capturing the usage of state variables.
[0070] For the constructor in the identified function, determine SenderChecks. If the constructor saves the deployer address to storage, and the sender address flows into the conditional branch and is compared with the deployer address, then the constructor is added to the SenderChecks collection as a check function of the constructor.
[0071] Finally, based on the control flow graph, the function call chain (def-use chain) is obtained according to the identified functions, the state variables defined by the functions, the state variables used by the functions, and the constructors.
[0072] S2: Based on the function call chain, determine the calling order between functions and obtain the generation sequence. After checking the generation sequence according to the data flow gain (DataFlowGain), obtain the function call sequence;
[0073] Determine the function parameters of the function call sequence and obtain the initial transaction sequence.
[0074] The function call sequence process of Algorithm 1 in Table 1 is taken as an example for detailed description.
[0075] Table 1 Function call sequence process
[0076]
[0077] Preferably, based on the function call chain, the calling order between functions is determined to obtain a generation sequence, which is specifically:
[0078] The identified functions, state variables defined by the functions, and state variables used by the functions in the function call chain are obtained. For each function, the calling sequence between the functions is determined according to the state variables defined by the function and the state variables used by the function to obtain a generated sequence.
[0079] As can be seen from Table 1, the identified functions (Funcs), the state variables defined by the functions (Defs), and the state variables used by the functions (Uses) are used as input, and a set of function call sequences are finally output. First, the work list works is initialized with a singleton sequence containing each function in Funcs (line 3). Functions that do not define any state variables are ignored because they do not affect the persistent state. Next, the sequence s is taken from the work list (line 5), and a generation sequence is created by appending each function in Funcs to s (line 9).
[0080] The processing logic of the above process is to take a sequence s from the work list works and try to get the generated sequence by appending other functions in the identified functions (Funcs) to s. This means that each iteration will extend the current generated sequence.
[0081] The work list works is a data structure used to store a sequence of functions to be processed so as to obtain a function call sequence.
[0082] Initialization: The work list works initially contains a singleton sequence for each function extracted from Funcs. These sequences represent a single function call.
[0083] Singleton sequence: The singleton sequence of each function is a sequence that contains only the function itself. For example, if there are functions A, B, and C, the singleton sequence is [A], [B], and [C].
[0084] Generation of sequence s: Initially, each element in the work list works is a singleton sequence. Next, the algorithm takes a sequence s from works, which may be a single function or a combination of multiple functions generated previously.
[0085] Extension process: After extracting the sequence s from the work list works, the algorithm will append each function in Funcs to s to get the generated sequence. For example, if s is [A], the generated sequences will be [A,B], [A,C].
[0086] After obtaining the generated sequence, it is necessary to further determine the meaningful calling order to obtain the function call sequence. Preferably, after checking the generated sequence according to data flow acquisition (DataFlowGain), the function call sequence is obtained, which is specifically:
[0087] Get the data stream of the generated sequence and compare it with the stored data stream. If the data stream covers the stored data stream, the generated sequence is used as the function call sequence. See Table 1 (lines 7-8) for details.
[0088] For example, DataFlowGain collects triples from a given sequence<f1,v,f2> To statically approximate the function-level data flow. Where f1 and f2 are functions that appear in the sequence,<f1,v,f2> means that f1 defines v, and f2 uses v. Returns true if a triplet is found from the sequence that did not appear previously. Iterations continue as long as new data is observed, extending the sequences in the work list works. If a sequence does not yield gains through expansion, it is added to the output set, marking the completion of the sequence of function calls.
[0089] After obtaining the function call sequence, it is necessary to specify the content of the generated function sequence. Preferably, the function parameters of the function call sequence are determined to obtain the initial transaction sequence, which is specifically:
[0090] First, for each function in the function call sequence, if the function is a check function of the constructor (SenderChecks), the sender of the function is set to the deployer; if the function is not a check function of the constructor, the sender of the function is randomly set to the deployer or the user.
[0091] Secondly, initialize the function parameters of each transaction. Represent the parameters of the set function as a byte stream. If there is an application binary interface (ABI), determine the parameter type and the byte stream length of the parameter according to the application binary interface;
[0092] If no binary interface is present, the byte stream length of each parameter is set to a preset value.
[0093] S3: Based on the execution path of the initial transaction sequence, determine the prefix subpath, determine the branch according to the prefix subpath, and if the branch contains a preset vulnerable instruction, record the branch as a vulnerable branch; traverse the execution path to obtain a set of vulnerable branches;
[0094] According to the energy allocation rule, energy is allocated to the vulnerability branches in the vulnerability branch set to obtain the target vulnerability branch.
[0095] Among them, based on the execution path of the initial transaction sequence, a prefix subpath is determined, and a branch is determined according to the prefix subpath. If the branch contains a preset vulnerable instruction, the branch is recorded as a vulnerable branch; the execution path is traversed to obtain a set of vulnerable branches.
[0096] Most existing fuzz testing tools usually treat the branches of a program as equal, ignoring the fact that vulnerable code often only accounts for a small part of the entire code. Therefore, traditional fuzz testing tools may waste a lot of resources on normal branches instead of focusing on branches that are more prone to vulnerabilities. To solve this problem, an energy allocation mechanism is designed to allocate fuzz testing resources to these important branches. The mechanism consists of two parts: branch analysis and energy allocation.
[0097] First, a branch search algorithm is introduced to analyze all branches found during fuzz testing and focus on the vulnerable branches. See the branch search process of Algorithm 2 in Table 2 for details.
[0098] Table 2 Branch search process
[0099]
[0100] Preferably, based on the execution path of the initial transaction sequence, a prefix subpath is determined, and a branch is determined according to the prefix subpath, specifically:
[0101] Based on the execution path of the initial transaction sequence, the subpath of the execution path is determined, and the subpath with the same starting point as the execution path is recorded as the prefix subpath. If the prefix subpath ends with a conditional statement (located in the conditional jump block), the prefix subpath is used as a branch of the execution path.
[0102] For example, given an execution path p of the initial transaction sequence in a smart contract, if br is a subpath of p and br and p have the same starting point, then br is called a prefix subpath of p. This process is achieved through the forward analysis method.
[0103] The forward-looking analysis method is introduced as follows:
[0104] Proactive analysis methods belong to online static analysis, which aims to guide gray-box fuzz testing towards target locations through semantics, such as locations reported by other analyses or recently modified parts of the program. Figure 1 As shown, Figure 1 To include the target location and The program execution tree. Look-ahead analysis of the program path (bold path) is analyzed to identify a prefix subpath , making it impossible for all suffix paths to reach the target location ( and ). In the given prefix subpath In the case of , all suffix paths are followed to find the reachable target location (with Prefix subpath The last program position is the "split point" ( ). When analyzing all suffix paths, we do not consider all possible execution states at the split point, but only focus on the paths along In other words, lookahead analysis combines the accuracy of path-sensitive analysis along feasible path prefixes with the scalability of path-insensitive suffix analysis. Intuitively, for a given path , the accuracy of the lookahead analysis is determined by the number of paths that prove that all suffix paths cannot reach any target location. Therefore, to optimize accuracy, the analysis attempts to identify paths The first split point on ), making all targets unreachable.
[0105] Through forward-looking analysis technology, resources can be allocated more strategically during the fuzz testing process, so that more energy can be focused on program paths that may reach the target location, thereby achieving targeted fuzz testing.
[0106] As can be seen from Table 2, the process of obtaining the vulnerable branch is as follows: first, all prefix subpaths br are found during the fuzz test (line 1). Secondly, lines 5-7 check whether the prefix subpath br is located at the conditional statement jump, and use the look-ahead analysis method to detect its shortest prefix subpath. Then, line 8 checks whether there is a prefix subpath br that satisfies the form of the vulnerable statement. Finally, a set of vulnerable branches Bvulnerable is obtained.
[0107] Then, in order to obtain important vulnerability branches, energy is allocated to the vulnerability branches in the vulnerability branch set according to the energy allocation rule to obtain the target vulnerability branch.
[0108] The energy allocation rule is specifically:
[0109] Given a branch br1 in path p1 and a branch br2 in path p2, in the case where br1∈Bvulnerable, the energy allocation function Ω will be α* The energy of is distributed to br1(α>1), The energy of is allocated to br2. The coefficient α controls the preference for vulnerable branches.
[0110] Among them, path p1: represents a specific execution path in the program, which consists of a series of instructions and branches.
[0111] Branch br1: is a specific branch in path p1, usually the result of a conditional statement or a judgment statement.
[0112] Path p2: Similar to path p1, it represents another execution path in the program.
[0113] Branch br2: A specific branch in path p2.
[0114] Bvulnerable: represents a set of vulnerable branches, including all known vulnerable branches.
[0115] Ω: represents the energy allocation function, which is responsible for allocating different energies to different branches.
[0116] The coefficient α is used to control the preference for the vulnerable branch br1. The condition α>1 means that the energy allocation priority for br1 is higher than that for other branches.
[0117] : Represents the unit of basic energy allocation, used to allocate to other branches (such as br2).
[0118] use Figure 2To illustrate the energy allocation rule, for ease of understanding, the Solidity source code is used for explanation. Specifically, firstly, all found branches are analyzed, and the branch br at line 13 is selected as the vulnerable branch because it contains a vulnerable statement (i.e., block.number) at line 14. Then, according to the energy allocation rule, the energy α* Assigned to branch br. Existing testing tools cannot reach the if branch on line 13 within the specified time because they waste too much energy on the while branch on line 7. In contrast, the method of the present application successfully covers this branch and exposes the block dependency vulnerability on line 14 within an average of 10 seconds (the time range of 5 runs is between 6 seconds and 14 seconds).
[0119] The present invention adopts an energy allocation mechanism, which can flexibly allocate fuzz testing resources to vulnerable branches, thereby improving the overall fuzz testing efficiency and branch coverage.
[0120] S4: Based on the initial transaction sequence of the target vulnerability branch, perform random mutation or mutation based on conditional branches to obtain test cases;
[0121] Use instruction addresses as nodes and keys as state variables to capture the dynamic data flow of test cases;
[0122] Based on the captured dynamic data flow, if a test case shows a previously undetected data flow or covers an unvisited branch, the test case is recorded as a target test case;
[0123] Detect vulnerabilities based on targeted test cases.
[0124] First, based on the initial transaction sequence of the target vulnerability branch, random mutation or conditional branch-based mutation is performed to obtain test cases.
[0125] Among them, regarding mutation, two complementary strategies are adopted. Specifically:
[0126] Random mutation is to insert a new transaction sequence, cancel a random transaction sequence, or swap two random transaction sequences into the initial transaction sequence of the target vulnerability branch.
[0127] However, random mutations are prone to get stuck when checking conditional branches such as magic values. Therefore, based on the above random mutations, mutations based on conditional branches are adopted. Mutations based on conditional branches parse the conditional branches in the initial transaction sequence of the target vulnerability branch, construct and solve linear equations, and perform mutations based on the linear equations.
[0128] Take the condition "balances[msg.sender]>= amount" as an example. Assuming the current balance balances[msg.sender] is 100, a linear equation (e.g., x>= 100, where x is amount) is parsed, constructed, and solved. If amount is greater than or equal to 100, the condition is true; otherwise, it is false. The condition depends on two input fields: balances[msg.sender] (current balance) and amount (transfer amount). To ensure that both fields can be processed so that different scenarios can be explored effectively. Mutation will be performed to generate a new sequence to explore uncovered paths. For example, a new transfer request may be created, setting amount to 50 (valid transfer) or 150 (invalid transfer) to test different conditional branches. For each generated sequence, the mutation method updates the constraints to reflect the new state, such as -(balances[msg.sender]>= amount) to indicate the opposite branch to explore.
[0129] The present invention adopts mutation based on conditional branches on the basis of random mutation to penetrate complex branch conditions, thereby improving the efficiency and coverage of fuzzy testing.
[0130] Secondly, considering that the previous code coverage feedback is not enough to identify the target test cases during the fuzz testing process, in order to solve this problem, data flow-based feedback is introduced in addition to the traditional code coverage feedback. Specifically, when a test case shows a previously undetected data flow or covers an unvisited branch, the test case is considered meaningful.
[0131] Therefore, after getting the test case, the instruction address is used as the node and the key as the state variable to capture the dynamic data flow of the test case;
[0132] Based on the captured dynamic data flow, if a test case shows a previously undetected data flow or covers an unvisited branch, the test case is recorded as a target test case.
[0133] Dataflow represents the definition-use dependency between variables, which can be determined through def-use chains. During dynamic execution, as the path is extended, dataflow can capture some new data flows that were not detected before.
[0134] In order to capture the dynamic flow, based on the function call chain (def-use chain), which contains the state variables defined by the function (Defs) and the state variables used by the function (Uses), the dynamic data flow is captured. First, an instruction address is used as the program point P1, and the key of the memory is used as the state variable v .set up is a state variable v The def-use chain on the , indicating the state variable v Defined at program point p1 and used at program point p2. Then Figure 3 The def-use chain in is shown below. Test case A generates and , where 12, 14, 15, and 17 represent lines of code, and test case B only generates Therefore, it can be identified that test case B does not exhibit meaningful program behavior.
[0135] Finally, vulnerabilities are detected according to the target test cases.
[0136] For example, assertion failure vulnerabilities (AF) can be accurately detected by checking whether the target test case executes the INVALID instruction;
[0137] Taint the return value of the instruction that obtains the block status (such as TIMESTAMP, NUMBER). Then, monitor whether the tainted value flows into the operand of the CALL or JUMPI instruction to detect the block information dependency vulnerability (BID);
[0138] Detect Ether Leakage (EL) vulnerabilities by checking if there are any previous transactions from the deployer in the target test case;
[0139] Detect suicide vulnerabilities (SC) by checking whether a normal user in the target test case can execute the SELFDESTRUCT instruction and destroy the contract;
[0140] Transaction State Dependency (TSD) vulnerabilities are detected by tainting the return value of the ORIGIN instruction and checking whether the value flows into the operand of the JUMPI instruction.
[0141] The present invention first analyzes the control flow graph to obtain key information such as function state variables; secondly, initializes the transaction sequence to generate a meaningful initial transaction sequence; then branch analysis and energy allocation under forward-looking analysis, giving priority to vulnerable branches; finally, fuzzy testing based on data flow, combining random mutation and mutation based on conditional branches to generate test cases, and using data flow feedback mechanism to generate meaningful test cases as target test cases. By comprehensively utilizing forward-looking analysis and feedback based on data flow, the efficiency and accuracy of smart contract vulnerability detection are significantly improved, which can better handle complex contract logic, discover deep-level vulnerabilities, and improve branch coverage.
[0142] The present invention also provides a smart contract vulnerability detection system based on gray box fuzz testing, comprising:
[0143] Function call chain building module: used to build a control flow graph based on the bytecode of the smart contract to be tested;
[0144] Perform an abstract interpretation of the bytecode to obtain the identified functions, the state variables defined by the functions, the state variables used by the functions, and the check function of the constructor;
[0145] Based on the control flow graph, the function call chain is obtained according to the identified functions, the state variables defined by the functions, the state variables used by the functions, and the constructors;
[0146] Initial transaction sequence generation module: Based on the function call chain, determine the calling order between functions to obtain the generation sequence. After checking the generation sequence according to the data flow, obtain the function call sequence;
[0147] Determine the function parameters of the function call sequence and obtain the initial transaction sequence;
[0148] Target vulnerability branch determination module: Based on the execution path of the initial transaction sequence, determine the prefix subpath, determine the branch according to the prefix subpath, and if the branch contains a preset vulnerable instruction, record the branch as a vulnerability branch; traverse the execution path to obtain a set of vulnerability branches;
[0149] According to the energy allocation rule, energy is allocated to the vulnerability branches of the vulnerability branch set to obtain the target vulnerability branch;
[0150] Vulnerability detection module: Based on the initial transaction sequence of the target vulnerability branch, random mutation or mutation based on conditional branches is performed to obtain test cases;
[0151] Use instruction addresses as nodes and keys as state variables to capture the dynamic data flow of test cases;
[0152] Based on the captured dynamic data flow, if a test case shows a previously undetected data flow or covers an unvisited branch, the test case is recorded as a target test case;
[0153] Detect vulnerabilities based on targeted test cases.
[0154] Experimental Evaluation
[0155] A. Experimental Setup
[0156] (1) Environment: All experiments were run on an Ubuntu 20.04 server equipped with two Intel E5-2699 v4 (2.2 GHz) CPUs and 512 GB of main memory. Docker 20.10.3 was used for the experiments, and a container was used to run the tool on a single contract. A maximum of 72 containers were started in parallel, and each container was assigned a CPU core and 6 GB of memory. To compile the contract, solc-0.4.26 was used.
[0157] (2) Comparison tools: Two fuzz testing tools, ILF and sFuzz, were selected as the comparison objects for the vulnerability detection method of this application. Among them, ILF uses machine learning to effectively generate transaction sequences; sFuzz combines the coverage-guided fuzz testing tool AFL (American Fuzzy Lop) with the branch distance feedback used in search-based testing to explore difficult-to-reach branches. However, sFuzz does not directly deal with the transaction problem of stateful variables in this application.
[0158] (3) Benchmarking: Two different datasets were used for experiments.
[0159] Dataset 1 was constructed by extracting contracts from SmartBugs. Specifically, contracts with assertion failure vulnerabilities (AF), block information dependency vulnerabilities (BID), ether leakage vulnerabilities (EL), suicide vulnerabilities (SC), and transaction state dependency vulnerabilities (TSD) were imported. Subsequently, preprocessing was performed, such as filtering out contracts with any parameters in the constructor to avoid abnormal operation on such contracts. In the end, 149 contracts were obtained, including 13 AF, 57 BID, 7 EL, 7 SC, and 16 TSD. In addition, a single contract can have multiple vulnerability categories.
[0160] Dataset 2: This dataset contains 500 popular and complex smart contracts from Etherscan, an online platform that provides Ethereum smart contract codes and statistics. First, we downloaded contracts with more than 30,000 transactions and excluded contracts that were incompatible with the solc version used. Finally, we sorted the remaining contracts according to bytecode size and selected the 500 largest contracts to ensure that the collected contracts were both popular and complex.
[0161] B Analysis
[0162] Since Dataset 1 contains five types of vulnerabilities, it can provide a real basis for evaluation. Therefore, by applying the detection method of this application (combination of static and dynamic data flow analysis), static data flow analysis method (compared to the combination of static and dynamic data flow analysis of this application, only static data flow analysis), dynamic data flow analysis method (compared to the combination of static and dynamic data flow analysis of this application, only dynamic data flow analysis), and no static and dynamic data flow analysis method (compared to the combination of static and dynamic data flow analysis of this application, no static and dynamic data flow analysis) in Dataset 1, the effectiveness and overhead of the detection method of this application for vulnerability detection are evaluated.
[0163] Figure 4 The number of vulnerabilities discovered over time under four different detection methods is shown. It can be seen that there is a significant difference in the effect of discovering deep vulnerabilities in the later stages of fuzz testing. Among them, compared with the method without static and dynamic data flow analysis, the detection method of this application (a combination of static and dynamic data flow analysis) can discover about 18.6% more unique vulnerabilities. This result verifies that the smart contract vulnerabilities existing in the prior art can only be discovered by considering stateful transaction sequences, and the detection method of this application plays an important role in this process.
[0164] The impact on code coverage is determined by detecting the number of instructions executed using the detection method of the present application (combination of static and dynamic data flow analysis) and the method without static and dynamic data flow analysis (compared to the combination of static and dynamic data flow analysis of the present application, without static and dynamic data flow analysis). Figure 5 It shows that compared with the method without static and dynamic data flow analysis, turning on static and dynamic data flow, that is, using the detection method of this application for analysis, covers 2% more instructions. Although the coverage gap is not significant, there is a significant difference in the number of vulnerabilities found. This further illustrates that although the method without static and dynamic data flow analysis can effectively guide the fuzz testing tool to increase coverage, it may not be enough to trigger vulnerabilities when a stateful transaction sequence is required, and the detection method of this application can solve this problem.
[0165] Comparison with existing tools
[0166] (1) Comparison on Dataset 1: The detection method of this application (denoted as AheadFuzz) is compared with the ILF and sFuzz tools on Dataset 1, which is built from the SmartBugs benchmark. Contracts marked as AF, BID, EL, SC, and TSD are selected. Then, each tool is run for one hour on each contract in Dataset 1. In order to measure the vulnerability discovery effect, it is checked whether the vulnerabilities marked on each contract can be reported.
[0167] Figure 6(a) shows the instruction coverage over time. Figure 6 (b) shows the number of vulnerabilities found over time. The results are the average based on five repeated experiments. Figure 6 As shown in (a), the detection method of the present application (AheadFuzz) also continuously covers more instructions in the whole process. Specifically, the detection method of the present application covers 0.36 times and 0.7 times more instructions than ILF and sFuzz, respectively. Figure 6 (b) shows that the detection method (AheadFuzz) of this application can find more vulnerabilities, 0.19 times and 0.11 times more vulnerabilities than ILF and sFuzz, respectively. This result remains consistent in five repeated experiments.
[0168] The number of false positives caused by each detection method is also counted and summarized in Table 3, and the number of vulnerabilities found (i.e. true positives) is also listed. Table 3 shows that the detection method of this application (AheadFuzz) not only has the highest recall rate (abbreviated as R) in this benchmark test, but also has the highest precision rate (abbreviated as P). The formulas for precision and recall are as follows:
[0169] ;
[0170] ;
[0171] In the formula, is the accuracy rate; is the recall rate; is the number of true positives; is the number of false negatives; is the number of false positives.
[0172] Table 3 The number of true positives (TP) and false positives (FP) detected by different detection methods on dataset 1
[0173]
[0174] D Large-scale testing
[0175] To further evaluate the scalability of our proposed detection method (AheadFuzz), we ran AheadFuzz on Dataset 2, which contains 500 popular and large contracts collected from Etherscan. We ran AheadFuzz on each contract for one hour and manually checked the authenticity of the reports, classifying them into true positives and false positives.
[0176] The specific results are shown in Table 4. AheadFuzz reported a total of 49 vulnerabilities. Among the 500 contracts, 35 contracts were marked as having at least one such vulnerability. These contracts were manually checked and 83.6% of the reports were confirmed to be true, which proves that AheadFuzz can accurately detect and reduce false positives.
[0177] Table 4 Number of vulnerabilities found by the detection method (AheadFuzz) of this application on Dataset 2
[0178]
Claims
1. A smart contract vulnerability detection method based on gray box fuzz testing, characterized in that: The following steps are involved: S1: Construct a control flow graph based on the bytecode of the smart contract to be tested; Perform an abstract interpretation of the bytecode to obtain the identified functions, the state variables defined by the functions, the state variables used by the functions, and the check function of the constructor; Based on the control flow graph, the function call chain is obtained according to the identified functions, the state variables defined by the functions, the state variables used by the functions, and the constructors; S2: Based on the function call chain, determine the calling order between functions and obtain the generation sequence. After checking the generation sequence according to the data flow, obtain the function call sequence; Determine the function parameters of the function call sequence and obtain the initial transaction sequence; S3: Based on the execution path of the initial transaction sequence, determine the prefix subpath, determine the branch according to the prefix subpath, and if the branch contains a preset vulnerable instruction, record the branch as a vulnerable branch; Traverse the execution path to obtain the set of vulnerable branches; According to the energy allocation rule, energy is allocated to the vulnerability branches of the vulnerability branch set to obtain the target vulnerability branch; S4: Based on the initial transaction sequence of the target vulnerability branch, perform random mutation or mutation based on conditional branches to obtain test cases; Use instruction addresses as nodes and keys as state variables to capture the dynamic data flow of test cases; Based on the captured dynamic data flow, if a test case shows a previously undetected data flow or covers an unvisited branch, the test case is recorded as a target test case; Detect vulnerabilities based on targeted test cases.
2. The smart contract vulnerability detection method based on gray box fuzz testing according to claim 1 is characterized in that: In step S3, based on the execution path of the initial transaction sequence, a prefix subpath is determined, and a branch is determined according to the prefix subpath, specifically: Based on the execution path of the initial transaction sequence, the subpath of the execution path is determined, and the subpath with the same starting point as the execution path is recorded as a prefix subpath. If the prefix subpath ends with a conditional statement, the prefix subpath is used as a branch of the execution path.
3. The smart contract vulnerability detection method based on gray box fuzz testing according to claim 1 is characterized in that: In step S4, random mutation is to insert a new transaction sequence, cancel a random transaction sequence, or exchange two random transaction sequences into the initial transaction sequence of the target vulnerability branch; Based on the mutation of conditional branches, in order to parse the conditional branches in the initial transaction sequence of the target vulnerability branch, a linear equation is constructed and solved, and mutation is performed according to the linear equation.
4. The smart contract vulnerability detection method based on gray box fuzz testing according to claim 1 is characterized in that: In step S1, the bytecode is abstractly interpreted to obtain the identified function, the state variables defined by the function, the state variables used by the function, and the check function of the constructor, specifically: Identify functions based on the transfer instructions in the control flow graph; Using flow-sensitive and context-sensitive methods, the memory abstract value and storage abstract value are calculated to determine the source of the operands. Based on the SLOAD and SSTORE instructions, the state variables defined and used by each function are identified. For the constructor in the identified function, if the constructor saves the deployer address to storage and the sender address flows into the conditional branch and is compared with the deployer address, the constructor is used as the check function of the constructor.
5. The smart contract vulnerability detection method based on gray box fuzz testing according to claim 1 is characterized in that: In step S2, based on the function call chain, the calling sequence between functions is determined to obtain a generated sequence, which is specifically: The identified functions, state variables defined by the functions, and state variables used by the functions in the function call chain are obtained. For each function, the calling sequence between the functions is determined according to the state variables defined by the function and the state variables used by the function to obtain a generated sequence.
6. The smart contract vulnerability detection method based on gray box fuzz testing according to claim 1 is characterized in that: In step S2, the function parameters of the function call sequence are determined to obtain the initial transaction sequence, which is specifically: For each function in the function call sequence, if the function is a check function of the constructor, the sender of the function is set to the deployer; if the function is not a check function of the constructor, the sender of the function is randomly set to the deployer or the user; The parameters of the set function are expressed as a byte stream. If an application binary interface exists, the parameter type and the byte stream length of the parameter are determined according to the application binary interface. If no binary interface is present, the byte stream length of each parameter is set to a preset value.
7. The smart contract vulnerability detection method based on gray box fuzz testing according to claim 1 is characterized in that: In step S2, after obtaining and checking the generated sequence according to the data stream, a function call sequence is obtained, which is specifically: Get the data stream of the generated sequence and compare it with the stored data stream. If the data stream covers the stored data stream, use the generated sequence as the function call sequence.
8. The smart contract vulnerability detection method based on gray box fuzz testing according to claim 1 is characterized in that: In step S1, a control flow graph is constructed according to the bytecode of the smart contract to be detected, specifically: The bytecode of the smart contract to be tested is converted into assembly instructions, the assembly instructions are converted into intermediate representations, constant propagation analysis is performed, control flow transfer instructions are determined, and a control flow graph is constructed.
9. A smart contract vulnerability detection system based on gray box fuzz testing, characterized in that: include: Function call chain building module: used to build a control flow graph based on the bytecode of the smart contract to be tested; Perform an abstract interpretation of the bytecode to obtain the identified functions, the state variables defined by the functions, the state variables used by the functions, and the check function of the constructor; Based on the control flow graph, the function call chain is obtained according to the identified functions, the state variables defined by the functions, the state variables used by the functions, and the constructors; Initial transaction sequence generation module: Based on the function call chain, determine the calling order between functions to obtain the generation sequence. After checking the generation sequence according to the data flow, obtain the function call sequence; Determine the function parameters of the function call sequence and obtain the initial transaction sequence; Target vulnerability branch determination module: Based on the execution path of the initial transaction sequence, determine the prefix subpath, determine the branch according to the prefix subpath, and if the branch contains a preset vulnerable instruction, record the branch as a vulnerable branch; Traverse the execution path to obtain the set of vulnerable branches; According to the energy allocation rule, energy is allocated to the vulnerability branches of the vulnerability branch set to obtain the target vulnerability branch; Vulnerability detection module: Based on the initial transaction sequence of the target vulnerability branch, random mutation or mutation based on conditional branches is performed to obtain test cases; Use instruction addresses as nodes and keys as state variables to capture the dynamic data flow of test cases; Based on the captured dynamic data flow, if a test case shows a previously undetected data flow or covers an unvisited branch, the test case is recorded as a target test case; Detect vulnerabilities based on targeted test cases.
Citation Information
Patent Citations
EOSIO smart contract-oriented grey box fuzzy test method
CN115438351A
Intelligent contract fuzzy test method and system
CN115794625A