issue=Issue("CALL with gas to dynamic address","Warning")
description="The function "+call.node.function_name+" contains a call.value() to "
issue.description="The function "+call.node.function_name+" contains a call.value() to "
target=str(call.to)
target=str(call.to)
is_valid=False
is_valid=False
@ -32,9 +31,9 @@ def execute(statespace):
if("calldata"intargetor"caller"intarget):
if("calldata"intargetor"caller"intarget):
if("calldata"intarget):
if("calldata"intarget):
issue.description+="an address provided as a function argument. "
description+="an address provided as a function argument. "
else:
else:
issue.description+="the address of the transaction sender. "
description+="the address of the transaction sender. "
is_valid=True
is_valid=True
else:
else:
@ -49,7 +48,7 @@ def execute(statespace):
ifs.tainted:
ifs.tainted:
issue.description+= \
description+= \
"an address found at storage position "+str(index)+".\n"+ \
"an address found at storage position "+str(index)+".\n"+ \
"This storage position can be written to by calling the function '"+s.node.function_name+"'.\n" \
"This storage position can be written to by calling the function '"+s.node.function_name+"'.\n" \
"Verify that the contract address cannot be set by untrusted users.\n"
"Verify that the contract address cannot be set by untrusted users.\n"
@ -62,7 +61,10 @@ def execute(statespace):
continue
continue
ifis_valid:
ifis_valid:
issue.description+="The available gas is forwarded to the called contract.\nMake sure that the logic of the calling contract is not adversely affected if the called contract misbehaves (e.g. reentrancy)."
description+="The available gas is forwarded to the called contract.\nMake sure that the logic of the calling contract is not adversely affected if the called contract misbehaves (e.g. reentrancy)."
issue=Issue(call.node.module_name,call.node.function_name,call.addr,"CALL with gas to dynamic address","Warning",description)
issue=Issue("CALLDATA forwarded with delegatecall()","Informational")
issue=Issue(call.node.module_name,call.node.function_name,call.addr,"CALLDATA forwarded with delegatecall()","Informational")
issue.description= \
issue.description= \
"The contract '"+str(call.node.module_name)+"' forwards its calldata via DELEGATECALL in its fallback function. " \
"The contract '"+str(call.node.module_name)+"' forwards its calldata via DELEGATECALL in its fallback function. " \
"This means that any function in the called contract can be executed. Note that the callee contract will have access to the storage of the calling contract.\n"
"This means that any function in the called contract can be executed. Note that the callee contract will have access to the storage of the calling contract.\n"
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+"'."
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+"'."
"The function "+call.node.function_name+"in contract '"+call.node.module_name+"'contains a call to "+receiver+".\n" \
"The function "+call.node.function_name+" contains a call to "+receiver+".\n" \
"The return value of this call is not checked. Note that the function will continue to execute with a return value of '0' if the called contract throws."
"The return value of this call is not checked. Note that the function will continue to execute with a return value of '0' if the called contract throws."
logging.debug("[UNCHECKED_SUICIDE] suicide in function "+node.function_name)
logging.debug("[UNCHECKED_SUICIDE] suicide in function "+node.function_name)
issue=Issue("Unchecked SUICIDE","Warning")
description="The function "+node.function_name+" executes the SUICIDE instruction."
issue.description="The function "+node.function_name+" executes the SUICIDE instruction."
state=node.states[instruction['address']]
state=node.states[instruction['address']]
to=state.stack.pop()
to=state.stack.pop()
if("caller"instr(to)):
if("caller"instr(to)):
issue.description+="\nThe remaining Ether is sent to the caller's address.\n"
description+="\nThe remaining Ether is sent to the caller's address.\n"
elif("storage"instr(to)):
elif("storage"instr(to)):
issue.description+="\nThe remaining Ether is sent to a stored address\n"
description+="\nThe remaining Ether is sent to a stored address\n"
elif("calldata"instr(to)):
elif("calldata"instr(to)):
issue.description+="\nThe remaining Ether is sent to an address provided as a function argument."
description+="\nThe remaining Ether is sent to an address provided as a function argument."
elif(type(to)==BitVecNumRef):
elif(type(to)==BitVecNumRef):
issue.description+="\nThe remaining Ether is sent to: "+hex(to.as_long())
description+="\nThe remaining Ether is sent to: "+hex(to.as_long())
else:
else:
issue.description+="\nThe remaining Ether is sent to: "+str(to)+"\n"
description+="\nThe remaining Ether is sent to: "+str(to)+"\n"
constrained=False
constrained=False
can_solve=True
can_solve=True
@ -68,7 +67,7 @@ def execute(statespace):
forsinstatespace.sstors[index]:
forsinstatespace.sstors[index]:
ifs.tainted:
ifs.tainted:
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+"'."
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
ifnotoverwrite:
ifnotoverwrite:
@ -90,17 +89,21 @@ def execute(statespace):
ifnotconstrained:
ifnotconstrained:
issue.description+="\nIt seems that this function can be called without restrictions."
description+="\nIt seems that this function can be called without restrictions."