# 科学家社区周分享-链上合约FUZZ和闪电贷潜在利用合约

By [科学家社区](https://paragraph.com/@0x8576195e6be1c75ecedf13372ee18e3ced652c36) · 2022-04-19

---

关于周分享的内容 科学家社区是在每周五的晚上8点进行周分享 我们的telegram群组如下，本文是2022年4月15日的技术分享总结。本周的技术分享内容在投票中 写文时还没有确定～

我们的宗旨是绝不作恶 帮助项目方发现漏洞 修补问题 科学家社区我本人是实名在做的 大家可以加我的微信号交流 微信号是C1h2e1

[科学家社区](https://t.me/scientistDAO)

在读之前介绍一下整体的思路
-------------

我们在链上做合约创建的监控 ，通过监控后拿到ABI去不断的在本地的Fork Chain去调用 通过参数组合和碰撞然后去看能否能进行套利的点等等。Method ID不能通过[4bytes](https://www.4byte.directory/) 找到的，通过参数的不同组合方案去碰撞一个正确调用方式 以此寻找套利空间。 最后我们通过监控交易去寻找与DEX的STATICCALL(getReserves)这类的不安全的价格获取～

### 字典

*   address
    
    *   0x0000000000000000000000000000000000000000
        
    *   Top Holder List
        
    *   你自己的地址
        
    *   0x000000000000000000000000000000000000dead
        
    *   合约创建者
        
*   bool
    
    *   True
        
    *   False
        
*   uint256
    
    *   0-10
        
    *   timestamp
        

监控合约创建到从ByteCode中提取ABI
----------------------

6080604052 这是每一个合约Bytecode的前4个字节的内容，也就是我们需要监控的特征，下面是监控的Demo代码～ 💡 科学家社区所有的代码只有Demo片段 不会发任何完整的直接用的代码 防止作恶和伸手党，本身我自己写的代码是一长串 但是为了方便演示我把每一个小段分开摘出来 👀的出来我对你们的❤️吗？

    from web3 import Web3
    rpc_url = "https://RPC_HERE.cnm"
    web3 = Web3(Web3.HTTPProvider(rpc_url))
    def getTxContract(BlockNumber):
        txConutInBlock = web3.eth.getBlockTransactionCount(BlockNumber)
        for Numbers in range(0,txConutInBlock-1):
            info = web3.eth.get_transaction_by_block(BlockNumber,Numbers)
            if info['input'][0:10] == "0x60806040" :
                target = web3.eth.get_transaction_receipt(info['hash'])
                print(target['contractAddress'])
    

我们监控到合约以后直接用这个项目的代码把ABI摘出来就好了

[https://github.com/beched/abi-decompiler](https://github.com/beched/abi-decompiler)

    import re
    opcodes = {
        '63' : 'PUSH4',
    }
    def push_bytes(h):
        i = str(int(h, 16))
        return '0x' + h
    def decode(hexcode):
        size = len(str(len(hexcode)))
        h = ''
        o = ''
        pushcnt = 0
        cnt = -1
        for item in hexcode:
            cnt += 1
            if pushcnt > 0:
                h += item.lower()
                pushcnt -= 1
                if pushcnt == 0:
                    i = str(int(h, 16))
                    o += push_bytes(h) + '\n'
                    h = ''
            elif isinstance(item, str) and item.lower() in opcodes:
                if int('60', 16) <= int(item, 16) <= int('7f', 16):
                    pushcnt = int(item, 16) - int('60', 16) + 1
                else:
                    o += '\n'
        return o.strip()
    
    if __name__ == '__main__':
        hexcode=open('test.bin','r').read()
        print(decode([hexcode[i:i+2] for i in range(2, len(hexcode), 2)]))
    

原作者是Python2的代码这里我自己弄了个Python3的可以作为参考

如果你和我一样是一个十里八乡有名的裁缝的话你现在已经能通过监控合约创建→获取Method ID了 。Method ID也叫Function Signature 生成方式如下～

![](https://storage.googleapis.com/papyrus_images/05129457cf3832e4bf4274392780ba1c58f06014e612a160a724e132aa0d25b0.png)

现在我们拿到了Method ID和合约的地址，我们就可以去进行组合了 首先我们可以通过4Bytes去做查询看能不能直接查到调用需要的参数和参数类型 /api/v1/signatures/?hex\_signature=0xabcd1234 我们可以通过ABI直接去进行查询 返回text signature 然后去用这个调用

![](https://storage.googleapis.com/papyrus_images/329dc50ca08f6313b074dc7c83b0114058d1ad128525250efd8f5ba1ca3d35b1.png)

当我们在4bytes上无法查询到的时候我们可以通过枚举参数类型和参数数量来完成这个操作。

假设我的合约中有这样一个函数

    funciton withdraw(uint256 Numbers,address From) external;
    

这里我们就可以通过字典里内容的组合去达成一次成功的调用 具体怎么算成功 因个人而定 这里不写了。

监控闪电贷潜在利用合约
-----------

首先我们需要找到价格可操纵的点，大部分是Uniswap及Fork项目的价格获取 一般是两种调用方法

    UniswapRouterV2.getReserves()
    Pair.getReserves()
    

![](https://storage.googleapis.com/papyrus_images/be12d5fcdef7529afa545a63b97471c3e72f04e04e64fcae8ed828edc488b9ba.png)

![](https://storage.googleapis.com/papyrus_images/529b0d0348525e7eac56d817841a4ee68b28accd5cb0925275a1d0e75c78045e.png)

---

*Originally published on [科学家社区](https://paragraph.com/@0x8576195e6be1c75ecedf13372ee18e3ced652c36/fuzz)*
