Open source incorrect-equality detector

pull/146/head
Josselin 6 years ago
parent c102cf2334
commit 1532babf38
  1. 55
      README.md
  2. 1
      scripts/tests_generate_expected_json_5.sh
  3. 2
      scripts/travis_test_5.sh
  4. 5
      slither/__main__.py
  5. 119
      slither/detectors/statements/incorrect_strict_equality.py
  6. 1
      tests/expected_json/incorrect_equality.incorrect-equality.json

@ -60,25 +60,25 @@ Num | Detector | What it Detects | Impact | Confidence
5 | `arbitrary-send` | [Functions that send ether to arbitrary destinations](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#functions-that-send-ether-to-arbitrary-destinations) | High | Medium
6 | `controlled-delegatecall` | [Controlled delegatecall destination](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#controlled-delegatecall) | High | Medium
7 | `reentrancy-eth` | [Reentrancy vulnerabilities (theft of ethers)](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#reentrancy-vulnerabilities) | High | Medium
8 | `locked-ether` | [Contracts that lock ether](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#contracts-that-lock-ether) | Medium | High
9 | `shadowing-abstract` | [State variables shadowing from abstract contracts](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#state-variable-shadowing-from-abstract-contracts) | Medium | High
10 | `constant-function` | [Constant functions changing the state](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#constant-functions-changing-the-state) | Medium | Medium
11 | `reentrancy-no-eth` | [Reentrancy vulnerabilities (no theft of ethers)](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#reentrancy-vulnerabilities) | Medium | Medium
12 | `tx-origin` | [Dangerous usage of `tx.origin`](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#dangerous-usage-of-txorigin) | Medium | Medium
13 | `uninitialized-local` | [Uninitialized local variables](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#uninitialized-local-variables) | Medium | Medium
14 | `unused-return` | [Unused return values](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#unused-return) | Medium | Medium
15 | `calls-loop` | [Multiple calls in a loop](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description/_edit#calls-inside-a-loop) | Low | Medium
16 | `reentrancy-benign` | [Benign reentrancy vulnerabilities](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#reentrancy-vulnerabilities) | Low | Medium
17 | `timestamp` | [Dangerous usage of `block.timestamp`](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#block-timestamp) | Low | Medium
18 | `assembly` | [Assembly usage](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#assembly-usage) | Informational | High
19 | `constable-states` | [State variables that could be declared constant](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#state-variables-that-could-be-declared-constant) | Informational | High
20 | `external-function` | [Public function that could be declared as external](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#public-function-that-could-be-declared-as-external) | Informational | High
21 | `low-level-calls` | [Low level calls](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#low-level-calls) | Informational | High
22 | `naming-convention` | [Conformance to Solidity naming conventions](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#conformance-to-solidity-naming-conventions) | Informational | High
23 | `pragma` | [If different pragma directives are used](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#different-pragma-directives-are-used) | Informational | High
24 | `solc-version` | [Old versions of Solidity (< 0.4.23)](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#old-versions-of-solidity) | Informational | High
25 | `unused-state` | [Unused state variables](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#unused-state-variables) | Informational | High
8 | `incorrect-equality` | [Dangerous strict equalities](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#dangerous-strict-equalities) | Medium | High
9 | `locked-ether` | [Contracts that lock ether](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#contracts-that-lock-ether) | Medium | High
10 | `shadowing-abstract` | [State variables shadowing from abstract contracts](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#state-variable-shadowing-from-abstract-contracts) | Medium | High
11 | `constant-function` | [Constant functions changing the state](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#constant-functions-changing-the-state) | Medium | Medium
12 | `reentrancy-no-eth` | [Reentrancy vulnerabilities (no theft of ethers)](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#reentrancy-vulnerabilities) | Medium | Medium
13 | `tx-origin` | [Dangerous usage of `tx.origin`](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#dangerous-usage-of-txorigin) | Medium | Medium
14 | `uninitialized-local` | [Uninitialized local variables](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#uninitialized-local-variables) | Medium | Medium
15 | `unused-return` | [Unused return values](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#unused-return) | Medium | Medium
16 | `calls-loop` | [Multiple calls in a loop](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description/_edit#calls-inside-a-loop) | Low | Medium
17 | `reentrancy-benign` | [Benign reentrancy vulnerabilities](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#reentrancy-vulnerabilities) | Low | Medium
18 | `timestamp` | [Dangerous usage of `block.timestamp`](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#block-timestamp) | Low | Medium
19 | `assembly` | [Assembly usage](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#assembly-usage) | Informational | High
20 | `constable-states` | [State variables that could be declared constant](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#state-variables-that-could-be-declared-constant) | Informational | High
21 | `external-function` | [Public function that could be declared as external](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#public-function-that-could-be-declared-as-external) | Informational | High
22 | `low-level-calls` | [Low level calls](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#low-level-calls) | Informational | High
23 | `naming-convention` | [Conformance to Solidity naming conventions](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#conformance-to-solidity-naming-conventions) | Informational | High
24 | `pragma` | [If different pragma directives are used](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#different-pragma-directives-are-used) | Informational | High
25 | `solc-version` | [Old versions of Solidity (< 0.4.23)](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#old-versions-of-solidity) | Informational | High
26 | `unused-state` | [Unused state variables](https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#unused-state-variables) | Informational | High
[Contact us](https://www.trailofbits.com/contact/) to get access to additional detectors.
@ -89,14 +89,15 @@ To run a printer, use `--print` and a comma-separated list of printers.
Num | Printer | Description
--- | --- | ---
1 | `call-graph` | Export the call-graph of the contracts to a dot file
2 | `contract-summary` | Print a summary of the contracts
3 | `function-summary` | Print a summary of the functions
4 | `human-summary` | Print a human readable summary of the contracts
5 | `inheritance` | Print the inheritance relations between contracts
6 | `inheritance-graph` | Export the inheritance graph of each contract to a dot file
7 | `slithir` | Print the slithIR representation of the functions
8 | `vars-and-auth` | Print the state variables written and the authorization of the functions
2 | `cfg` | Export the CFG of each functions
3 | `contract-summary` | Print a summary of the contracts
4 | `function-summary` | Print a summary of the functions
5 | `human-summary` | Print a human readable summary of the contracts
6 | `inheritance` | Print the inheritance relations between contracts
7 | `inheritance-graph` | Export the inheritance graph of each contract to a dot file
8 | `slithir` | Print the slithIR representation of the functions
9 | `slithir-ssa` | Print the slithIR representation of the functions
10 | `vars-and-auth` | Print the state variables written and the authorization of the functions
## How to install
Slither requires Python 3.6+ and [solc](https://github.com/ethereum/solidity/), the Solidity compiler.

@ -28,3 +28,4 @@ generate_expected_json(){
#generate_expected_json tests/inline_assembly_contract-0.5.1.sol "assembly"
#generate_expected_json tests/inline_assembly_library-0.5.1.sol "assembly"
#generate_expected_json tests/constant-0.5.1.sol "constant-function"
#generate_expected_json tests/incorrect_equality.sol "incorrect-equality"

@ -86,7 +86,7 @@ test_slither tests/controlled_delegatecall.sol "controlled-delegatecall"
test_slither tests/constant-0.5.1.sol "constant-function"
test_slither tests/unused_return.sol "unused-return"
test_slither tests/timestamp.sol "timestamp"
test_slither tests/incorrect_equality.sol "incorrect-equality"
### Test scripts

@ -134,7 +134,7 @@ def get_detectors_and_printers():
from slither.detectors.shadowing.state import StateShadowing
from slither.detectors.operations.block_timestamp import Timestamp
from slither.detectors.statements.calls_in_loop import MultipleCallsInLoop
from slither.detectors.statements.incorrect_strict_equality import IncorrectStrictEquality
detectors = [Backdoor,
UninitializedStateVarsDetection,
@ -162,7 +162,8 @@ def get_detectors_and_printers():
ShadowingAbstractDetection,
StateShadowing,
Timestamp,
MultipleCallsInLoop]
MultipleCallsInLoop,
IncorrectStrictEquality]
from slither.printers.summary.function import FunctionSummary
from slither.printers.summary.contract import ContractSummary

@ -0,0 +1,119 @@
"""
Module detecting dangerous strict equality
"""
import itertools
from slither.analyses.data_dependency.data_dependency import is_dependent_ssa
from slither.core.declarations import Function
from slither.detectors.abstract_detector import (AbstractDetector,
DetectorClassification)
from slither.slithir.operations import (Assignment, Balance, Binary, BinaryType,
HighLevelCall)
from slither.core.solidity_types import MappingType, ElementaryType
from slither.core.variables.state_variable import StateVariable
from slither.core.declarations.solidity_variables import SolidityVariable, SolidityVariableComposed
from slither.slithir.variables import ReferenceVariable
class IncorrectStrictEquality(AbstractDetector):
ARGUMENT = 'incorrect-equality'
HELP = 'Dangerous strict equalities'
IMPACT = DetectorClassification.MEDIUM
CONFIDENCE = DetectorClassification.HIGH
WIKI = 'https://github.com/trailofbits/slither/wiki/Vulnerabilities-Description#dangerous-strict-equalities'
sources_taint = [SolidityVariable('now'),
SolidityVariableComposed('block.number'),
SolidityVariableComposed('block.timestamp')]
@staticmethod
def is_direct_comparison(ir):
return isinstance(ir, Binary) and ir.type == BinaryType.EQUAL
@staticmethod
def is_any_tainted(variables, taints, function):
return any([is_dependent_ssa(var, taint, function.contract) for var in variables for taint in taints])
def taint_balance_equalities(self, functions):
taints = []
for func in functions:
for node in func.nodes:
for ir in node.irs_ssa:
if isinstance(ir, Balance):
taints.append(ir.lvalue)
if isinstance(ir, HighLevelCall):
#print(ir.function.full_name)
if isinstance(ir.function, Function) and\
ir.function.full_name == 'balanceOf(address)':
taints.append(ir.lvalue)
if isinstance(ir.function, StateVariable) and\
isinstance(ir.function.type, MappingType) and\
ir.function.name == 'balanceOf' and\
ir.function.type.type_from == ElementaryType('address') and\
ir.function.type.type_to == ElementaryType('uint256'):
taints.append(ir.lvalue)
if isinstance(ir, Assignment):
if ir.rvalue in self.sources_taint:
taints.append(ir.lvalue)
return taints
# Retrieve all tainted (node, function) pairs
def tainted_equality_nodes(self, funcs, taints):
results = dict()
taints += self.sources_taint
for func in funcs:
for node in func.nodes:
for ir in node.irs_ssa:
# Filter to only tainted equality (==) comparisons
if self.is_direct_comparison(ir) and self.is_any_tainted(ir.used, taints, func):
if func not in results:
results[func] = []
results[func].append(node)
return results
def detect_strict_equality(self, contract):
funcs = contract.all_functions_called + contract.modifiers
# Taint all BALANCE accesses
taints = self.taint_balance_equalities(funcs)
# Accumulate tainted (node,function) pairs involved in strict equality (==) comparisons
results = self.tainted_equality_nodes(funcs, taints)
return results
def detect(self):
results = []
for c in self.slither.contracts_derived:
ret = self.detect_strict_equality(c)
info = ''
# sort ret to get deterministic results
ret = sorted(list(ret.items()), key=lambda x:x[0].name)
for f, nodes in ret:
info += "{}.{} ({}) uses a dangerous strict equality:\n".format(f.contract.name,
f.name,
f.source_mapping_str)
# sort the nodes to get deterministic results
nodes.sort(key=lambda x: x.node_id)
for node in nodes:
info += "\t- {}\n".format(str(node.expression))
json = self.generate_json_result(info)
self.add_function_to_json(f, json)
self.add_nodes_to_json(nodes, json)
results.append(json)
if info:
self.log(info)
return results

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save