區(qū)塊鏈Solidity安全-call函數(shù)濫用漏洞

call函數(shù)介紹

在Solidity中兔毙,可以使用call柠辞、delegatecall尘颓、callcode三個(gè)函數(shù)實(shí)現(xiàn)跨合約的函數(shù)調(diào)用功能走触。

這里主要介紹call函數(shù)的使用,call函數(shù)的調(diào)用模型:

<address>.call(...) returns (bool)

call函數(shù)可以接受任何長(zhǎng)度疤苹、任何類型的參數(shù)互广,其傳入的參數(shù)會(huì)被填充至 32 字節(jié)最后拼接為一個(gè)字符串序列,由 EVM 解析執(zhí)行卧土。

在call函數(shù)調(diào)用的過程中惫皱,Solidity中的內(nèi)置變量 msg 會(huì)隨著調(diào)用的發(fā)起而改變,msg 保存了調(diào)用方的信息包括:調(diào)用發(fā)起的地址尤莺,交易金額旅敷,被調(diào)用函數(shù)字符序列等。

使用call函數(shù)進(jìn)行跨合約的函數(shù)調(diào)用后颤霎,內(nèi)置變量 msg 的值會(huì)修改為調(diào)用者媳谁,執(zhí)行環(huán)境為被調(diào)用者的運(yùn)行環(huán)境(合約的storage)。

通過下面的例子友酱,演示call函數(shù)的調(diào)用:

pragma solidity ^0.4.0;

contract A {
    address public temp1;
    uint256 public temp2;

    function fcall(address addr) public {
        temp1 = msg.sender;
        temp2 = 100;
        addr.call(bytes4(keccak256("test()")));
    }
}

contract B {
    address public temp1;
    uint256 public temp2;

    function test() public  {
        temp1 = msg.sender;
        temp2 = 200;
    }
}

在Remix中進(jìn)行部署晴音、調(diào)用測(cè)試:

  1. 部署合約,A合約地址: 0x100eee74459cb95583212869f9c0304e7ce11eaa , B合約地址: 0xe90f4f8aeba3ade774cac94245792085a451bc8e

    remix_1.png

  2. 調(diào)用A合約的fcall函數(shù)缔杉,使用B合約的地址作為參數(shù)


    remix_2.png
  3. 分別查看A合約和B合約的temp1和temp2變量的值:

  • A合約的temp1:0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c
  • A合約的temp2:100
  • B合約的temp1:0x100eeE74459CB95583212869f9c0304e7cE11EAA
  • B合約的temp2:200


    remix_3.png

通過上面的例子锤躁,可以看出:

在A合約中,msg.sender = address(調(diào)用者) 壮吩;在A合約中調(diào)用B合約的函數(shù)进苍,函數(shù)中加缘, msg.sender = address(A合約地址) 鸭叙。

同時(shí),在A合約中調(diào)用B合約的函數(shù)拣宏,調(diào)用的運(yùn)行環(huán)境是被調(diào)用者的運(yùn)行環(huán)境沈贝,即是B合約的運(yùn)行環(huán)境。

call函數(shù)濫用漏洞說明

利用call函數(shù)濫用漏洞勋乾,可以執(zhí)行 call注入 攻擊宋下。call注入 是一種新的攻擊方式,原因是對(duì)call調(diào)用處理不當(dāng)辑莫,配合一定的應(yīng)用場(chǎng)景的一種攻擊手段学歧。

通常情況下,跨合約間的函數(shù)調(diào)用會(huì)使用call函數(shù)各吨,由于call在相互調(diào)用過程中內(nèi)置變量msg會(huì)隨著調(diào)用方的改變而改變枝笨,這就成為了一個(gè)安全隱患,在特定的應(yīng)用場(chǎng)景下將引發(fā)安全問題,被惡意攻擊者利用横浑,施行 call注入 攻擊剔桨。

call函數(shù)的調(diào)用方式:

<address>.call(function_selector, arg1, arg2, ...)
<address>.call(bytes)

call函數(shù)擁有極大的自由度:

  1. 對(duì)于一個(gè)指定合約地址的call調(diào)用,可以調(diào)用該合約下的任意函數(shù)
  2. 如果call調(diào)用的合約地址由用戶指定徙融,那么可以調(diào)用任意合約的任意函數(shù)

同時(shí)洒缀,call函數(shù)調(diào)用,會(huì)自動(dòng)忽略多余的參數(shù)欺冀,如下:

pragma solidity ^0.4.0;

contract A {
    uint256 public aa = 0;

    function test(uint256 a) public {
        aa = a;
    }

    function callFunc() public {
        this.call(bytes4(keccak256("test(uint256)")), 10, 11, 12);
    }
}

call函數(shù)調(diào)用中的參數(shù)11树绩,12將會(huì)被自動(dòng)忽略,test函數(shù)中 aa = 10 隐轩。

call注入攻擊模型

下面的例子展示了call注入模型:

