1.理解自杀函数检测自杀函数的风险与应用场景。自杀函数可以做为一种隐藏的transfer的手段。 2.shift汇编函数与其它语言的参数不一致,容易混淆。
自杀函数的检测和shift汇编函数的检测比较简单,因此放在了同一篇中。主要理解
Solidity中的自杀函数(selfdestruct)可以用于销毁智能合约,并将合约余额发送到指定的地址。尽管自杀函数在某些情况下可能是必要的,但它也存在一些潜在的风险和安全考虑,包括:
自杀函数有这么多的风险,那么自杀函数通常用在哪些场景中呢?
功能:检测合约代码中是否有对selfdestruct的调用。如果public或者external类型的函数名中包含suicide
或者selfdestruct
的关键字,就认为可能存在风险。代码会输出风险提示由人工进行分析排查。
检测逻辑:
detect_suicidal_func(func)
函数detect_suicidal_func(func)
函数中,函数必须为public或者external,通过func.internal_calls取得函数内部调用的所有的函数对象
。取函数对象的name属性就得到了函数名。这样就能得到当前函数中所有的被调用的函数名。suicide(address)
或者selfdestruct(address)
def detect_suicidal_func(func):
"""Detect if the function is suicidal
Detect the public functions calling suicide/selfdestruct without protection
Returns:
(bool): True if the function is suicidal
"""
if func.is_constructor:
return False
if func.visibility not in ["public", "external"]:
return False
calls = [c.name for c in func.internal_calls]
if not ("suicide(address)" in calls or "selfdestruct(address)" in calls):
return False
if func.is_protected():
return False
return True
Ethernaut Challenge — Level 7: Force
中,使用自杀函数强制向一个合约转账,有兴趣的可以检索看看。具体记不太清了,只记得大概是这么个合约
)内置的shift函数,第1个参数表示偏移的位数,第2个参数表示要操作的操作数
。
这点与其他语言中的shift函数参数的位置是相反的。这个差异可能导致shift代码的含义与要实现的功能不相符。
如下面的代码可能就是个有问题的代码
。下面的代码中函数的意思将数字8右移a位。而代码作者的本意应该是把数字a右移8位。
contract C {
function f() internal returns (uint a) {
assembly {
a := shr(a, 8)
}
}
}
检测的脚本在detectors/assembly/shift_parameter_mixup.py
脚本中。
检测逻辑:
contains_assembly
,在检测合约中是否包含assembly编码。Binary
对象类型,并且ir的类型为BinaryType.LEFT_SHIFT
或者 BinaryType.RIGHT_SHIFT
,并且ir的variable_left
左边的变量为 Constant
类型。主要的检测代码:
def _check_function(self, f):
results = []
for node in f.nodes:
for ir in node.irs:
if isinstance(ir, Binary) and ir.type in [
BinaryType.LEFT_SHIFT,
BinaryType.RIGHT_SHIFT,
]:
if isinstance(ir.variable_left, Constant):
info = [f, " contains an incorrect shift operation: ", node, "\n"]
json = self.generate_result(info)
results.append(json)
return results
检测效果如图:
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!