Skip to content

Misc专题二:流量取证/区块链基础

约 2423 个字 7 行代码 3 张图片 预计阅读时间 10 分钟

流量取证

流量取证基础

网络流量(\(\rightarrow\) 回顾 web 基础)

  • 应用层(HTTP/FTP/...) \(\rightarrow\) 表示层 \(\rightarrow\) 会话层(SSL/TLS/...)
  • \(\rightarrow\) 传输层(TCP/UDP) \(\rightarrow\) 网络层(IP/ICMP/...)
  • \(\rightarrow\) 数据链路层 \(\rightarrow\) 物理层

最终传输的仍然是二进制数据

  • 捕获这些数据, 就可以分析得到正在进行的通信内容

流量取证一般就是拿到这些数据包(cap、 pcap、 pcapng 格式)进行分析

  • 如有损坏的话修复数据包(少见, pcapfix 可以修复)
  • 分析、 提取得到正在通信的内容(可能包含有效信息)
  • 分析一些特定的、 不太常见的协议(比如一些自定义协议)
  • 分析、 解密一些加密的协议(比如 VMess 等)

流量取证常用工具

  • tcpdump 抓 TCP 包(Linux 命令行)
  • Wireshark: 直接抓包, 得到物理层的全部数据并解析(开源)
    • 自带命令行工具 tshark
  • termshark: 类似 Wireshark 的开源命令行工具
  • pyshark: tshark 的 Python 封装, 可以用 Python 脚本分析
  • scapy: Python 库,

Wireshark 基本用法

浏览主界面的所有数据包, 大致了解都由什么协议组成

追踪流(追踪 TCP 流 / 追踪 HTTP 流)

  • 得到某次通信的全部数据包, 并进行解析
  • 另存为, 保存流数据
  • 可以转换不同的显示形式(ASCII、 HEX、 Raw)

文件 > 导出, 提取某些数据包的流内容

统计部分

  • 协议层次: 统计各层协议的数据包数量
  • 流量图: 统计各个端口的流量, 可视化显示
  • HTTP: 分组计数、 请求统计

Wireshark 过滤器

过滤协议: 直接输入 tcp/udp/http 等

过滤 ip: ip.addr == xx.xx.xx.xx 或 ip.src ip.dst

过滤端口: tcp.port == 80 或 tcp.srcport tcp.dstport

包长度过滤: frame.len ip.len tcp.len ……

http 过滤

  • http.request.method == GET
  • http.request.uri == "/index.php"
  • http contains "flag"(相当于搜索功能)

HTTP 协议流量分析

分析统计信息

  • 查看所有的 HTTP 请求 URI
  • 分析 HTTP 往返的情况, 流量整体信息

具体分析某些请求: 利用过滤器

分析某一数据包具体内容

  • 跟踪流, 跟踪 TCP 解析 TCP, 跟踪 HTTP 可以自动解压 gzip 等
  • 分析请求头、 响应头、 请求体、 响应体等

具体题目示例

  • 本次 lab 中的题目: SQL 盲注流量分析

UDP 协议

UDP 协议是无连接的, 不需要像 TCP 一样三次握手

和 TCP/HTTP 一样直接追踪分析就可以

常见的基于 UDP 的协议: DNS

具体题目示例

  • 本次 lab 中的题目: dnscap
  • MRCTF 2022: Bleach!

    • 基于 UDP 的 RTP 协议, 需要手动选择进行解析
    • RTP 是一种音视频传输协议, 可以得到音频流
    • wav 音频流中 LSB 包含隐写图片

其他协议

ICMP 协议: ping

  • 某时也会带有一些信息, 可以进行进一步分析

OICQ 协议: QQ 使用, 是加密的, 但是可以看到双方 QQ 号等

WIFI 协议(IEEE 802.11)

  • 可以使用 Linux aircrack 套件爆破密码
  • 有了密码后可以在 Wireshark 中设置并解密流量

USB 协议

  • 安装了 USBcap 之后可以在 Wireshark 中捕获 USB 流量
  • 有工具可以解析流量, 绘制鼠标轨迹, 得到按键信息等

其他加密协议

  • VMess, 需要读文档 / 源码, 实现解密
  • 例题: 强网杯 2022 Quals 谍影重重

以太坊区块链基础

以太坊模型全览 - 区块与世界状态

区块与世界状态

每个区块包含三颗 Merkle 树根节点

  • stateRoot 即世界状态树根节点, 状态是一组用户状态的组合

区块由“矿工”或“验证者”将交易打包形成, 后广播到网络中

  • 每条交易会引发世界状态的转变, 消耗一定 gas

以太坊模型全览 - 交易与世界状态转变

交易与世界状态转变

每一条交易都会引起状态的改变

多个交易打包到一起, 最终状态就是新区块存储的状态

交易信息中包含 hash/v/r/s 为交易签名, 用于验证交易的合法性

合约在 EVM 上执行, 执行过程中也有各种漏洞

账户

外部账户(Externally Owned Account)

  • 有一对公私钥, 用于签署交易

    • 私钥是随机生成的 256 位数(32 字节)
    • 公钥由私钥经过 ECDSA 算法计算而来, 是一个 64 字节的数
    • 地址由公钥经过 Keccak-256 哈希后取前 20 字节得到

account

合约账户(Contract Account)

  • 由 EOA 通过交易创建的账户, 其中包含合约代码
  • 合约可以存储、 拥有以太币
  • 向合约账户发送交易 \(\rightarrow\) 调用合约中的函数
  • 合约本身不能主动发起交易, 但可以在被调用时向外发送交易

交易

