Update security checks

pull/23/head
Bernhard Mueller 7 years ago
parent 64b8d2fb78
commit 1ce6fbb588
  1. 47
      mythril/analysis/modules/ether_send.py
  2. 29
      mythril/analysis/modules/unchecked_suicide.py
  3. 16
      mythril/analysis/solver.py
  4. 17
      mythril/analysis/symbolic.py
  5. 3
      mythril/exceptions.py

@ -1,6 +1,8 @@
from z3 import * from z3 import *
from mythril.analysis.ops import * from mythril.analysis.ops import *
from mythril.analysis import solver
from mythril.analysis.report import Issue from mythril.analysis.report import Issue
from mythril.exceptions import UnsatError
import re import re
import logging import logging
@ -41,6 +43,8 @@ def execute(statespace):
issue.description += "a non-zero amount of Ether is sent to an address taken from function arguments.\n" issue.description += "a non-zero amount of Ether is sent to an address taken from function arguments.\n"
interesting = True interesting = True
issue.description += "Call value is " + str(call.value) + "\n"
if interesting: if interesting:
node = call.node node = call.node
@ -48,33 +52,44 @@ def execute(statespace):
can_solve = True can_solve = True
for constraint in node.constraints: for constraint in node.constraints:
m = re.search(r'storage_([0-9a-f])+', str(constraint))
m = re.search(r'storage_([a-z0-9_&^]+)', str(constraint))
can_solve = True
if (m): if (m):
index = m.group(1) index = m.group(1)
write_func = statespace.find_storage_write(index) try:
can_write = False
if write_func is None: for s in statespace.sstors[index]:
can_solve = False
break
if can_solve:
s = Solver() if s.tainted:
can_write = True
for constraint in node.constraints: issue.description += "\nThere is a check on storage index " + str(index) + ". This storage index can be written to by calling the function '" + s.node.function_name + "'."
s.add(constraint) break
if (s.check() == sat):
m = s.model() if not can_write:
logging.info("No storage writes to index " + str(index))
can_solve = False
break
logging.debug("Model for node " + str(node.uid) + ", function " + node.function_name + ": ") except KeyError:
logging.info("No storage writes to index " + str(index))
can_solve = False
break
for d in m.decls(): if can_solve:
logging.debug("%s = 0x%x" % (d.name(), m[d].as_long()))
try:
model = solver.get_model(node.constraints)
issues.append(issue) issues.append(issue)
for d in model.decls():
logging.debug("[UNCHECKED_SEND] %s = 0x%x" % (d.name(), model[d].as_long()))
except UnsatError:
logging.debug("[UNCHECKED_SEND] no model found")
return issues return issues

@ -1,10 +1,13 @@
from z3 import * from z3 import *
from mythril.analysis import solver
from mythril.analysis.ops import * from mythril.analysis.ops import *
from mythril.analysis.report import Issue from mythril.analysis.report import Issue
from mythril.exceptions import UnsatError
import re import re
import logging import logging
''' '''
MODULE DESCRIPTION: MODULE DESCRIPTION:
@ -52,8 +55,9 @@ def execute(statespace):
can_write = False can_write = False
for s in statespace.sstors[index]: for s in statespace.sstors[index]:
if s.tainted: if s.tainted:
can_write = True can_write = Trues
issue.description += "\nThere is a check on storage index " + str(index) + ". This storage index can be written to by calling the function '" + s.node.function_name + "'." issue.description += "\nThere is a check on storage index " + str(index) + ". This storage index can be written to by calling the function '" + s.node.function_name + "'."
break break
@ -70,24 +74,13 @@ def execute(statespace):
if can_solve: if can_solve:
s = Solver() try:
model = solver.get_model(node.constraints)
for constraint in node.constraints:
s.add(constraint)
if (s.check() == sat):
m = s.model()
logging.debug("Model for node " + str(node.uid) + ", function " + node.function_name + ": ")
for d in m.decls():
logging.debug("%s = 0x%x" % (d.name(), m[d].as_long()))
issues.append(issue) issues.append(issue)
else: for d in model.decls():
logging.debug("unsat") logging.debug("[UNCHECKED_SUICIDE] main model: %s = 0x%x" % (d.name(), model[d].as_long()))
except UnsatError:
logging.debug("[UNCHECKED_SUICIDE] no model found")
return issues return issues

@ -0,0 +1,16 @@
from z3 import *
from mythril.exceptions import UnsatError
def get_model(constraints):
s = Solver()
for constraint in constraints:
s.add(constraint)
if (s.check() == sat):
return s.model()
else:
raise UnsatError

@ -1,5 +1,8 @@
from mythril.analysis import solver
from mythril.exceptions import UnsatError
from laser.ethereum import svm from laser.ethereum import svm
from .ops import * from .ops import *
import logging
class StateSpace: class StateSpace:
@ -66,18 +69,26 @@ class StateSpace:
def sstor_analysis(self): def sstor_analysis(self):
logging.debug("Analyzing storage operations...")
for index in self.sstors: for index in self.sstors:
for s in self.sstors[index]: for s in self.sstors[index]:
s.tainted = True # For now we simply 'taint' every storage location that is reachable without any constraint on msg.sender
# For now we simply 'taint' every storage location that can be written to without any constraint on msg.sender
for constraint in s.node.constraints: for constraint in s.node.constraints:
logging.debug("Constraint: " + str(constraint))
if ("caller" in str(constraint)): if ("caller" in str(constraint)):
s.tainted = False s.tainted = False
break break
try:
solver.get_model(s.node.constraints)
s.tainted = True
except UnsatError:
s.tainted = False
def find_storage_write(self, index): def find_storage_write(self, index):

@ -1,2 +1,5 @@
class CompilerError(Exception): class CompilerError(Exception):
pass pass
class UnsatError(Exception):
pass
Loading…
Cancel
Save