某次锁仓合约应急响应分析记录

这篇具有很好参考价值的文章主要介绍了某次锁仓合约应急响应分析记录。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

背景介绍

在之前的一次应急响应中有客户反馈某合约在上X币交易所的时候,按照交易所的要求曾找人写了锁仓合约并完成了2.5亿某代币的锁仓操作,本来应该是三个月解锁一次,两年解锁完毕,然而一年快过去了,一笔解锁款都没有收到,客户感到很是费解,这和预期的有很大的差入,所以需要帮忙查看究竟是代码问题,还是操作问题并尽最大的可能将未解锁的合约代币进行解锁操作

锁仓合约

智能合约中的锁仓合约是一种功能强大的合约,它用于将加密货币或数字资产锁定在一个特定的账户中以实现一定的安全性和可控性,锁仓合约通常被用于以下几个方面:

  • 基本锁仓:锁仓合约可用于将加密货币或数字资产锁定在一个特定的账户中一段预定的时间,这可以用于各种情况,例如:长期投资、团队解锁、ICO众筹等,在锁仓期间,资产将无法被转移或使用,直到锁仓期满
  • 投票权锁定:一些项目或组织可能会使用锁仓合约来限制投资者或持有者的投票权以防止他们在短期内大量投票或操纵决策,在这种情况下锁仓合约可以将一定数量的代币或股份锁定在账户中直到特定的条件满足
  • 奖励和激励计划:锁仓合约也可以用于奖励和激励计划,特别是在加密货币项目中,项目团队可以锁定一部分代币或股份以作为未来的奖励或激励分配给特定的个人或团队,这可以帮助确保项目的成功和可持续发展
  • 安全保障:锁仓合约还可以用于提供额外的安全保障,通过将资产锁定在一个合约中可以防止黑客攻击或非法访问,这对于保护大量资产或敏感信息非常重要

分析过程

初次分析

第一次分析的时候客户提供了锁仓合约的代码,只是对锁仓解锁的业务逻辑进行了分析并没有彻底发现问题,基本的流程分析流程大致如下:
首先查看了合约代码,发现其中的锁仓部分代码中代币分配总量:2.5亿,耗费两年时间分配完成,其中每隔三个月解锁一次

