作为一个区块链的小白,一直想复现短地址攻击。但是在网上参考了很多大佬们的文章,发现很多文章都只是简单介绍了这种攻击的原理,但是具体的复现,简单带过,像我这种菜鸡要想跟着复现还是很难的。所以从开始研究到复现,着实踩了不少坑,今天就把我复现期间的一些细节写出来,分享给大家。
我在Centos上复现的:
需要安装:nodejs、 git、wget、,vim、gcc-c++、ntp、 epel、cmake3.x: (智能合约需要cmake3.x版本才可以编译)、golang、go-ethereum、keythereum、web3.js、ethereumjs-tx
需要安装的东西有点多,为保证文章不是大量篇幅都在讲安装(虽然我很多时间都浪费在了安装上),我就不写详细的安装步骤了,推荐两个我安装时参考的文章:
https://blog.csdn.net/xc70203/article/details/77988473
https://blog.csdn.net/long085/article/details/80294910
没有涉及到的,那么基本使用npm就可以安装。
安装时如果遇到报错:可以尝试使用淘宝源安装、或者是指定版本安装。说多了都是泪,虽然我没有完全把各个软件都装好,但是勉强可以完成复现。
环境安装好之后,就可以开始漏洞的复现了。
1. 先编写我们自己的以太坊私有链创世区块的json文件,内容如下,其中chainId的值可以随机,但是应该大于0,大于0表示就是私有链:
在该路径下初始化一下(“geth init genesis.json”):
初始化之后,就可以开启我们的私有链的,贴图中框内是私有链创建之后运行期间的文件保存路径,包括区块信息,信息等。如果第一次复现失败,再次进入控制台时发现无法挖矿,或者挖不到矿,可以考虑简单暴力的办法,把这些文件删掉,重新初始化配置文件。
2. 使用命令开启终端:
因为直接使用“geth console”开启终端的话,其日志等等一些信息会不断的刷新,严重影响我们输入命令,所以我们使用“geth —networkid 1000 console 2>>geth.log”将日志信息输出到本路径下geth.log文件中, —network参数指定我们所要连接的私有链的ID,即我们之前在genesis.json文件中的“chainId”
3. 刚创建私有链时,是没有一个账户的,我们使用“personal.newAccount(“123”)”命令生成新的账户。多次生成账户,直到生成我们需要的账户地址(地址末尾有两个0,目前猜测是必须要是2的倍数,因为我使用1个0的进行测试,没有成功,但是3个或以上的地址实在是太难生成了,全看运气,所以就没测试)值得注意的是,我一开始的时候密码使用的是“1”而不是“123”,但是生成了将近200个账户都没有结尾是两个0的账户(很多次尝试,也浪费了不少时间),网上有些人说理论上生成256个账户,就会有一个结尾为“00”的。我尝试了使用密码“123”后,很多次都是在10个账户以内或者稍多一些就生成了“00”结尾的账户,不知道究竟是什么原因。毕竟是玄学。
personal.newAccount("123")
4. 我们需要把地址整理一下,因为私链默认的挖矿账户是第一个生成的账户,我们也不多此一举去修改它,就用它来部署合约,所以我们需要保留的就是第一个账户地址和生成的“靓号”地址:
5. 接下来就是部署合约了,但是部署合约之前需要挖矿,因为现在每个账户都没有钱,而部署合约是需要花钱的。所以使用“miner.start()”开始挖矿,为确保挖矿正常进行,使用“eth.blockNumber”查看区块的数量是否变多,也可以使用“eth.getBalance(addr1)”来查看账户中是否有以太币,单位wei。“miner.stop()”停止挖矿。
6. 编写智能合约,这里借鉴了某大佬的代码,我能成功复现这个漏洞,大佬的文章简直就是指路明灯(https://blog.csdn.net/TurkeyCock/article/details/84061796#commentBox),而我复现的整个过程也是使用了大佬的思路,因为功能简单,直接转账就行。其实自己编写也就那样,一个转账函数一个查询函数,毕竟是在命令行交互界面运行,能简单就简单,不要那些存款啦什么的骚操作了。
7. 将代码在Remix中编译完成,在“Details”中将WEB3DEPLOY复制:
8. 在控制台中解锁账户,部署合约:
部署合约直接将刚刚复制的“WEB3DEPLOY”粘贴进控制台就可以了。
挖矿,打包交易,显示合约地址,停止挖矿一气呵成:
9. 生成ABI字节码:
var short_address = short_addressContract.at('合约地址')var abi = short_address.transfer.getData('靓号', 转账的代币数)
我们这里向目标地址转账1个代币。
保存好这个abi。
10. 获取账户addr1的私钥(这里也是我踩过的一个坑,刚开始以为私钥就是keystore路径下的对应UTC文件中的“ciphertext”的值,导致解决问题的方向出错,浪费了很多时间,甚至差点放弃,后来由于刷新了一下发际线高度,发现了问题所在。)
获取私钥参考文章:https://www.cnblogs.com/wanghui-garcia/p/9519873.html。
11. 编写脚本生成“raw transcation”,需要用到私钥、合约地址、abi。
node运行脚本,得到签名后的交易:
12. 使用eth.sendRawTranscation()发送交易,得到交易hash:
13. 继续挖矿,使交易被打包进区块,确定队列中没有交易在等待,就可以停止挖矿了:
14. 查看对应的账户,复现成功,撒花撒花:
有时候可能会复现失败,没关系,多复现几次,总有一次会成功的,年轻人,要有耐心。
临终总结:玄学真不是我等凡人可触碰的,计算机学起来挺有意思的,就是脑袋有点凉,不说了,买霸王去了。
*本文作者:18611588432,本文属 FreeBuf 原创奖励计划,未经许可禁止转载。