From 700794971ba6bb1d905c6de171331dbd265619e3 Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Thu, 5 Oct 2023 14:27:28 +0200 Subject: [PATCH 1/6] Release 2 new detectors --- slither/detectors/all_detectors.py | 2 + .../detectors/assembly/incorrect_return.py | 91 ++++++++++++++++++ .../assembly/return_instead_of_leave.py | 64 ++++++++++++ ...tReturn_0_8_10_incorrect_return_sol__0.txt | 4 + ...OfLeave_0_8_10_incorrect_return_sol__0.txt | 2 + .../0.8.10/incorrect_return.sol | 36 +++++++ .../0.8.10/incorrect_return.sol-0.8.10.zip | Bin 0 -> 2892 bytes .../return-leave/0.8.10/incorrect_return.sol | 8 ++ .../0.8.10/incorrect_return.sol-0.8.10.zip | Bin 0 -> 1445 bytes tests/e2e/detectors/test_detectors.py | 10 ++ tests/e2e/solc_parsing/test_ast_parsing.py | 8 +- 11 files changed, 221 insertions(+), 4 deletions(-) create mode 100644 slither/detectors/assembly/incorrect_return.py create mode 100644 slither/detectors/assembly/return_instead_of_leave.py create mode 100644 tests/e2e/detectors/snapshots/detectors__detector_IncorrectReturn_0_8_10_incorrect_return_sol__0.txt create mode 100644 tests/e2e/detectors/snapshots/detectors__detector_ReturnInsteadOfLeave_0_8_10_incorrect_return_sol__0.txt create mode 100644 tests/e2e/detectors/test_data/incorrect-return/0.8.10/incorrect_return.sol create mode 100644 tests/e2e/detectors/test_data/incorrect-return/0.8.10/incorrect_return.sol-0.8.10.zip create mode 100644 tests/e2e/detectors/test_data/return-leave/0.8.10/incorrect_return.sol create mode 100644 tests/e2e/detectors/test_data/return-leave/0.8.10/incorrect_return.sol-0.8.10.zip diff --git a/slither/detectors/all_detectors.py b/slither/detectors/all_detectors.py index 57f44bc56e..4a111bb64a 100644 --- a/slither/detectors/all_detectors.py +++ b/slither/detectors/all_detectors.py @@ -92,3 +92,5 @@ from .operations.cache_array_length import CacheArrayLength from .statements.incorrect_using_for import IncorrectUsingFor from .operations.encode_packed import EncodePackedCollision +from .assembly.incorrect_return import IncorrectReturn +from .assembly.return_instead_of_leave import ReturnInsteadOfLeave diff --git a/slither/detectors/assembly/incorrect_return.py b/slither/detectors/assembly/incorrect_return.py new file mode 100644 index 0000000000..dc1868e646 --- /dev/null +++ b/slither/detectors/assembly/incorrect_return.py @@ -0,0 +1,91 @@ +from typing import List, Optional + +from slither.core.declarations import SolidityFunction, Function +from slither.detectors.abstract_detector import ( + AbstractDetector, + DetectorClassification, + DETECTOR_INFO, +) +from slither.slithir.operations import SolidityCall +from slither.utils.output import Output + + +def _assembly_node(function: Function) -> Optional[SolidityCall]: + """ + Check if there is a node that use return in assembly + + Args: + function: + + Returns: + + """ + + for ir in function.all_slithir_operations(): + if isinstance(ir, SolidityCall) and ir.function == SolidityFunction( + "return(uint256,uint256)" + ): + return ir + return None + + +class IncorrectReturn(AbstractDetector): + """ + Check for cases where a return(a,b) is used in an assembly function + """ + + ARGUMENT = "incorrect-return" + HELP = "If a `return` is incorrectly used in assembly mode." + IMPACT = DetectorClassification.HIGH + CONFIDENCE = DetectorClassification.MEDIUM + + WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-assembly-return" + + WIKI_TITLE = "Incorrect return in assembly" + WIKI_DESCRIPTION = "Detect if `return` in an assembly block halts unexpectedly the execution." + WIKI_EXPLOIT_SCENARIO = """ +```solidity +contract C { + function f() internal returns (uint a, uint b) { + assembly { + return (5, 6) + } + } + + function g() returns (bool){ + f(); + return true; + } +} +``` +The return statement in `f` will cause execution in `g` to halt. +The function will return 6 bytes starting from offset 5, instead of returning a boolean.""" + + WIKI_RECOMMENDATION = "Use the `leave` statement." + + # pylint: disable=too-many-nested-blocks + def _detect(self) -> List[Output]: + results: List[Output] = [] + for c in self.contracts: + for f in c.functions_declared: + + for node in f.nodes: + if node.sons: + for function_called in node.internal_calls: + if isinstance(function_called, Function): + found = _assembly_node(function_called) + if found: + + info: DETECTOR_INFO = [ + f, + " calls ", + function_called, + " which halt the execution ", + found.node, + "\n", + ] + json = self.generate_result(info) + + results.append(json) + + return results diff --git a/slither/detectors/assembly/return_instead_of_leave.py b/slither/detectors/assembly/return_instead_of_leave.py new file mode 100644 index 0000000000..74c377d400 --- /dev/null +++ b/slither/detectors/assembly/return_instead_of_leave.py @@ -0,0 +1,64 @@ +from typing import List + +from slither.core.declarations import SolidityFunction, Function +from slither.detectors.abstract_detector import ( + AbstractDetector, + DetectorClassification, + DETECTOR_INFO, +) +from slither.slithir.operations import SolidityCall +from slither.utils.output import Output + + +class ReturnInsteadOfLeave(AbstractDetector): + """ + Check for cases where a return(a,b) is used in an assembly function that also returns two variables + """ + + ARGUMENT = "return-leave" + HELP = "If a `return` is used instead of a `leave`." + IMPACT = DetectorClassification.HIGH + CONFIDENCE = DetectorClassification.MEDIUM + + WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-assembly-return" + + WIKI_TITLE = "Return instead of leave in assembly" + WIKI_DESCRIPTION = "Detect if a `return` is used where a `leave` should be used." + WIKI_EXPLOIT_SCENARIO = """ +```solidity +contract C { + function f() internal returns (uint a, uint b) { + assembly { + return (5, 6) + } + } + +} +``` +The function will halt the execution, instead of returning a two uint.""" + + WIKI_RECOMMENDATION = "Use the `leave` statement." + + def _check_function(self, f: Function) -> List[Output]: + results: List[Output] = [] + + for node in f.nodes: + for ir in node.irs: + if isinstance(ir, SolidityCall) and ir.function == SolidityFunction( + "return(uint256,uint256)" + ): + info: DETECTOR_INFO = [f, " contains an incorrect call to return: ", node, "\n"] + json = self.generate_result(info) + + results.append(json) + return results + + def _detect(self) -> List[Output]: + results: List[Output] = [] + for c in self.contracts: + for f in c.functions_declared: + + if len(f.returns) == 2 and f.contains_assembly: + results += self._check_function(f) + + return results diff --git a/tests/e2e/detectors/snapshots/detectors__detector_IncorrectReturn_0_8_10_incorrect_return_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_IncorrectReturn_0_8_10_incorrect_return_sol__0.txt new file mode 100644 index 0000000000..5d87cd932d --- /dev/null +++ b/tests/e2e/detectors/snapshots/detectors__detector_IncorrectReturn_0_8_10_incorrect_return_sol__0.txt @@ -0,0 +1,4 @@ +C.bad1() (tests/e2e/detectors/test_data/incorrect-return/0.8.10/incorrect_return.sol#21-24) calls C.indirect() (tests/e2e/detectors/test_data/incorrect-return/0.8.10/incorrect_return.sol#17-19) which halt the execution return(uint256,uint256)(5,6) (tests/e2e/detectors/test_data/incorrect-return/0.8.10/incorrect_return.sol#4) + +C.bad0() (tests/e2e/detectors/test_data/incorrect-return/0.8.10/incorrect_return.sol#8-11) calls C.internal_return() (tests/e2e/detectors/test_data/incorrect-return/0.8.10/incorrect_return.sol#2-6) which halt the execution return(uint256,uint256)(5,6) (tests/e2e/detectors/test_data/incorrect-return/0.8.10/incorrect_return.sol#4) + diff --git a/tests/e2e/detectors/snapshots/detectors__detector_ReturnInsteadOfLeave_0_8_10_incorrect_return_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_ReturnInsteadOfLeave_0_8_10_incorrect_return_sol__0.txt new file mode 100644 index 0000000000..28f579f818 --- /dev/null +++ b/tests/e2e/detectors/snapshots/detectors__detector_ReturnInsteadOfLeave_0_8_10_incorrect_return_sol__0.txt @@ -0,0 +1,2 @@ +C.f() (tests/e2e/detectors/test_data/return-leave/0.8.10/incorrect_return.sol#3-7) contains an incorrect call to return: return(uint256,uint256)(5,6) (tests/e2e/detectors/test_data/return-leave/0.8.10/incorrect_return.sol#5) + diff --git a/tests/e2e/detectors/test_data/incorrect-return/0.8.10/incorrect_return.sol b/tests/e2e/detectors/test_data/incorrect-return/0.8.10/incorrect_return.sol new file mode 100644 index 0000000000..e81a747ba1 --- /dev/null +++ b/tests/e2e/detectors/test_data/incorrect-return/0.8.10/incorrect_return.sol @@ -0,0 +1,36 @@ +contract C { + function internal_return() internal{ + assembly { + return (5, 6) + } + } + + function bad0() public returns (bool){ + internal_return(); + return true; + } + + function indirect2() internal { + internal_return(); + } + + function indirect() internal { + indirect2(); + } + + function bad1() public returns (bool){ + indirect(); + return true; + } + + function good0() public{ + // Dont report if there is no following operation + internal_return(); + } + + function good1() public returns (uint a, uint b){ + assembly { + return (5, 6) + } + } +} \ No newline at end of file diff --git a/tests/e2e/detectors/test_data/incorrect-return/0.8.10/incorrect_return.sol-0.8.10.zip b/tests/e2e/detectors/test_data/incorrect-return/0.8.10/incorrect_return.sol-0.8.10.zip new file mode 100644 index 0000000000000000000000000000000000000000..2491a10a6554d40be21373fc9f7eeb55ceb9f46e GIT binary patch literal 2892 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 literal 0 HcmV?d00001 diff --git a/tests/e2e/detectors/test_detectors.py b/tests/e2e/detectors/test_detectors.py index 6fc04e4e1f..9ca1bfcde9 100644 --- a/tests/e2e/detectors/test_detectors.py +++ b/tests/e2e/detectors/test_detectors.py @@ -1654,6 +1654,16 @@ def id_test(test_item: Test): "encode_packed_collision.sol", "0.7.6", ), + Test( + all_detectors.IncorrectReturn, + "incorrect_return.sol", + "0.8.10", + ), + Test( + all_detectors.ReturnInsteadOfLeave, + "incorrect_return.sol", + "0.8.10", + ), ] GENERIC_PATH = "/GENERIC_PATH" diff --git a/tests/e2e/solc_parsing/test_ast_parsing.py b/tests/e2e/solc_parsing/test_ast_parsing.py index 2da4cf1e26..37f6d7274b 100644 --- a/tests/e2e/solc_parsing/test_ast_parsing.py +++ b/tests/e2e/solc_parsing/test_ast_parsing.py @@ -4,13 +4,13 @@ import sys from pathlib import Path from typing import List, Dict, Tuple -from packaging.version import parse as parse_version -import pytest + +from crytic_compile import CryticCompile, save_to_zip +from crytic_compile.utils.zip import load_from_zip from deepdiff import DeepDiff +from packaging.version import parse as parse_version from solc_select.solc_select import install_artifacts as install_solc_versions from solc_select.solc_select import installed_versions as get_installed_solc_versions -from crytic_compile import CryticCompile, save_to_zip -from crytic_compile.utils.zip import load_from_zip from slither import Slither from slither.printers.guidance.echidna import Echidna From 561a6f88d01ba4f3478dc12c74a63ed9b70f336c Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Thu, 5 Oct 2023 15:01:35 +0200 Subject: [PATCH 2/6] Update slither/detectors/assembly/incorrect_return.py Co-authored-by: alpharush <0xalpharush@protonmail.com> --- slither/detectors/assembly/incorrect_return.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither/detectors/assembly/incorrect_return.py b/slither/detectors/assembly/incorrect_return.py index dc1868e646..f5f0a98d9d 100644 --- a/slither/detectors/assembly/incorrect_return.py +++ b/slither/detectors/assembly/incorrect_return.py @@ -67,7 +67,7 @@ class IncorrectReturn(AbstractDetector): def _detect(self) -> List[Output]: results: List[Output] = [] for c in self.contracts: - for f in c.functions_declared: + for f in c.functions_and_modifiers_declared: for node in f.nodes: if node.sons: From 4d738ec358c394d7cf7d056d0095ce2673f50166 Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Wed, 11 Oct 2023 09:56:10 +0200 Subject: [PATCH 3/6] Minor --- slither/detectors/assembly/return_instead_of_leave.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/slither/detectors/assembly/return_instead_of_leave.py b/slither/detectors/assembly/return_instead_of_leave.py index 74c377d400..a1591d834b 100644 --- a/slither/detectors/assembly/return_instead_of_leave.py +++ b/slither/detectors/assembly/return_instead_of_leave.py @@ -58,7 +58,11 @@ def _detect(self) -> List[Output]: for c in self.contracts: for f in c.functions_declared: - if len(f.returns) == 2 and f.contains_assembly: + if ( + len(f.returns) == 2 + and f.contains_assembly + and f.visibility not in ["public", "external"] + ): results += self._check_function(f) return results From f7ab4a734fb93433eca7afa4e867acafbeb05605 Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Wed, 11 Oct 2023 10:12:41 +0200 Subject: [PATCH 4/6] Add incorrect-exp detector --- slither/detectors/operations/incorrect_exp.py | 0 ...onentiation_0_7_6_incorrect_exp_sol__0.txt | 9 ++++++ .../incorrect-exp/0.7.6/incorrect_exp.sol | 30 ++++++++++++++++++ .../0.7.6/incorrect_exp.sol-0.7.6.zip | Bin 0 -> 2473 bytes 4 files changed, 39 insertions(+) create mode 100644 slither/detectors/operations/incorrect_exp.py create mode 100644 tests/e2e/detectors/snapshots/detectors__detector_IncorrectOperatorExponentiation_0_7_6_incorrect_exp_sol__0.txt create mode 100644 tests/e2e/detectors/test_data/incorrect-exp/0.7.6/incorrect_exp.sol create mode 100644 tests/e2e/detectors/test_data/incorrect-exp/0.7.6/incorrect_exp.sol-0.7.6.zip diff --git a/slither/detectors/operations/incorrect_exp.py b/slither/detectors/operations/incorrect_exp.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/e2e/detectors/snapshots/detectors__detector_IncorrectOperatorExponentiation_0_7_6_incorrect_exp_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_IncorrectOperatorExponentiation_0_7_6_incorrect_exp_sol__0.txt new file mode 100644 index 0000000000..458dd3bdcd --- /dev/null +++ b/tests/e2e/detectors/snapshots/detectors__detector_IncorrectOperatorExponentiation_0_7_6_incorrect_exp_sol__0.txt @@ -0,0 +1,9 @@ +Test.bad1() (tests/e2e/detectors/test_data/incorrect-exp/0.7.6/incorrect_exp.sol#9-12) has bitwise-xor operator ^ instead of the exponentiation operator **: + - UINT_MAX = 2 ^ 256 - 1 (tests/e2e/detectors/test_data/incorrect-exp/0.7.6/incorrect_exp.sol#10) + +Test.bad0(uint256) (tests/e2e/detectors/test_data/incorrect-exp/0.7.6/incorrect_exp.sol#5-7) has bitwise-xor operator ^ instead of the exponentiation operator **: + - a ^ 2 (tests/e2e/detectors/test_data/incorrect-exp/0.7.6/incorrect_exp.sol#6) + +Derived.slitherConstructorVariables() (tests/e2e/detectors/test_data/incorrect-exp/0.7.6/incorrect_exp.sol#30) has bitwise-xor operator ^ instead of the exponentiation operator **: + - my_var = 2 ^ 256 - 1 (tests/e2e/detectors/test_data/incorrect-exp/0.7.6/incorrect_exp.sol#3) + diff --git a/tests/e2e/detectors/test_data/incorrect-exp/0.7.6/incorrect_exp.sol b/tests/e2e/detectors/test_data/incorrect-exp/0.7.6/incorrect_exp.sol new file mode 100644 index 0000000000..b930ee5c1f --- /dev/null +++ b/tests/e2e/detectors/test_data/incorrect-exp/0.7.6/incorrect_exp.sol @@ -0,0 +1,30 @@ +contract Test { + + uint my_var = 2 ^ 256-1; + + function bad0(uint a) internal returns (uint) { + return a^2; + } + + function bad1() internal returns (uint) { + uint UINT_MAX = 2^256-1; + return UINT_MAX; + } + + /* Correct exponentiation operator */ + function good0(uint a) internal returns (uint) { + return a**2; + } + + /* Neither operand is a constant */ + function good1(uint a) internal returns (uint) { + return a^a; + } + + /* The constant operand 0xff in hex typically means bitwise xor */ + function good2(uint a) internal returns (uint) { + return a^0xff; + } +} + +contract Derived is Test {} diff --git a/tests/e2e/detectors/test_data/incorrect-exp/0.7.6/incorrect_exp.sol-0.7.6.zip b/tests/e2e/detectors/test_data/incorrect-exp/0.7.6/incorrect_exp.sol-0.7.6.zip new file mode 100644 index 0000000000000000000000000000000000000000..c6fea01511ee4ecf31db7b382c3ca0f81ef8bd15 GIT binary patch literal 2473 zcma);`8U)H1IE80#!|+f7=|$n*~z|4Mac-mMY0YivKz~_G_sGx*hSYi3Af>52-$VZ zmUZk)MpE`QveR4d@9#P9^Zf8R&pFQ@@G(WvGw1?zz-2%ajk21?2^5}z03g~30N?-s zJo0w-!QrsZ0S?$;Us-=2&)@XH1vp@E&Tfx_u(Iy{KHkg>7Xdo}hyVcX_;^>PQzbvr z@IamBrQ8nhNANbG*d(*7I>HnFExZc5tA(F|rHkV~MlaLp;je?<-aOxsjfTl}^s>-t zUqr-no=ivx42eD3RF{{h7|4x0u0MU(@a!X`poZ9=ZhDxN!92n_;}W#BMNUXsec^bE z#fu|Xn&`Kleyu<%PBN1usF!TSz(a80d%mR5qHGGLSKPjW)o?J^2nW#P5_*+Syx(uE4Z7ec(nf3?Y`oDLXNx8+Ey!MU?w+rKBIzp5@Eq5U7-;Ub1f)G8U54_02*F|7zJKra3|~b`zgTGEkVZ zC7t&F*wo&wWcMeo!Ly<}h2&J&n&au0KX-^(I6Se@F-P2Rrl5+nSvQW|WYC?pv{Nsi z2*gsWpNgtd{iFuh__QY_nTYTC(0^a%>~E)GlP8GTQ^6;6q`MTGj&OzQxuh zl$YpUaj$NSNA7EqnckDMEw@GgnM?7lYh7G2o;dFZp}y_PsQq?%Bv`pP>dhKWEVCL^&ATIw;={?s)hmzm<ort6JLG7eTx=o7pz}Bq_UqKY_c&e0HJoFWQcoew-`U=26qbI7i_oF!yRMN((lVirZ{TO4}6JDWv%)Bs#<>PZ>102Sq z%TfT|)yQpy+M9C;PR%vkOYO1Q3+A?uA3W{6`ubgwd#7uwqg}WVw?oXIyth(43s;(j z@Dfs z5{83?1#{6eT;xY;f}k0cA@c7z3^$zceB~&phNun@bKDx-L_aC8;Gip8_-xR#q!Cv> z2h#q)cXtVzG!{EaiJE2jk$eij{^@S2k|^)l$I(IT2-M5+s1VkT?DoiySqwUKajJf& zXj>lk2ZXoPZHr6`Hl4HRUl-b-=a`b2*d|oO@Kli}r~8*<_&yw2ps6Pu*l5w4Mos+| zN*x>AHC&)?&-oU$+sR1O$v*Ao{wB8>Bc9|dG~qO<&|Z>7%=W*PZ@g4uQ|>nHEFB4^ zeuiPn?h z@j&7xSR|D0umM`S!n)Z49SLCk7V6csKI~{{Qt;D7(P8aHHt4m-0GraKUGEWW`d!{& zW;lx7Lp{7>UGGh!Kcn|DeN7g{<|s6+iGbhydFL^ha~OFoHw{q`9z57Fg6@}_qw%x) zx1e6mUGG!TVu~v|!HUI6J$2y1oP>Kl%cfNYmS#AD?{yq)$IWMicDUYd@*e%F{ZtVx zbmd_D==|WWGif_?3_l2JC_FTCK6Q{zZPFDQUlo$ciqi(t1lgxmk}nr9BEzGFpQF zBnQ$nQ1DtwfB0Q#EZ%pWw+-~u{fDou?X3-Q+hr2!GTyEsfPOtgP90;+F|D~rUriNy zoJO%z(n=(C5v(%aERZJ%rNsk0oraPVn-MxNabK?C1=PZC0(lcFC`a_(uu`}kE; zLY5uC+TH`gpBGxgGovbx@Ivf7bBSxm%0J+`NFT7|00t4_xcY(s-6r0 literal 0 HcmV?d00001 From 4d1d32b63fd06eeba69af35cd64680bfa2338167 Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Wed, 11 Oct 2023 10:22:27 +0200 Subject: [PATCH 5/6] Add tautological-compare --- slither/detectors/all_detectors.py | 2 + slither/detectors/operations/incorrect_exp.py | 93 ++++++++++++++++++ .../statements/tautological_compare.py | 69 +++++++++++++ .../tautological-compare/0.8.20/compare.sol | 6 ++ .../0.8.20/compare.sol-0.8.20.zip | Bin 0 -> 2032 bytes tests/e2e/detectors/test_detectors.py | 10 ++ 6 files changed, 180 insertions(+) create mode 100644 slither/detectors/statements/tautological_compare.py create mode 100644 tests/e2e/detectors/test_data/tautological-compare/0.8.20/compare.sol create mode 100644 tests/e2e/detectors/test_data/tautological-compare/0.8.20/compare.sol-0.8.20.zip diff --git a/slither/detectors/all_detectors.py b/slither/detectors/all_detectors.py index 4a111bb64a..97622f8878 100644 --- a/slither/detectors/all_detectors.py +++ b/slither/detectors/all_detectors.py @@ -94,3 +94,5 @@ from .operations.encode_packed import EncodePackedCollision from .assembly.incorrect_return import IncorrectReturn from .assembly.return_instead_of_leave import ReturnInsteadOfLeave +from .operations.incorrect_exp import IncorrectOperatorExponentiation +from .statements.tautological_compare import TautologicalCompare diff --git a/slither/detectors/operations/incorrect_exp.py b/slither/detectors/operations/incorrect_exp.py index e69de29bb2..6188f5cb16 100644 --- a/slither/detectors/operations/incorrect_exp.py +++ b/slither/detectors/operations/incorrect_exp.py @@ -0,0 +1,93 @@ +""" +Module detecting incorrect operator usage for exponentiation where bitwise xor '^' is used instead of '**' +""" +from typing import Tuple, List, Union + +from slither.core.cfg.node import Node +from slither.core.declarations import Contract, Function +from slither.detectors.abstract_detector import ( + AbstractDetector, + DetectorClassification, + DETECTOR_INFO, +) +from slither.slithir.operations import Binary, BinaryType, Operation +from slither.slithir.utils.utils import RVALUE +from slither.slithir.variables.constant import Constant +from slither.utils.output import Output + + +def _is_constant_candidate(var: Union[RVALUE, Function]) -> bool: + """ + Check if the variable is a constant. + Do not consider variable that are expressed with hexadecimal. + Something like 2^0xf is likely to be a correct bitwise operator + :param var: + :return: + """ + return isinstance(var, Constant) and not var.original_value.startswith("0x") + + +def _is_bitwise_xor_on_constant(ir: Operation) -> bool: + return ( + isinstance(ir, Binary) + and ir.type == BinaryType.CARET + and (_is_constant_candidate(ir.variable_left) or _is_constant_candidate(ir.variable_right)) + ) + + +def _detect_incorrect_operator(contract: Contract) -> List[Tuple[Function, Node]]: + ret: List[Tuple[Function, Node]] = [] + f: Function + for f in contract.functions + contract.modifiers: # type:ignore + # Heuristic: look for binary expressions with ^ operator where at least one of the operands is a constant, and + # the constant is not in hex, because hex typically is used with bitwise xor and not exponentiation + nodes = [node for node in f.nodes for ir in node.irs if _is_bitwise_xor_on_constant(ir)] + for node in nodes: + ret.append((f, node)) + return ret + + +# pylint: disable=too-few-public-methods +class IncorrectOperatorExponentiation(AbstractDetector): + """ + Incorrect operator usage of bitwise xor mistaking it for exponentiation + """ + + ARGUMENT = "incorrect-exp" + HELP = "Incorrect exponentiation" + IMPACT = DetectorClassification.HIGH + CONFIDENCE = DetectorClassification.MEDIUM + + WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-exponentiation" + + WIKI_TITLE = "Incorrect exponentiation" + WIKI_DESCRIPTION = "Detect use of bitwise `xor ^` instead of exponential `**`" + WIKI_EXPLOIT_SCENARIO = """ +```solidity +contract Bug{ + uint UINT_MAX = 2^256 - 1; + ... +} +``` +Alice deploys a contract in which `UINT_MAX` incorrectly uses `^` operator instead of `**` for exponentiation""" + + WIKI_RECOMMENDATION = "Use the correct operator `**` for exponentiation." + + def _detect(self) -> List[Output]: + """Detect the incorrect operator usage for exponentiation where bitwise xor ^ is used instead of ** + + Returns: + list: (function, node) + """ + results: List[Output] = [] + for c in self.compilation_unit.contracts_derived: + res = _detect_incorrect_operator(c) + for (func, node) in res: + info: DETECTOR_INFO = [ + func, + " has bitwise-xor operator ^ instead of the exponentiation operator **: \n", + ] + info += ["\t - ", node, "\n"] + results.append(self.generate_result(info)) + + return results diff --git a/slither/detectors/statements/tautological_compare.py b/slither/detectors/statements/tautological_compare.py new file mode 100644 index 0000000000..0dc34b582f --- /dev/null +++ b/slither/detectors/statements/tautological_compare.py @@ -0,0 +1,69 @@ +from typing import List +from slither.detectors.abstract_detector import ( + AbstractDetector, + DetectorClassification, + DETECTOR_INFO, +) +from slither.slithir.operations import ( + Binary, + BinaryType, +) + +from slither.core.declarations import Function +from slither.utils.output import Output + + +class TautologicalCompare(AbstractDetector): + """ + Same variable comparison detector + """ + + ARGUMENT = "tautological-compare" + HELP = "Comparing a variable to itself always returns true or false, depending on comparison" + IMPACT = DetectorClassification.MEDIUM + CONFIDENCE = DetectorClassification.HIGH + + WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#tautological-compare" + + WIKI_TITLE = "Tautological compare" + WIKI_DESCRIPTION = "A variable compared to itself is probably an error as it will always return `true` for `==`, `>=`, `<=` and always `false` for `<`, `>` and `!=`." + WIKI_EXPLOIT_SCENARIO = """ +```solidity + function check(uint a) external returns(bool){ + return (a >= a); + } +``` +`check` always return true.""" + + WIKI_RECOMMENDATION = "Remove comparison or compare to different value." + + def _check_function(self, f: Function) -> List[Output]: + affected_nodes = set() + for node in f.nodes: + for ir in node.irs: + if isinstance(ir, Binary): + if ir.type in [ + BinaryType.GREATER, + BinaryType.GREATER_EQUAL, + BinaryType.LESS, + BinaryType.LESS_EQUAL, + BinaryType.EQUAL, + BinaryType.NOT_EQUAL, + ]: + if ir.variable_left == ir.variable_right: + affected_nodes.add(node) + + results = [] + for n in affected_nodes: + info: DETECTOR_INFO = [f, " compares a variable to itself:\n\t", n, "\n"] + res = self.generate_result(info) + results.append(res) + return results + + def _detect(self): + results = [] + + for f in self.compilation_unit.functions_and_modifiers: + results.extend(self._check_function(f)) + + return results diff --git a/tests/e2e/detectors/test_data/tautological-compare/0.8.20/compare.sol b/tests/e2e/detectors/test_data/tautological-compare/0.8.20/compare.sol new file mode 100644 index 0000000000..ede2f0fc18 --- /dev/null +++ b/tests/e2e/detectors/test_data/tautological-compare/0.8.20/compare.sol @@ -0,0 +1,6 @@ + +contract A{ + function check(uint a) external returns(bool){ + return (a >= a); + } +} \ No newline at end of file diff --git a/tests/e2e/detectors/test_data/tautological-compare/0.8.20/compare.sol-0.8.20.zip b/tests/e2e/detectors/test_data/tautological-compare/0.8.20/compare.sol-0.8.20.zip new file mode 100644 index 0000000000000000000000000000000000000000..05b78fad0871c604d79bcb87bb5f0eeedc3d9cea GIT binary patch literal 2032 zcmai#Ydq5n1IPb!zvQ|~mSgS;F_(o!ZiUX!TneqR4(58yZA3)I*$fpO#By1YCYR){ z4JnkJL<%7?xuhl6i5XAldH;N#-|xlu&F}5+^F<*Ag{%MpKpME}hV&F8q}*yfd%1_&G*s*XOiGzt+spL^@-{RJuC?U zOW|W=dETh@(Ls&iWpfy;frU3%KGpG*H;lXJ;86DmMT}pba9fAb#e5Hm9%^zgfToc6 zeu~N2E1ww0{(@Ps42^Yf$2D|g#9y@4MDs+O|Fqn^VRM^E%HH&T%5_aPyWHNNZp00m zZ<*6Hk!ly;mRU&1!COHSR6i-ogDY_>CkmXh+ov7f)iHCqp?-W&2c-%d|4fZ%Uq2Iv zGg>Np8MtwB$PTSkW?6KI8RY2P;b)T|hYQgcOpQ^(EO5EVxBj7>u zD^itIwwv>j0A9^c};AP!!gw z5|^os{ZO)YdnoVH=Ymad?uJe=?UI*914S{~?{*j(D>Op-w z4FVU-y+7=BCxGVM1^ih*KfqcDtFjKL`!0g?UOoALyjH52UfP-uH*`bYyBG-i#-M^ZG#jhJB8@bFWJTTW?R7irU|p`e^th7~%27IX7MGOUX+_HD?x&A4`=n-X2}f3#oc9*a~C44wG(|jA`6S0dhJb%-AwTKH;3K-A6dyZ}lT? ztGRHH0s9s-$gR*pw`y`hfhY-bRV|+No>DX-=hXMOjKPdYjiIS~mz1kVH@dczo%JK1 zXMy&j3Jq(i6{qcU*0bug!bU2Q?Dm<(i>UJ5io2+>eaS`aFr{z7PGiwG{-6p<)LeXt z6Ca-m|5WEn|LsU+t&dX;0U_soyn<1m#pPbGzehz`usV<9Njov;&}b`f2=3%tQ|(nO zartbkKD75Jjh)ctP>?JhZg*WPU7lt6BQNKNx-31ZqtaN}WQV_z+4%E?$BVThMNal7 z0oB!)0BrB{iu+~4-oqB%yl+(;uM(Vs(V-$ArROA*DhQ_8e)Bc5v4E6kr^yJx%=eFF zs&!scO_ZpgLx2N=ZhF7SbvV}=u*4gW5DXYHT)Jf*=xN#!G1B{GsX0FW2;l@}j+tO$ z8N-?0?lU$0=NmXE`A6uiS1#~!@Na9meU&L9aXf*c;&^u)Rjy}Xq3>5V5i9aXE{;BS z+>9m`?yCki2b64uFSAhZl z)TnTxb<0|q6I`z(P5QtaO7vL*FW=xBC2fF1b#YUbAy~}B38exy*OGajmTit|-%7*n zRIdB)U)3N_e-=<$hln;z*&Q-_9ahu0R@QX5ME((#oc>@@07a8Bt(<^qkNO zwpC1Ble02@3dL(SmJ2+CxnA2ox#GT03uP^j`&wT=@ar^c<4!#n=`~Y_E5VLn!7H&O zxS1*@(hQ1OT9}z_L$5OjGz?gf)bKE;vT)aek~}R5C!s{xW33bqx}(|v+nukvBg%QY zk;HXQ(2ud5bL(W08`xaC=}_BtjqPZIZnsgs2>Q(qFe$$_V@k z#=(Q>^(XF=15FMz5cWLGd^Rbzwe1JU_N+VxUy;+2k*1PSxPFzdH@R;9I1xN)h(0gW z>hY+B#Ay0HiPxPheus=?A5KU0w{`7gzA5mX;k*w>$+YVYNTU$rl!M>(7I@X7X)%>0IU=`u< z6}c5DKG=N08qNfNeZ}14t6ig_kRSmo!T+t}Uq=3KQb7OW|Hv7I6c+h+2KrU!U(EjH HbpZGeo!!Aw literal 0 HcmV?d00001 diff --git a/tests/e2e/detectors/test_detectors.py b/tests/e2e/detectors/test_detectors.py index 9ca1bfcde9..99e9095fff 100644 --- a/tests/e2e/detectors/test_detectors.py +++ b/tests/e2e/detectors/test_detectors.py @@ -1664,6 +1664,16 @@ def id_test(test_item: Test): "incorrect_return.sol", "0.8.10", ), + Test( + all_detectors.IncorrectOperatorExponentiation, + "incorrect_exp.sol", + "0.7.6", + ), + Test( + all_detectors.TautologicalCompare, + "compare.sol", + "0.8.20", + ), ] GENERIC_PATH = "/GENERIC_PATH" From 538539ba9e9eb97a3ffbba87e181cb8118d40df7 Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Wed, 11 Oct 2023 10:32:42 +0200 Subject: [PATCH 6/6] Add return-bomb detector --- slither/detectors/all_detectors.py | 1 + slither/detectors/statements/return_bomb.py | 123 ++++++++++++++++++ ...r_ReturnBomb_0_8_20_return_bomb_sol__0.txt | 5 + ...tologicalCompare_0_8_20_compare_sol__0.txt | 3 + .../return-bomb/0.8.20/return_bomb.sol | 57 ++++++++ .../0.8.20/return_bomb.sol-0.8.20.zip | Bin 0 -> 7966 bytes tests/e2e/detectors/test_detectors.py | 5 + 7 files changed, 194 insertions(+) create mode 100644 slither/detectors/statements/return_bomb.py create mode 100644 tests/e2e/detectors/snapshots/detectors__detector_ReturnBomb_0_8_20_return_bomb_sol__0.txt create mode 100644 tests/e2e/detectors/snapshots/detectors__detector_TautologicalCompare_0_8_20_compare_sol__0.txt create mode 100644 tests/e2e/detectors/test_data/return-bomb/0.8.20/return_bomb.sol create mode 100644 tests/e2e/detectors/test_data/return-bomb/0.8.20/return_bomb.sol-0.8.20.zip diff --git a/slither/detectors/all_detectors.py b/slither/detectors/all_detectors.py index 97622f8878..fab9562d20 100644 --- a/slither/detectors/all_detectors.py +++ b/slither/detectors/all_detectors.py @@ -96,3 +96,4 @@ from .assembly.return_instead_of_leave import ReturnInsteadOfLeave from .operations.incorrect_exp import IncorrectOperatorExponentiation from .statements.tautological_compare import TautologicalCompare +from .statements.return_bomb import ReturnBomb diff --git a/slither/detectors/statements/return_bomb.py b/slither/detectors/statements/return_bomb.py new file mode 100644 index 0000000000..8b6cd07a29 --- /dev/null +++ b/slither/detectors/statements/return_bomb.py @@ -0,0 +1,123 @@ +from typing import List + +from slither.core.cfg.node import Node +from slither.core.declarations import Contract +from slither.core.declarations.function import Function +from slither.core.solidity_types import Type +from slither.detectors.abstract_detector import ( + AbstractDetector, + DetectorClassification, + DETECTOR_INFO, +) +from slither.slithir.operations import LowLevelCall, HighLevelCall +from slither.analyses.data_dependency.data_dependency import is_tainted +from slither.utils.output import Output + + +class ReturnBomb(AbstractDetector): + + ARGUMENT = "return-bomb" + HELP = "A low level callee may consume all callers gas unexpectedly." + IMPACT = DetectorClassification.LOW + CONFIDENCE = DetectorClassification.MEDIUM + + WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#return-bomb" + + WIKI_TITLE = "Return Bomb" + WIKI_DESCRIPTION = "A low level callee may consume all callers gas unexpectedly." + WIKI_EXPLOIT_SCENARIO = """ +```solidity +//Modified from https://github.com/nomad-xyz/ExcessivelySafeCall +contract BadGuy { + function youveActivateMyTrapCard() external pure returns (bytes memory) { + assembly{ + revert(0, 1000000) + } + } +} + +contract Mark { + function oops(address badGuy) public{ + bool success; + bytes memory ret; + + // Mark pays a lot of gas for this copy + //(success, ret) = badGuy.call{gas:10000}( + (success, ret) = badGuy.call( + abi.encodeWithSelector( + BadGuy.youveActivateMyTrapCard.selector + ) + ); + + // Mark may OOG here, preventing local state changes + //importantCleanup(); + } +} + +``` +After Mark calls BadGuy bytes are copied from returndata to memory, the memory expansion cost is paid. This means that when using a standard solidity call, the callee can "returnbomb" the caller, imposing an arbitrary gas cost. +Callee unexpectedly makes the caller OOG. +""" + + WIKI_RECOMMENDATION = "Avoid unlimited implicit decoding of returndata." + + @staticmethod + def is_dynamic_type(ty: Type) -> bool: + # ty.is_dynamic ? + name = str(ty) + if "[]" in name or name in ("bytes", "string"): + return True + return False + + def get_nodes_for_function(self, function: Function, contract: Contract) -> List[Node]: + nodes = [] + for node in function.nodes: + for ir in node.irs: + if isinstance(ir, (HighLevelCall, LowLevelCall)): + if not is_tainted(ir.destination, contract): # type:ignore + # Only interested if the target address is controlled/tainted + continue + + if isinstance(ir, HighLevelCall) and isinstance(ir.function, Function): + # in normal highlevel calls return bombs are _possible_ + # if the return type is dynamic and the caller tries to copy and decode large data + has_dyn = False + if ir.function.return_type: + has_dyn = any( + self.is_dynamic_type(ty) for ty in ir.function.return_type + ) + + if not has_dyn: + continue + + # If a gas budget was specified then the + # user may not know about the return bomb + if ir.call_gas is None: + # if a gas budget was NOT specified then the caller + # may already suspect the call may spend all gas? + continue + + nodes.append(node) + # TODO: check that there is some state change after the call + + return nodes + + def _detect(self) -> List[Output]: + results = [] + + for contract in self.compilation_unit.contracts: + for function in contract.functions_declared: + nodes = self.get_nodes_for_function(function, contract) + if nodes: + info: DETECTOR_INFO = [ + function, + " tries to limit the gas of an external call that controls implicit decoding\n", + ] + + for node in sorted(nodes, key=lambda x: x.node_id): + info += ["\t", node, "\n"] + + res = self.generate_result(info) + results.append(res) + + return results diff --git a/tests/e2e/detectors/snapshots/detectors__detector_ReturnBomb_0_8_20_return_bomb_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_ReturnBomb_0_8_20_return_bomb_sol__0.txt new file mode 100644 index 0000000000..f53b5233fd --- /dev/null +++ b/tests/e2e/detectors/snapshots/detectors__detector_ReturnBomb_0_8_20_return_bomb_sol__0.txt @@ -0,0 +1,5 @@ +Mark.oops(address) (tests/e2e/detectors/test_data/return-bomb/0.8.20/return_bomb.sol#31-55) tries to limit the gas of an external call that controls implicit decoding + ret1 = BadGuy(badGuy).fbad{gas: 2000}() (tests/e2e/detectors/test_data/return-bomb/0.8.20/return_bomb.sol#42) + (x,str) = BadGuy(badGuy).fbad1{gas: 2000}() (tests/e2e/detectors/test_data/return-bomb/0.8.20/return_bomb.sol#44) + (success,ret) = badGuy.call{gas: 10000}(abi.encodeWithSelector(BadGuy.llbad.selector)) (tests/e2e/detectors/test_data/return-bomb/0.8.20/return_bomb.sol#47-51) + diff --git a/tests/e2e/detectors/snapshots/detectors__detector_TautologicalCompare_0_8_20_compare_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_TautologicalCompare_0_8_20_compare_sol__0.txt new file mode 100644 index 0000000000..76685043ce --- /dev/null +++ b/tests/e2e/detectors/snapshots/detectors__detector_TautologicalCompare_0_8_20_compare_sol__0.txt @@ -0,0 +1,3 @@ +A.check(uint256) (tests/e2e/detectors/test_data/tautological-compare/0.8.20/compare.sol#3-5) compares a variable to itself: + (a >= a) (tests/e2e/detectors/test_data/tautological-compare/0.8.20/compare.sol#4) + diff --git a/tests/e2e/detectors/test_data/return-bomb/0.8.20/return_bomb.sol b/tests/e2e/detectors/test_data/return-bomb/0.8.20/return_bomb.sol new file mode 100644 index 0000000000..76413fdcaa --- /dev/null +++ b/tests/e2e/detectors/test_data/return-bomb/0.8.20/return_bomb.sol @@ -0,0 +1,57 @@ +contract BadGuy { + function llbad() external pure returns (bytes memory) { + assembly{ + revert(0, 1000000) + } + } + + function fgood() external payable returns (uint){ + assembly{ + return(0, 1000000) + } + } + + function fbad() external payable returns (uint[] memory){ + assembly{ + return(0, 1000000) + } + } + + function fbad1() external payable returns (uint, string memory){ + assembly{ + return(0, 1000000) + } + } + + +} + +contract Mark { + + function oops(address badGuy) public{ + bool success; + string memory str; + bytes memory ret; + uint x; + uint[] memory ret1; + + x = BadGuy(badGuy).fgood{gas:2000}(); + + ret1 = BadGuy(badGuy).fbad(); //good (no gas specified) + + ret1 = BadGuy(badGuy).fbad{gas:2000}(); + + (x, str) = BadGuy(badGuy).fbad1{gas:2000}(); + + // Mark pays a lot of gas for this copy 😬😬😬 + (success, ret) = badGuy.call{gas:10000}( + abi.encodeWithSelector( + BadGuy.llbad.selector + ) + ); + + // Mark may OOG here, preventing local state changes + //importantCleanup(); + } +} + diff --git a/tests/e2e/detectors/test_data/return-bomb/0.8.20/return_bomb.sol-0.8.20.zip b/tests/e2e/detectors/test_data/return-bomb/0.8.20/return_bomb.sol-0.8.20.zip new file mode 100644 index 0000000000000000000000000000000000000000..4c10ea6fea0dfc804d3fef44769721e1be8d5765 GIT binary patch literal 7966 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