一条交易包含以下内容:

  • from: 交易发送者地址
  • to: 交易接收者地址, 如果为空则表示是在创建智能合约
  • value: 交易金额, 即发送方要给接收方转移的以太币数量(wei 为单位)
  • data: 交易数据, 如果是创建智能合约则是智能合约代码, 如果是调用智能
  • 合约则是调用的函数名和参数
  • gasPrice: 交易的 gas 价格, 即每单位 gas 的价格(wei 为单位)
  • gasLimit: 交易的 gas 上限, 即交易允许执行的最大 gas 数量
  • nonce: 交易的序号, 即发送者已经发送的交易数量

除此之外发送的交易数据包还需要包含:

  • hash: 交易的哈希值, 由前面的内容和 chainId 计算得到
  • v、 r、 s: 交易签名的三个部分, 由发送者私钥对交易哈希值进行签名得到

以太币单位: https://converter.murkin.me/

关于链与 faucet

公开链: 真实的交易

私链: 自己搭建的链, 模拟真实的链

  • 一般 CTF 题目都使用私链部署
  • 可以通过 geth 等工具部署私链

more

智能合约安全基础

关于合约

合约的创建和调用都通过交易来进行

合约调用:

  • data 字段为编码后的函数名(selector)和参数, 称为 calldata
  • selector 是函数签名 keccak256 的前四个字节
  • 不存在对应 selector 则会调用 fallback 函数, 还不存在则 revert

合约存储: 全公开存储, 都在链上, 可以 getStorageAt 查看

revert: 回滚, 所有当前调用中的状态改变全都复原

合约编译后得到字节码在 EVM 上运行:

Solidity 语言

https://note.tonycrane.cc/ctf/blockchain/eth/solidity/

官方文档:https://docs.soliditylang.org/en/latest/index.html

以太坊官方的编写智能合约的语言

IDE:https://remix.ethereum.org/

通过 contract 关键字声明一个合约

通过 function 定义一个可以调用的函数

  • public、 internal、 external、 private
  • 属性(状态)会自动创建 getter 函数
  • 通过 view、 pure 关键字定义一个不改变状态的函数

通过 payable 关键字定义一个可以接收以太币的函数

特殊函数: constructor、 fallback、 receive

常见漏洞示例

整型溢出

Ethernaut 题目 Token:

mapping(address => uint256) balances;
function transfer(address _to, uint256 _value) public returns (bool) {
    require(balances[msg.sender] - _value >= 0);
    balances[msg.sender] -= _value;
    balances[_to] += _value;
    return true;
}
  • balances 字典是 uint256, 无符号减法有溢出风险
  • 给任意地址转账, 原余额 20 Token, 转 21 个, 则 balances 会变的巨大
  • 通过事先检查或者使用 SafeMath 库可以避免
  • 新版本 solidity 自动开启了溢出检查

重入攻击

Ethernaut 题目 Re-entrancy, 很经典的智能合约漏洞,例如如下合约:

contract Bank {
    mapping(address => uint256) balances;
    ...
    function withdraw(uint256 amount) public {
        require(balances[msg.sender] >= amount);
        msg.sender.call.value(amount)("");
        balances[msg.sender] -= amount;
    }
}

withdraw 时先转钱再更新 balances

转钱的时候会进入到目标合约的 fallback 函数, 可以再次调用 withdraw

再次调用时 require 检查的仍然是老的 balances

这样可以把钱取空

伪随机数

区块链需要所有以太坊节点验证交易计算出相同结果达成共识

无法实现真随机数

伪随机可以破解:

  • 利用区块变量作为随机数: 可以获取
  • 利用 blockhash 作为随机数: 只保留最近 256 个区块
  • 回滚攻击: 不断 revert 来猜随机数

Ethernaut 题目 Coin Flip, 留作作业。

其他常见漏洞: https://note.tonycrane.cc/ctf/blockchain/eth/vuln/

CTF 比赛中的私链题目交互

一般会过滤掉大部分 geth rpc 接口

  • 防止其他队伍扒链蹭车 / 重放
  • 白名单示例可见 chainflag/solidctf 中的白名单,一般就是这些
  • geth 手动操作很复杂(只能发 raw), remix/metamask 可能会无法连接

可以 / 推荐通过 web3.py 进行交互

  • 通过 eth.contract 和 abi 与 addr/bytecode 创建合约对象
  • 通过 contract.functions.f().build_transaction() 构建交易
  • 通过 eth.account.sign_transaction(txn, privateKey) 签名
  • 得到 rawTransaction 后 eth.send_raw_transaction(raw) 发送
  • 通过 eth.wait_for_transaction_receipt(hash) 等待交易完成
  • 无需交易的 view 函数可以直接 contract.functions.f().call()

https://note.tonycrane.cc/ctf/blockchain/eth/basic/#_15

more

Read more: https://note.tonycrane.cc/ctf/blockchain/eth

以太坊基础知识: 账户、 交易、 合约、 区块等, 及其原理

Solidity 语言: 最常用的智能合约语言, 以太坊官方语言

  • 了解其语法、 类型, 以及合约运行的整体逻辑
  • 了解一些 ERC 标准(目的是看懂题目的合约)

以太坊虚拟机(EVM) : 执行合约字节码的栈结构虚拟机

  • 了解其运行原理, 与账户、 合约、 交易的关系, 反汇编、 反编译的方法

交互、 测试环境: geth、 Remix、 MetaMask、 web3.js、 web3.py 等

常见合约漏洞: 整型溢出、 重入、 伪随机、 薅羊毛、 非预期的远程调用……

入门做题平台:

  • ethernaut
  • 校巴上的几道 Blockchain 题建议有一定基础了解之后再做

Comments