contract A {
    function info(bytes data) public{
        this.call(data);
        //this.call(bytes4(keccak256("secret()"))); //利用代碼示意
    }
    function secret() public{
        require(this == msg.sender);
        // secret operations
    }
}

在合約A中存在 info()secret() 函數(shù)葱峡,其中 secret() 函數(shù)只能由合約自己調(diào)用,在 info() 中有用戶可以控制的call調(diào)用龙助,用戶精心構(gòu)造傳入的數(shù)據(jù)(將注釋轉(zhuǎn)為字節(jié)序列)砰奕,即可繞過 require() 的限制,成功執(zhí)行 secret() 下面的代碼提鸟。

call注入攻擊引起的安全問題

權(quán)限繞過

function callFunc(bytes data) public {
    this.call(data);
    //this.call(bytes4(keccak256("withdraw(address)")), target); //利用代碼示意
}

function withdraw(address addr) public {
    require(isAuth(msg.sender));
    addr.transfer(this.balance);
}

function isAuth(address src) internal view returns (bool) {
    if (src == address(this)) {
        return true;
    }
    else if (src == owner) {
        return true;
    }
    else {
        return false;
    }
}

通過精心構(gòu)造 callFunc() 的傳入?yún)?shù)(如:this.call(bytes4(keccak256("withdraw(address)")), target); )军援,惡意攻擊者可以繞過函數(shù) withdraw() 的權(quán)限驗(yàn)證。

竊取代幣

在代幣合約中称勋,往往會(huì)加入一個(gè)call回調(diào)函數(shù)胸哥,用于通知接收方以完成后續(xù)的操作。但由于call調(diào)用的特性赡鲜,用戶可以向call傳入 transfer() 函數(shù)調(diào)用空厌,即可竊取合約地址下代幣。

function transfer(address _to, uint256 _value) public {
    require(_value <= balances[msg.sender]);
    balances[msg.sender] -= _value;
    balances[_to] += _value;
}

function callFunc(bytes data) public {
    this.call(data);
    //this.call(bytes4(keccak256("transfer(address,uint256)")), target, value); //利用代碼示意
}

漏洞預(yù)防

預(yù)發(fā)call函數(shù)濫用漏洞的最好方式是盡量減少使用call函數(shù)银酬。

如果合約邏輯無(wú)法避免跨合約的函數(shù)調(diào)用嘲更,可以采用 new 合約,并指定 function_selector 的方式揩瞪,指定調(diào)用的合約及合約方法赋朦,并做好函數(shù)參數(shù)的檢查。

    constructor() {
        b =  new  B();
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末李破,一起剝皮案震驚了整個(gè)濱河市宠哄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嗤攻,老刑警劉巖毛嫉,帶你破解...
    沈念sama閱讀 212,080評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異妇菱,居然都是意外死亡承粤,警方通過查閱死者的電腦和手機(jī)惊畏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,422評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來密任,“玉大人颜启,你說我怎么就攤上這事±嘶洌” “怎么了缰盏?”我有些...
    開封第一講書人閱讀 157,630評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)淹遵。 經(jīng)常有香客問我口猜,道長(zhǎng),這世上最難降的妖魔是什么透揣? 我笑而不...
    開封第一講書人閱讀 56,554評(píng)論 1 284
  • 正文 為了忘掉前任济炎,我火速辦了婚禮,結(jié)果婚禮上辐真,老公的妹妹穿的比我還像新娘须尚。我一直安慰自己,他們只是感情好侍咱,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,662評(píng)論 6 386
  • 文/花漫 我一把揭開白布耐床。 她就那樣靜靜地躺著,像睡著了一般楔脯。 火紅的嫁衣襯著肌膚如雪撩轰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,856評(píng)論 1 290
  • 那天昧廷,我揣著相機(jī)與錄音堪嫂,去河邊找鬼。 笑死木柬,一個(gè)胖子當(dāng)著我的面吹牛皆串,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播弄诲,決...
    沈念sama閱讀 39,014評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼愚战,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了齐遵?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,752評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤塔插,失蹤者是張志新(化名)和其女友劉穎梗摇,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體想许,經(jīng)...
    沈念sama閱讀 44,212評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡伶授,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,541評(píng)論 2 327
  • 正文 我和宋清朗相戀三年断序,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片糜烹。...
    茶點(diǎn)故事閱讀 38,687評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡违诗,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出疮蹦,到底是詐尸還是另有隱情诸迟,我是刑警寧澤,帶...
    沈念sama閱讀 34,347評(píng)論 4 331
  • 正文 年R本政府宣布愕乎,位于F島的核電站阵苇,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏感论。R本人自食惡果不足惜绅项,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,973評(píng)論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望比肄。 院中可真熱鬧快耿,春花似錦、人聲如沸芳绩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,777評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)示括。三九已至铺浇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間垛膝,已是汗流浹背鳍侣。 一陣腳步聲響...
    開封第一講書人閱讀 32,006評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吼拥,地道東北人倚聚。 一個(gè)月前我還...
    沈念sama閱讀 46,406評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像凿可,于是被迫代替她去往敵國(guó)和親惑折。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,576評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容