Skip to content

Commit

Permalink
working version
Browse files Browse the repository at this point in the history
  • Loading branch information
Yhtiyar authored and olegggatttor committed Apr 17, 2024
1 parent ec0830f commit f92059a
Show file tree
Hide file tree
Showing 7 changed files with 905 additions and 1 deletion.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 60 additions & 0 deletions slither_pess/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from slither_pess.detectors.arbitrary_call import ArbitraryCall
from slither_pess.detectors.double_entry_token_possibility import (
DoubleEntryTokenPossiblity,
)
from slither_pess.detectors.dubious_typecast import DubiousTypecast
from slither_pess.detectors.falsy_only_eoa_modifier import OnlyEOACheck
from slither_pess.detectors.magic_number import MagicNumber
from slither_pess.detectors.strange_setter import StrangeSetter
from slither_pess.detectors.unprotected_setter import UnprotectedSetter
from slither_pess.detectors.nft_approve_warning import NftApproveWarning
from slither_pess.detectors.inconsistent_nonreentrant import InconsistentNonreentrant
from slither_pess.detectors.call_forward_to_protected import CallForwardToProtected
from slither_pess.detectors.multiple_storage_read import MultipleStorageRead
from slither_pess.detectors.timelock_controller import TimelockController
from slither_pess.detectors.tx_gasprice_warning import TxGaspriceWarning
from slither_pess.detectors.unprotected_initialize import UnprotectedInitialize
from slither_pess.detectors.readonly_reentrancy.read_only_reentrancy import (
ReadOnlyReentrancy,
)
from slither_pess.detectors.event_setter import EventSetter
from slither_pess.detectors.before_token_transfer import BeforeTokenTransfer
from slither_pess.detectors.uni_v2 import UniswapV2
from slither_pess.detectors.token_fallback import TokenFallback
from slither_pess.detectors.for_continue_increment import ForContinueIncrement
from slither_pess.detectors.ecrecover import Ecrecover
from slither_pess.detectors.public_vs_external import PublicVsExternal
from slither_pess.detectors.readonly_reentrancy.balancer_readonly_reentrancy import (
BalancerReadonlyReentrancy,
)


def make_plugin():
plugin_detectors = [
DoubleEntryTokenPossiblity,
UnprotectedSetter,
NftApproveWarning,
InconsistentNonreentrant,
StrangeSetter,
OnlyEOACheck,
MagicNumber,
DubiousTypecast,
CallForwardToProtected,
MultipleStorageRead,
TimelockController,
TxGaspriceWarning,
UnprotectedInitialize,
ReadOnlyReentrancy,
EventSetter,
BeforeTokenTransfer,
UniswapV2,
TokenFallback,
ForContinueIncrement,
ArbitraryCall,
Ecrecover,
PublicVsExternal,
BalancerReadonlyReentrancy,
]
plugin_printers = []

return plugin_detectors, plugin_printers
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
from typing import List
from slither.utils.output import Output
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.declarations import Function, Contract
from slither.core.cfg.node import Node


class BalancerReadonlyReentrancy(AbstractDetector):
"""
Sees if a contract has a beforeTokenTransfer function.
"""

ARGUMENT = "pess-balancer-readonly-reentrancy" # slither will launch the detector with slither.py --detect mydetector
HELP = "beforeTokenTransfer function does not follow OZ documentation"
IMPACT = DetectorClassification.LOW
CONFIDENCE = DetectorClassification.HIGH

WIKI = (
"https://docs.openzeppelin.com/contracts/4.x/extending-contracts#rules_of_hooks"
)
WIKI_TITLE = "Before Token Transfer"
WIKI_DESCRIPTION = "Follow OZ documentation using their contracts"
WIKI_EXPLOIT_SCENARIO = "-"
WIKI_RECOMMENDATION = (
"Make sure that beforeTokenTransfer function is used in the correct way."
)

VULNERABLE_FUNCTION_CALLS = ["getRate", "getPoolTokens"]
visited = []
contains_reentrancy_check = {}

def is_balancer_integration(self, c: Contract) -> bool:
"""
Iterates over all external function calls, and checks the interface/contract name
for a specific keywords to decide if the contract integrates with balancer
"""
for (
fcontract,
_,
) in c.all_high_level_calls:
contract_name = fcontract.name.lower()
if any(map(lambda x: x in contract_name, ["balancer", "ivault", "pool"])):
return True

def _has_reentrancy_check(self, node: Node) -> bool:
if node in self.visited:
return self.contains_reentrancy_check[node]

self.visited.append(node)
self.contains_reentrancy_check[node] = False

for c, n in node.high_level_calls:
if isinstance(n, Function):
if (
n.name == "ensureNotInVaultContext"
and c.name == "VaultReentrancyLib"
) or (
n.name == "manageUserBalance"
): # TODO check if errors out
self.contains_reentrancy_check[node] = True
return True

has_check = False
for internal_call in node.internal_calls:
if isinstance(internal_call, Function):
has_check |= self._has_reentrancy_check(internal_call)
# self.contains_reentrancy_check[internal_call] |= has_check

self.contains_reentrancy_check[node] = has_check
return has_check

def _check_function(self, function: Function) -> list:
has_dangerous_call = False
dangerous_call = None
for n in function.nodes:
for c, fc in n.high_level_calls:
if isinstance(fc, Function):
if fc.name in self.VULNERABLE_FUNCTION_CALLS:
dangerous_call = fc
has_dangerous_call = True
break

if has_dangerous_call and not any(
[self._has_reentrancy_check(node) for node in function.nodes]
):
print("READONLY_REENTRANCY!!!")

def _detect(self) -> List[Output]:
"""Main function"""
res = []
for contract in self.compilation_unit.contracts_derived:
if not self.is_balancer_integration(contract):
continue
for f in contract.functions_and_modifiers_declared:
self._check_function(f)
return res
Loading

0 comments on commit f92059a

Please sign in to comment.