ToB企服应用市场:ToB评测及商务社交产业平台

标题: Stratum挖矿协议&XMR挖矿流量分析 [打印本页]

作者: 温锦文欧普厨电及净水器总代理    时间: 2024-5-19 15:58
标题: Stratum挖矿协议&XMR挖矿流量分析
目录

媒介

之前做了一个关于“挖矿举动检测”的大创训练项目,在这里记载一下我关于挖矿相关内容的学习。
区块链和挖矿相关概念

区块链
首先需要了解一些关于区块链的内容。注意,区块链和挖矿是两个精密相关但又各自独立的概念,它们并不是同一件事。
区块链是一种分布式账本技术,它通已往中心化的方式安全地记载交易数据。每个区块包含一组交易记载,并通过加密的方式与前一个区块链接起来,形成一个不可篡改的链式结构。这种设计使得区块链具有很高的安全性和透明性。
简朴地说,区块链就好比一个公共的账簿,任何人都可以检察账簿中的记载,但一旦记载被写入,就很难更改或删除。这本账簿由网络中的许多人共同维护,每个人都持有账簿的副本。假如想要修改某一条记载,那么就要修改所有的人手中账簿的记载,这是很难做到的。因此很难对其举行篡改。
区块链的几个核心特点:去中心化、不可篡改、透明性、共识机制、智能合约等。
区块
区块链的一个核心组成部分就是区块,区块链也可以说是由多个区块按照时间序次连接形成的链式数据结构。
每个区块通常包含以下内容:
访问这个网站:https://blockchair.com/ 可以欣赏各类加密货币的区块情况。
比如下图中的Bitcoin blocks,可以清晰的看到此时最新的一个比特币块为842040,这个块的哈希值为00000...e11a0,时间戳为2024-05-04 10:30:57UTC,由矿工Foundry USA Pool挖到。

区块链相关概念就了解这么多,接下来看看挖矿是怎么回事。
挖矿相关术语
挖矿 是个将待确认的交易数据包含到区块链中,从而完成对这些交易举行确定的分布式共识体系。
挖矿的目的是什么?
通过挖矿,可以欺凌性保证块链中的数据按时间序次存储,保持比特币网络的中立性,且允许比特币网络上不同的计算机对体系状态达成一致。交易要得到确认,必须要被打包到一个符合非常严格的密码学规则的区块中,并通过比特币网络举行验证。这些规则可以防止对已有块的修改,因为一旦有改动,之后所有的块都将失效。挖矿的难度和中彩票相当,没人可以轻易地、一连地将新块加入到块链中。因此,没有集体和个人可以控制块链中包含什么样的内容大概更换掉块链中的部分内容以到达打消他们交易的目的。这就是一个到达共识的过程,网络中的节点通过共识机制来验证和记载新的交易,常见的共识机制包括工作量证实(PoW)和权益证实(PoS)。
说白了挖矿就是通过计算一个困难,优先得到记账权利,从而得到夸奖。
下面这个脚本大致描述了挖矿的过程:
  1. # 挖矿函数示例工作量证明(PoW)
  2. def mine_block(version, previous_block_hash, merkle_root_hash, time_stamp, difficulty):
  3.     '''
  4.     计算当前的区块头数据的SHA-256哈希值,改变nonce随机数,直到计算出小于目标值的hash
  5.     version 版本
  6.     previous_block_hash 前一个区块头的哈希值
  7.     merkle_root_hash 当前块默克尔树根的哈希值,当前区块所有交易产生的默克尔树根节点的哈希值
  8.     time_stamp 时间戳
  9.     difficulty 当前区块PoW算法的难度值
  10.     nonce 随机数
  11.     '''
  12.     # 根据当前难度值计算出一个目标值(控制在大约10分钟的计算量)
  13.     # 难度值受到网络上的总计算能力的影响,挖矿的难度会根据网络上的总计算能力进行自动调整
  14.     target = calculate_target(difficulty)
  15.     nonce = 0
  16.     while True:
  17.         # 构建区块头数据
  18.         block_header = f"{version}{previous_block_hash}{merkle_root_hash}{time_stamp}{difficulty}{nonce}".encode('utf-8')
  19.         # 计算SHA-256哈希值(两次)
  20.         hash_temp = hashlib.sha256(block_header).hexdigest()
  21.         hash_result = hashlib.sha256(hash_temp.encode()).hexdigest()
  22.         # 将哈希值转换为大整数与target比较,是否达到目标
  23.         hash_int = int(hash_result, 16)
  24.         if hash_int < target:
  25.             print("Nonce:", nonce)
  26.             print("Hash:", hash_result)
  27.             break
  28.         # 随机数+1(运算在千亿次数量级)
  29.         nonce += 1
