ContractFuzzer
2022-12-16 17:23:00 6 举报
AI智能生成
登录查看完整内容
为你推荐
查看更多
抱歉,暂无相关内容
ContractFuzzer分析
作者其他创作
大纲/内容
Dockerfile
base
示例合约
example
从以太坊浏览器下载合约的abi和bin
download_verified_contract_from_etherscan.py
Excel文件的读写
excelUtil.py
0x06fdde03:name()
0x07546172:minter()
0x0758a980:specialBonus(address)
从abi文件中提取对应的函数签名
get_function_signature_from_abi.py
0xdd9e7b1b: 0x70a08231 0xa9059cbb
0xfcfdbc23: 0x70a08231 0xa9059cbb
0xea083b86: 0x70a08231 0xa9059cbb
从bin文件中提取对应的函数签名对(合约函数签名:函数内部调用签名)
get_function_signature_pair_from_bin.py
生成自身函数与调用函数的签名对
根据PUSH4和CALL读出调用的函数签名
定位函数指令码区域
根据 PUSH4和EQ读出合约本身函数签名
通过evm disasm获取指令码
流程
外框
python封装工具
tools
geth --fast --identity \"TestNode2\" --rpc -rpcaddr \"0.0.0.0\" --rpcport \"8545\" --rpccorsdomain \"*\" --port \"30303\" --nodiscover --rpcapi \
启动命令
五个测试账户数据
keystore
交易日志
transactions.rlp
解锁账户密码: 123456
pwd.txt
链id:1900
networkid
私有链的配置信息
私有链配置文件
Ethereum
调用合约地址
caller
被调用合约函数
callee
函数传入以太坊
value
函数调用gas费
gas
最终消耗gas费
finalgas
传入参数
input
后续调用函数
nextcalls
函数操作码栈
OperationStack
状态栈
StateStack
是否抛出异常
throwException
是否gas费不足
errOutGas
是否余额不足
errOutBalance
封装函数体
初始化操作码栈,第一项为传入的operartion
初始化状态栈为空
初始化nextcalls为空
初始化input参数
newHackerContractCall()
HackerContractCall
结构体
call.OperationStack.push(opCodeToString[OPCODE])
OnOpcode()
OnCall()
OnDelegateCall()
OnCallCode()
确定最终gas费
call.finalgas = finalgas
OnCloseCall()
操作码函数
共用逻辑
添加后续调用函数
添加总函数调用列表与函数哈希列表
调用函数
初始化函数列表、函数哈希列表、函数调用栈
将此次EVM的直接调用压入函数调用栈第一个位置
EVM接收前端参数并进行合约函数调用时执行
在 evm.Call()函数中调用
hacker_init()
函数调用栈清空
初始化函数列表与函数哈希列表
测试漏洞
TestOracle()
创建所有测试机
漏洞种类
oracles
具体细节
profile
values := url.Values{\"oracles\
将测试结果发送给fuzzServer: http://localhost:8888/hack
本次EVM执行流程结束执行
在 evm.Call()函数最后调用
hacker_close()
生命周期函数
hacker_contractcall.go
压入函数操作码栈
传入 call.onOpCode()函数
EVM原生函数
调用 intructions.OpCode()函数
hook EVM操作码
Hacker_record()
hacker_instruction.go
操作码栈
HackerOperationStack
hacker_operation.go
InitOracle()
判断是否存在漏洞
Write()
String()
Oracle
接口
函数哈希列表
hacker_call_hashs
函数列表
hacker_calls
HackerRootCallFailed
重复函数对
repeatedPairs
描述
feauture
HackerReentrancy
HackerRepeatedCall
发送以太的函数
hacker_exception_calls
HackerEtherTransfer
HackerEtherTransferFailed
HackerCallEtherTransferFailed
HackerGaslessSend
调用了delegatecall的函数
hacker_delegate_calls
HackerDelegateCallInfo
抛出异常但跟函数未抛出异常的函数
HackerExceptionDisorder
通过send调用的函数
HackerSendOpInfo
通过call调用的函数抛出异常
HackerCallExecption
通过消息调用者或input传入的函数
HackerUnknownCall
修改账户状态的函数
HackerStorageChanged
调用了TIMESTAMP的函数
HackerTimestampOp
调用了NUMBER的函数
HackerNumberOp
调用了BLOCKHASH的函数
HackerBlockHashOp
HackerBalanceGtZero
实现
检查函数调用栈中的首项是否抛出异常
根调用失败
函数调用栈中是否存在某一项与第一项一致
如果小于,说明可能存在条件限制,未走到第一次的结束,认为不存在重入
第二次的函数操作栈是否不小于第一次的函数操作栈
重入
重复调用
函数调用栈中是否存在给下一个调用函数发送以太的函数
value>0
是否发送以太坊
被调用者是一个账户地址
方法抛出异常
方法gas不足
方法的input参数为空
方法的gas费用为2300
SEND转账的gas不足
发送或接收以太坊
value>0 || 操作码中包含BALANCE指令
抛出异常
以太坊交易失败
未使用send方法
gas费用大于2300
value > 0
TRANSFER转账失败
函数的操作码栈中包含DELEGATECALL指令
Delegatecall外部调用
函数调用栈中非根函数抛出了异常但根函数未抛出异常
无序异常
input参数为空
gas费为2300
SEND操作码调用
call函数异常
call调用
根函数的调用者是否与函数栈中某项被调用者地址一致 ||根函数的input是否包含函数栈中某项函数的input ||根函数的input是否包含函数栈中某项被调用者的地址
外部可控函数调用
根函数的状态栈的第一项与最后一项是否一致
修改账户状态
函数的操作码调用栈中包含TIMESTAMP操作码
timestamp依赖
函数的操作码调用栈中包含NUMBER操作码
blocknumber依赖
函数的操作码调用栈中包含BLOCKHASH操作码
blockhash依赖
如果函数调用栈中前n项为代理合约,则弹出前n项
根函数的被调用者为什么是测试合约
找出高价值合约
根函数的被调用者(即测试合约)余额是否大于0
存在余额合约
漏洞测试机
对总函数列表、函数列表哈希、后续调用进行合并哈希
根调用签名
操作码长度
操作栈
漏洞细节
Profile()
HackerCallInfoReportor
生成报告
hacker_oracle.go
addr
storage
balance
Hacker_ContractState
contracts []*Hacker_ContractState
HackerState
主要是调用方法是调用者与被调用者的状态对
data []*HackerState
HackerStateStack
状态栈,用于回滚
封装地址状态结构体与方法
地址状态
hacker_state.go
判断storage是否一致
showDiffStorage
判断余额是否一致
ShowDiffBalance
判断两个地址状态是否一致
ShowDiffState()
Hash(caller)+Hash(callee)+Hash(input)
对一次函数调用进行哈希
Hash()
封装一些常用函数
hacker_utils.go
判断合约是否为启动时注册的release oracle服务
isRelOracle()
hacker_hub.go
hook EVM执行操作码流程,生成新的geth
go-ethereum-cf
对 abi_dir 下的合约进行fuzz
启动监听服务
main()
contractfuzzer
随机选取函数
g_func_Robin.Random_select(funcs)
不同case分为byte、uint、address、string等进行fuz
Cfundemental: 基本类型
进入基本类型逻辑
遍历每个元素
CfixedArray: 固定数组
进入固定数组逻辑
生成随机长度固定数组
CdynamicArray: 动态数组
fuzz(type)
随机生成输入参数
f.Inputs.fuzz()
abi.fuzz()
fuzz测试合约的输入序列
current_contract_address
输入序列
msgs
将输入序列发送给fuzzMonitor: http://127.0.0.1:8088/runnerMonitor
fuzz
监听端口: 8888
监听路径: /hack
监听fuzz测试结果
保存测试文件
server
fuzz的种子文件
config
封装abi函数
abi
根据abi fuzz测试合约输入序列
contract_fuzzer
bnode ./utils/runFuzzMonitor --ip http://127.0.0.1:8545 --account 0 --value 0
监听端口: 8088
address
msg
接收参数
RunnerMonitor()
供后续调用
传入调用测试合约的地址与input输入,保存为合约变量
fallback函数,供重入测试
根据已定义的合约地址与输入参数重新调用函数
function()
Agen.sol
部署代理合约
getAgent()
将测试合约地址与传入参数保存进合约
调用代理合约的AgentCallWithValue函数
MyCallWithValueBatch(argsAgent)
进入EVM流程
调用测试合约地址与传入参数
发送测试交易
sendBatchTransaction(args)
启动fuzzMonitor
中转fuzz客户端与私链通信,添加代理
contract_tester
bnode ./utilsScripts/deployContract.js --contractdir $CONTRACTS -bindir $BINS --abidir $ABIS
使用命令
根据合约的abi与bin部署到测试链上
部署测试合约
contract_deployer
ContractFuzzer
收藏
0 条评论
回复 删除
下一页