contract xxxx is Ownable {
    using SafeMath for uint256;

    //Wallet Addresses for allocation
    address public teamReserveWallet = 0xA;
    address public finalReserveWallet = =0xA;

    //Token Allocations
    uint256 public teamReserveAllocation = 240 * (10 ** 6) * (10 ** 18);
    uint256 public finalReserveAllocation = 10 * (10 ** 6) * (10 ** 18);

    //Total Token Allocations
    uint256 public totalAllocation = 250 * (10 ** 6) * (10 ** 18);

    uint256 public teamTimeLock = 2 * 365 days;
    uint256 public teamVestingStages = 8;
    uint256 public finalReserveTimeLock = 2 * 365 days;

    /** Reserve allocations */
    mapping(address => uint256) public allocations;

    /** When timeLocks are over (UNIX Timestamp)  */  
    mapping(address => uint256) public timeLocks;

    /** How many tokens each reserve wallet has claimed */
    mapping(address => uint256) public claimed;

    /** When this vault was locked (UNIX Timestamp)*/
    uint256 public lockedAt = 0;

    MuskToken public token;

    /** Allocated reserve tokens */
    event Allocated(address wallet, uint256 value);

    /** Distributed reserved tokens */
    event Distributed(address wallet, uint256 value);

    /** Tokens have been locked */
    event Locked(uint256 lockTime);

    //Any of the three reserve wallets
    modifier onlyReserveWallets {
        require(allocations[msg.sender] > 0);
        _;
    }

锁仓时间为两年:

function allocate() public notLocked notAllocated onlyOwner {

        //Makes sure Token Contract has the exact number of tokens
        require(token.balanceOf(address(this)) == totalAllocation);

        allocations[teamReserveWallet] = teamReserveAllocation;
        allocations[finalReserveWallet] = finalReserveAllocation;

        Allocated(teamReserveWallet, teamReserveAllocation);
        Allocated(finalReserveWallet, finalReserveAllocation);

        lock();
    }

    //Lock the vault for the wallets
    function lock() internal notLocked onlyOwner {

        lockedAt = block.timestamp;

        timeLocks[teamReserveWallet] = lockedAt.add(teamTimeLock);
        timeLocks[finalReserveWallet] = lockedAt.add(finalReserveTimeLock);

        Locked(lockedAt);
    }

如果锁仓失败则允许所有者收回合约上的token并回收token

//In the case locking failed, then allow the owner to reclaim the tokens on the contract.
    //Recover Tokens in case incorrect amount was sent to contract.
    function recoverFailedLock() external notLocked notAllocated onlyOwner {

        // Transfer all tokens on this contract back to the owner
        require(token.transfer(owner, token.balanceOf(address(this))));
    }

而锁仓的代币中的0.1亿总量在2年后一次性分配:

//Claim tokens for final reserve wallet
    function claimTokenReserve() onlyTokenReserve locked public {

        address reserveWallet = msg.sender;

        // Can't claim before Lock ends
        require(block.timestamp > timeLocks[reserveWallet]);

        // Must Only claim once
        require(claimed[reserveWallet] == 0);

        uint256 amount = allocations[reserveWallet];

        claimed[reserveWallet] = amount;

        require(token.transfer(reserveWallet, amount));

        Distributed(reserveWallet, amount);
    }

2.4亿总量每三个月解锁一次:

//Claim tokens for Musk team reserve wallet
    function claimTeamReserve() onlyTeamReserve locked public {

        uint256 vestingStage = teamVestingStage();

        //Amount of tokens the team should have at this vesting stage
        uint256 totalUnlocked = vestingStage.mul(allocations[teamReserveWallet]).div(teamVestingStages);

        require(totalUnlocked <= allocations[teamReserveWallet]);

        //Previously claimed tokens must be less than what is unlocked
        require(claimed[teamReserveWallet] < totalUnlocked);

        uint256 payment = totalUnlocked.sub(claimed[teamReserveWallet]);

        claimed[teamReserveWallet] = totalUnlocked;

        require(token.transfer(teamReserveWallet, payment));

        Distributed(teamReserveWallet, payment);
    }

    //Current Vesting stage for Musk team 
    function teamVestingStage() public view onlyTeamReserve returns(uint256){

        // Every 3 months
        uint256 vestingMonths = teamTimeLock.div(teamVestingStages); 

        uint256 stage = (block.timestamp.sub(lockedAt)).div(vestingMonths);

        //Ensures team vesting stage doesn't go past teamVestingStages
        if(stage > teamVestingStages){
            stage = teamVestingStages;
        }

        return stage;

    }

从上面的代码我们可以看到这里的解锁条件需要满足以下条件:

1、 之前已成功锁仓
2、 自我每3个月调用一次claimTeamReserve进行解锁(需要使用teamReserveWallet地址),最后的一次(第8次)解锁可以调用claimTeamReserve和claimTokenReserve(解锁0.1亿总量)来解锁。

于是我们将解锁失败的原因总结了一下下并请客户进行锁仓和解锁操作:
1、合约的owner(0xB)没有调用allocate函数来锁仓,也就没有后面的解锁操作了
2、锁仓失败而且没有调用recoverFailedLock()来回收锁仓失败的token
3、解锁调用函数调用错误,每次解锁时应当调用teamVestingStage函数来解锁,而且调用者的地址需要为teamReserveWallet(0xA),第8次解锁时需要调用teamVestingStage函数以及claimTeamReserve函数来完成最后的解锁

深入分析

通过上面的分析并给予客户处置建议后客户进行操作发现并无效果,再次找到了我们寻求协助查看到底是什么问题,所以我们对链上的交易和合约内容进行了进一步的分析,这次的好处是提供了链上的查询地址,之前要了并没给,直接让看代码,不过最后我们也发现其实根源也还是在代码中,不过有点呆,具体看下面的分析记录:
首先我们在etherscan上查看锁仓合约的交易信息,发现一共有2次交易,一次是创建合约,另外一次是调用函数allocate进行锁仓操作

某次锁仓合约应急响应分析记录,区块链

锁仓操作交易细节如下:

某次锁仓合约应急响应分析记录,区块链


查看ERC20交易,可以看到musk合约创建后,转了2.5亿到锁仓合约,锁仓操作流程无误:

a. 创建代币合约、锁仓合约
b. 代币合约向锁仓合约转账,转账数量为锁仓总量
c. 锁仓合约执行锁仓操作

某次锁仓合约应急响应分析记录,区块链

根据以上分析得出结论为客户没有收到解锁token的原因是因为没有主动调用解锁函数去解锁,之后通过语音和视频交流的方式指导客户进行解锁操作,在解锁过程中使用MyCrypto以太坊钱包客户端与锁仓合约进行交互并成功解锁375万token,具体操作与交易记录如下

某次锁仓合约应急响应分析记录,区块链

某次锁仓合约应急响应分析记录,区块链

解锁操作后虽然客户账户成功解锁了375万,但是与预期的数量2.4亿/83()不一致,目前已经确认客户没有收到锁仓合约解锁token的原因是由于客户没有主动调用锁仓合约的解锁函数去解锁,下面继续分析解锁数量不正确的问题,
经过查看锁仓合约源代码,发现锁仓合约中的teamReserveWallet和finalReserveWallet两个锁仓操作的地址(这里做了匿名,直接用0xA来替代)一致:

contract XXX is Ownable {
    using SafeMath for uint256;

    //Wallet Addresses for allocation
    address public teamReserveWallet = 0xA;
    address public finalReserveWallet = 0xA;

    //Token Allocations
    uint256 public teamReserveAllocation = 240 * (10 ** 6) * (10 ** 18);
    uint256 public finalReserveAllocation = 10 * (10 ** 6) * (10 ** 18);

    //Total Token Allocations
    uint256 public totalAllocation = 250 * (10 ** 6) * (10 ** 18);

    uint256 public teamTimeLock = 2 * 365 days;
    uint256 public teamVestingStages = 8;
    uint256 public finalReserveTimeLock = 2 * 365 days;

    /** Reserve allocations */
    mapping(address => uint256) public allocations;

    /** When timeLocks are over (UNIX Timestamp)  */  
    mapping(address => uint256) public timeLocks;

    /** How many tokens each reserve wallet has claimed */
    mapping(address => uint256) public claimed;

    /** When this vault was locked (UNIX Timestamp)*/
    uint256 public lockedAt = 0;

    MuskToken public token;

    /** Allocated reserve tokens */
    event Allocated(address wallet, uint256 value);

在锁仓过程中由于锁仓地址一致,而同一变量allocations[WalletAddress]进行两次赋值,则第二次的0.1亿将会覆盖第一次的2.4亿的赋值,最后的allocations[WalletAddress]值为0.1亿,故真正实现锁仓的代币数量为0.1亿token,经计算0.1亿/8*3=375万,符合解锁数量

function allocate() public notLocked notAllocated onlyOwner {

        //Makes sure Token Contract has the exact number of tokens
        require(token.balanceOf(address(this)) == totalAllocation);

        allocations[teamReserveWallet] = teamReserveAllocation;
        allocations[finalReserveWallet] = finalReserveAllocation;

        Allocated(teamReserveWallet, teamReserveAllocation);
        Allocated(finalReserveWallet, finalReserveAllocation);

        lock();
    }

分析总结

客户反映多个月过去没有收到解锁token的原因是因为锁仓合约不是自动按时解锁的,需要主动调用解锁函数去解锁,后经过指导客户进行解锁操作成功解锁375万token,后因为解锁token数量有误差,经过分析查看锁仓合约源代码,发现allocate函数中存在同一变量两次赋值问题,在锁仓过程中真正锁仓的数量只有0.1亿token,由于锁仓合约已经部署完成,无法修改所以目前只能为客户追回的资产总量为0.1亿token(后续每隔3个月解锁一次)。基于本次的应急响应分析也深刻意识到合约审计过程中的细微之处不可忽略,同时也意识到合约研发人员不可偷懒,要对一些关键的变量,尤其是全局变量进行名词专用,不要过于去节省gas或者节省笔墨,安全很是重要文章来源地址https://www.toymoban.com/news/detail-848240.html

到了这里,关于某次锁仓合约应急响应分析记录的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 应急响应实战笔记02日志分析篇(5)

    常见的数据库攻击包括弱口令、SQL注入、提升权限、窃取备份等。对数据库日志进行分析,可以发现攻击行为,进一步还原攻击场景及追溯攻击源。 0x01 Mysql日志分析 general query log能记录成功连接和每次执行的查询,我们可以将它用作安全布防的一部分,为故障分析或黑客事

    2024年02月21日
    浏览(35)
  • 应急响应之windows日志分析工具logparser使用

    目录 一、logparser简介 (一)logparser介绍 (二)下载链接 二、logparser安装 三、基本查询结构 四、使用Log Parser分析日志 (一)查询登录成功的事件 1. 登录成功的所有事件 2. 指定登录时间范围的事件 (二)提取登录成功的用户名和IP (三)查询登录失败的事件 1. 登录失败的

    2023年04月09日
    浏览(30)
  • 应急响应 - Windows启动项分析,Windows计划任务分析,Windows服务分析

    「作者简介」: CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」: 对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 很多恶意程序会把自己添加到系统启动项中,在开机时自动运行。 msconfig是Windows自带的系统配置实用程序

    2023年04月17日
    浏览(43)
  • 应急响应 - Windows用户分析,Windows隐藏账号分析,Windows克隆账号分析

    「作者简介」: CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」: 对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 攻击者通常会在服务器中创建用户进行维权,查看是否有新增的可疑账号,核实后禁用或删除。 cmd中,输

    2023年04月22日
    浏览(35)
  • 74应急响应-win&linux分析后门&勒索病毒&攻击

    #操作系统(windows,linux)应急响应: 1.常见危害:暴力破解,漏洞利用,流量攻击,木马控制(Webshell,PC 木马等),病毒感染(挖矿,蠕虫,勒索等)。 2.常见分析:计算机账户,端口,进程,网络,启动(木马需要运行,除了伪装成正常文件就是自启动),服务,任务,文件(文件

    2024年01月21日
    浏览(43)
  • 应急响应 - Windows进程分析,Windows网络分析,tasklist,wmic process

    「作者简介」: CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」: 对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 tasklist命令用来查看计算机上的进程,默认显示所有进程。 参数/v,可以显示详细信息,也就是显示所有

    2023年04月14日
    浏览(46)
  • 【应急响应】网站入侵篡改指南&Webshell内存马查杀&漏洞排查&时间分析

    应急响应: 1、抗拒绝服务攻击防范应对指南 2、勒索软件防范应对指南 3、钓鱼邮件攻击防范应对指南 4、网页篡改与后门攻击防范应对指南 5、网络安全漏洞防范应对指南 6、大规模数据泄露防范应对指南 7、僵尸网络感染防范应对指南 8、APT攻击入侵防范应对指南 9、各种辅

    2024年01月20日
    浏览(34)
  • 应急响应-勒索病毒检测指南&Win&Linux样本演示&家族识别&分析解密

    勒索病毒是一种新型电脑病毒,主要以RDP爆破、邮件、程序木马、网页挂马的形式进行传播。该病毒性质恶劣、危害极大,一旦感染将给用户带来无法估量的损失。这种病毒利用各种加密算法对文件进行加密,被感染者一般无法解密,必须拿到解密的私钥才有可能破解。201

    2024年04月14日
    浏览(48)
  • Shell管理工具流量分析-上(菜刀、蚁剑、冰蝎2.0流量分析)&入侵检测、应急响应资料整理

    本文将会从攻防的角度分析常用 webshell 管理工具(菜刀、蚁剑、冰蝎2.0,冰蝎3.0、哥斯拉将在下篇介绍)的流量特点,后半部分会整理一些有关 webshell 入侵检测和应急响应的文章 先从最简单的开始吧,菜刀也算是比较早的 webshell 管理工具了,加密方式比较简单,这里分析

    2024年02月02日
    浏览(28)
  • slither——区块链智能合约静态分析工具

    Slither是一个用Python 3编写的智能合约静态分析框架(源码),提供如下功能: 自动化漏洞检测。提供超30多项的漏洞检查模型,模型列表详见:https://github.com/crytic/slither#detectors 自动优化检测。Slither可以检测编译器遗漏的代码优化项并给出优化建议。 代码理解。Slither能够绘

    2024年01月16日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包