复制代码
简朴地说,挖矿就是不停修改区块头中的参数,并计算区块头的散列值,直到其散列值与目标难度相匹配的过程。散列函数的结果无法提前得知,也没有能得到一个特定散列值的模式,所以这个过程十分消耗计算资源。
聊了这么多,区块链和挖矿的概念这些都不是重点,大概了解就好。重点是恶意的挖矿木马会对的主机造成严重的影响,要通过一些手段把识别这些恶意步伐,并做出应急的处置。
挖矿木马

市面上除了比特币,还有许多其他加密货币。比如以太坊(ETH)、莱特币(LTC)、门罗币(XMR)等。
挖矿木马的常见样本
还有非常多各种类型的挖矿木马,这里不先容了。
挖矿木马控制呆板挖矿的方式
挖矿木马举动特性
挖矿木马明显的举动特性就是极大的占用CPU及GPU资源。主要包括:CPU和GPU使用率高、相应速度慢、 崩溃或频繁重新启动、体系过热、异常网络运动。其次是在网络流量中,挖矿木马通讯过程接纳专门的通讯协议,因此存在肯定的网络通讯特性。
检测方法
我们接纳的是基于网络侧检测的方案,主要是分析挖矿数据包中的一些特性值举行检测。
挖矿协议Stratum

Stratum协议在2012年被提出,目的是扩展对矿池挖矿的支持,并取代了旧的getwork协议。Stratum协议允许矿机通过TCP连接与矿池使用 JSON-RPC 2.0 消息编码举行通讯,从而接收挖矿任务并提交工作证实。
Stratum工作过程

1. 矿机连接服务器
矿机使用 mining.subscribe 方法连接矿池,订阅当前连接。
  1. {
  2.     "id": 1,
  3.     "method": "mining.subscribe",
  4.     "params": []
  5. }
复制代码
矿池返回相关信息,需要矿工记载在本地。
  1. {
  2.   "id": 1,
  3.   "result": [
  4.     [
  5.       "mining.set_difficulty",
  6.       "subscription id 1"
  7.     ],
  8.     [
  9.       "mining.notify",
  10.       "subscription id 2"
  11.     ]
  12.   ],
  13.   "08000002": 4,
  14.   "error": null
  15. }
复制代码
mining.set_difficulty:用于矿池去设置矿机当前提交任务的最大难度值。
mining.notify:用于矿池向矿机发送新的挖矿任务。
extranonce1:十六进制编码,每个连接唯一的字符串,稍后将用于创建生成的事务。
extranonce2_size:指定在挖矿过程中使用的额外随机数(extranonce2)的巨细。
在上面这个示例 "08000002": 4 其中 08000002 表示extranonce1的值,4 表示extranonce2的长度为4字节。
2. 矿工认证
矿机使用 mining.authorize 方法向矿池提供登录凭据,矿池根据提供的信息验证矿工的权限。
  1. {
  2.     "id": 2,
  3.     "params": [
  4.         "miner",
  5.         "password"
  6.     ],
  7.     "method": “mining.authorize”
  8. }
复制代码
矿池返回授权。
  1. {
  2.    "error": null,
  3.    "id": 2,
  4.    "result": true
  5. }
复制代码
注意这里的这个id号是用来区矿工和矿池的应答消息的,并不是矿工的id。因为矿池的应答消息结构有些很雷同,矿机就是通过消息的id来区别这些消息是对应哪个发送消息的应答。
还有通过 jsonrpc 方式登录的,下面会提到。
3. 矿池向矿机下发挖矿工作任务
当矿池在被订阅之后,会使用 mining.notify 方法给矿机发送最少一个工作任务。
  1. {
  2.     "params": [
  3.         "bf",
  4.         "4d16b6f85af6e2198f44ae2a6de67f78487ae5611b77c6c0440b921e00000000",
  5.         "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff20020862062f503253482f04b8864e5008",
  6.         "072f736c7573682f000000000100f2052a010000001976a914d23fcdf86f7e756a64a7a9688ef9903327048ed988ac00000000",
  7.         [],
  8.         "00000002",
  9.         "1c2ac4af",
  10.         "504e86b9",
  11.         false
  12.     ],
  13.     "id": null,
  14.     "method": "mining.notify"
  15. }
复制代码
按序次描述 params 中每个字段:
4. 矿机开始挖矿
4.1 构建 coinbase 信息
为什么需要构造coinbase信息?
coinbase交易的存在是网络共识算法的一部分,coinbase交易是每个新区块中的第一个交易,它确认了区块的创建和挖矿过程的乐成。在挖矿过程中,矿工需要找到一个特定的哈希值,就修改coinbase交易中的Nonce字段并重新计算区块哈希。
总之,构造coinbase信息对于挖矿过程至关重要,它不仅是矿工得到夸奖的手段,也是维护区块链安全性和完整性的关键环节。
构建coinbase信息要用到的数据:coinb1,extranonce1,extranonce2_size,coinb2
在上面的交互过程中已知extranonce2_size,所以能够产生有效的extranonce2。构造coinbase只需要把这几个部分拼接起来:
  1. coinbase =  coinb1 + extranonce1 + extranonce2 + coinb2
复制代码
固然这个conbase还需要举行2次hash运行,投入背面的使用:
  1. # python脚本示例
  2. import hashlib
  3. import binascii
  4. coinbase_hash_bin = hashlib.sha256(hashlib.sha256(binascii.unhexlify(coinbase)).digest()).digest()
复制代码
4.2 计算 Merkle 根
根本的coinbase构建完毕了,现在就需要把区块中的其他交易给联系起来,需要计算一个merkleroot。
为什么是Merkle根?
Merkle树(也称为二叉哈希树)是一种数据结构,从区块内所有交易的哈希值开始构建,将这些哈希值配对,然后计算每个配对的哈希值,形成第二层。这个过程递归地重复,直到生成单个哈希值,即Merkle根(Merkle Root)。Merkle树允许通过Merkle证实快速验证区块中单个交易的存在性,任何对树中数据的更改都会导致Merkle根的变革。
所以说只要Merkle根没变,区块中的交易就没变。想要证实某个交易是区块的一部分时,就只需要提供Merkle根,无需提供整个区块的数据,这大大提高了服从。
构建Merkle根,使用 coinbase 和 merkle_branch 两两配对,然后把配对完成后举行2次hash运算,得到上一层的结果,然后重复上面的过程,继承配对计算,终极得到Merkle根。
  1. # python脚本示例
  2. import binascii
  3. def build_merkle_root(self, merkle_branch, coinbase_hash_bin):
  4.         merkle_root = coinbase_hash_bin
  5.         for h in self.merkle_branch:
  6.                 merkle_root = doublesha(merkle_root + binascii.unhexlify(h))
  7.         return binascii.hexlify(merkle_root)
复制代码
4.3 构建区块头
添补余下的 5 个字段:
  1. block_header = version + prevhash + merkle_root_hash + ntime + nbits + nonce
复制代码
5. 矿机向矿池提交工作量
当矿工发现符合哀求难度的任务,会使用 mining.submit 方法提交给矿池这样的share:
  1. {
  2.     "params": [
  3.         "miner",
  4.         "bf",
  5.         "00000001",
  6.         "504e86ed",
  7.         "b2957c02"
  8.     ],
  9.     "id": 4,
  10.     "method": "mining.submit"
  11. }
复制代码
按序次描述 params 中每个字段:
矿池拿到以上5个字段后,首先根据任务号id找出之前分配任务前存储的信息,然后重构区块,再验证share难度,对于符合难度要求的share,在检测是否符合全网难度。
默认share难度是1(难度1的目标是0x00000000ffff0000000000000000000000000000000000000000000000000000),矿池偶尔可以要求矿工更改share难度:
  1. {
  2.     "id": null,
  3.     "method": "mining.set_difficulty",
  4.     "params": [2]
  5. }
复制代码
这意味着收到服务器工作任务的矿工下一条任务讲改为难度2,这个数字的意思是派给矿机的任务难度是1个单位难度值的2倍。
关于更多Stratum的内容参考:https://en.bitcoin.it/wiki/Stratum_mining_protocol#Protocol
XMR挖矿流量分析

我们首选的加密货币是门罗币(Monero)。门罗币可以使用CPU或GPU举行挖矿,具有隐蔽性强,灵活性高等特点,是挖矿木马的首选,平常实境遇见的挖矿木马挖取的加密货币也险些都是门罗币。
情况搭建

XMRig挖矿步伐下载地址:https://xmrig.com/download
安装好以后,进入xmrig目录,键入 vim config.json 进入编辑模式,把user换成你的钱包地址,url为默认矿池地址,可以不更换。pass为矿机名。

保存并退出,键入 ./xmring 就可以开始愉快的挖矿了。
启动可以用以下方法:
  1. ./xmrig -u 钱包地址 -p 矿机名称 -o 矿池地址
复制代码

注意:本地挖矿需要比较好的网络情况,需要自己准备梯子。
流量分析

需要使用的工具有 tcodump 和 Wireshark 这两个,其中tcodump负责在linux抓包保存为pacp文件,Wireshark负责静态流量分析。
捕捉前 10000 个经过 eth0 接口的数据包:
  1. tcpdump -i eth0 -c 10000 -nn -w xmr_capture.pcap
复制代码
将保存的pacp包使用Wireshark打开,使用过滤器筛选出矿池端口的流量,然后右键追踪流 -> TCP Stream

红色为客户端矿机的数据包,蓝色为服务端矿池数据包。

XMR接纳Cryptonight算法作为其工作量证实的哈希函数。当使用XMRig举行挖矿时,他所接纳的CryptoNight算法大概会产生较多的网络流量,因为它需要频繁地与矿池通讯以获取新的挖矿任务。各种挖矿步伐在使用Stratum协议的数据格式都会稍有不同,包括XMRig。但是它们都遵循 JSON-RPC 2.0 的规范。
上面所提到登录认证通过mining.authorize方法,而XMRig则是通过jsonrpc方式登录:
  1. {"id":,"jsonrpc":"2.0","method":"login","params":{"login":"","pass":"","agent":"","algo":["","",""]}}
复制代码
接下来下面来分析在挖矿过程出现最为频繁的两种数据包流量,其一是XMRig挖矿客户端向矿池服务器提交挖矿工作的Request:
  1. {"id":,"jsonrpc":"2.0","method":"submit","params":{"id":"","job_id":"","nonce":"","result":""}}
复制代码
比如抓到包中的这条id为4的哀求数据:
  1. {
  2.     "id": 4,
  3.     "jsonrpc": "2.0",
  4.     "method": "submit",
  5.     "params": {
  6.         "id": "542241067",
  7.         "job_id": "542261814",
  8.         "nonce": "0a800200",
  9.         "result": "fe6a04d6530b7bdfc8d090b526a0c9211438cd48b07a43e7bc43d6c9211c0500"
  10.     }
  11. }
复制代码
按序次各个字段:
当矿池服务器接收到这个JSON哀求时,它会验证提交的哈希值是否有效,便是否满足当前网络的挖矿难度目标。
其二是矿池服务器向XMRig挖矿客户下发挖矿任务的Response:
  1. {"params":{"blob":"","target":"","job_id":""},"method":""}
复制代码
接下来分析id为4的相应数据:
在正式的相应数据之前有这样一条json数据:
  1. {
  2.   "jsonrpc": "2.0",
  3.   "id": 4,
  4.   "error": null,
  5.   "result": {
  6.     "status": "OK"
  7.   }
  8. }
复制代码
这是一个通用的乐成相应,再机矿乐成提交挖矿工作后由矿池返回。
返回的第二条数据,是矿池给挖矿客户端发送新的挖矿任务:
  1. {
  2.   "method": "job",
  3.   "params": {
  4.     "blob": "0000002025090f98bf0bb3da708a7deb62988f8ef0f4e3673b2bac4140d3e429ba8655b242128d5058ead989f769fcfcccfb31c8435d3490acfba756c13192d2dbf65536b7f2fa65d2ff001d00000000",
  5.     "algo": "ghostrider",
  6.     "height": 788962,
  7.     "job_id": "542263011",
  8.     "target": "ca860d00",
  9.     "id": "542241067"
  10.   },
  11.   "jsonrpc": "2.0"
  12. }
复制代码
这条相应是矿池向挖矿客户端提供的一个新的挖矿任务。挖矿客户端需要使用提供的 blob 数据和 algo 算法来开始挖矿工作,并尝试找到一个符合 target 要求的哈希值。
总结

对上面的json流量特性分析可以发现,主要特性字段有id,jsonrpc,method,params,job_id,nonce,result等,通过对具体通讯数据包举行相应特性字符串的检测,以此来发现挖矿举动的存在。
通过以上的方式,根本能够发现大多数的挖矿举动,但有些情况还是检测不到的。比如使用ssl对Stratum的数据举行加密,那么基于特性字符串的 DPI 技术就无能为力了。
参考文章:
https://en.bitcoin.it/wiki/Stratum_mining_protocol#Protocol
https://github.com/pangsitao/slush_stratum_protocol_zhCN/blob/master/main.md#Stratum协议
https://docs.google.com/document/d/17zHy1SUlhgtCMbypO8cHgpWH73V5iUQKk_0rWvMqSNs/edit?hl=en_US
https://zhuanlan.zhihu.com/p/571589377
https://www.freebuf.com/articles/network/195171.html
https://www.yuameshi.top/2021/05/termux-xmrig/
若有错误,欢迎指正!o( ̄▽ ̄)ブ

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4