经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 其他 » 区块链 » 查看文章
实现CTF智能合约题目的环境部署
来源:cnblogs  作者:KRDecad3  时间:2019/5/5 8:41:17  对本文有异议

本文章是参考一位大佬博客学来的。
智能合约题的环境主要包括两部分:一个是智能合约的部署,另一个就是监听合约事件进而发送flag的脚本。

智能合约部署

这里写的合约是指solidity合约,使用Remix IDE。
合约主要部署到以太坊测试链而非主链上(没钱??),几个主要的测试链:Ropsten,Rinkeby,Kovan。
这里需要一个浏览器钱包插件MetaMask(可以在FireFox和Chrom上下载),注册并申请账户后,选择测试网络(笔者选择的是Rospten):

新创建的账户是没有以太币的,需要到测试水管(在首页点击存入)申请:

有了以太币之后就可以利用Remix IDE将合约代码部署到测试网络。
这里先准备一个简单的发送flag的合约:

  1. pragma solidity ^0.4.24; //选择solidity编译器版本
  2. contract TestFlag {
  3. event victory(string b64email,string slogan); //定义事件
  4. function getFlag(string b64email) public {
  5. emit victory(b64email, "666!"); //触发此事件,发送flag到邮箱
  6. }
  7. }

整个编译器界面是这样的:

右侧选择编译器版本,然后点击Start to compile进行编译,编译成功的话右侧就会显示一个写着合约名称的绿色框框。
点击右上角的Run,Envir选择Injected Web3,账户就会自动变为你MetaMask钱包里的账户,如果之前没有部署过这个合约就点击下方红框Deploy,此时会跳出支付gas的弹窗,点击确定即可,等待几秒合约就会部署完成,最下方就会显示已部署的合约(及其地址);如果之前部署过相同合约,那么可以将合约地址复制到At Address并点击蓝色按钮加载合约,效果相同。

红框getFlag就是合约里的函数,输入一个邮箱base64字符串(双引号括上)并点击红色按钮就可以调用此函数了,通过ropsten.etherscan.io可以查到此合约的交易和事件。

智能合约的部署就这样了,但是现在调用函数还不能收到邮件,现在还缺少自动发送邮件的脚本,往下看。
注意下面的脚本需要用到合约地址和事件日志中的topic0。

邮件发送脚本的编写

先注册Infura https://infura.io 获取远程节点rpc:

点击黑色按钮创建project,然后在KEYS栏中找到ENDPOINT,Ropsten网络的URL,就是后面脚本中加载的RPC了(注意,API key不要暴露,具体什么安全规则这里咱也不知道??)。

这里使用python3编写脚本,需要用到web3的包,提前下一个(不过安装这个包有一点坑,百度一下如何下载web3.py包)。
附上python脚本:

  1. # -*- coding:UTF=8 -*-
  2. from web3 import Web3,HTTPProvider
  3. import os
  4. import time
  5. import binascii
  6. import base64
  7. import smtplib
  8. from email.mime.text import MIMEText
  9. from email.header import Header
  10. contract_address = "0x128..." # 你的合约地址
  11. contract_topic0 = "0x90c...1e8a11" # 事件日志中的topic0,针对同意合约的所有事件日志的topic0都是相同的
  12. rpc = "https://ropsten.infura.io/v3/1b8...64b0" # 你注册的Infura中的ENDPOINT
  13. flag = "flag{a_smart_contract_test}"
  14. email = {
  15. "host":"smtp.163.com",
  16. "port":25,
  17. "user":"sender@163.com", # 用来发送flag的邮箱
  18. "code":"******" # 邮箱的客户端授权码
  19. }
  20. # initial
  21. w3 = Web3(Web3.HTTPProvider(rpc))
  22. sender = smtplib.SMTP(host=email["host"],port=email["port"])
  23. sender.ehlo()
  24. sender.starttls()
  25. sender.login(email["user"],email["code"])
  26. # email content
  27. message = MIMEText("收下你的flag:"+flag, 'plain', 'utf-8')
  28. message["From"] = email["user"]
  29. message["Subject"] = Header("ctf flag","utf-8")
  30. # 发送flag的函数
  31. def sendflag(toEmail):
  32. message["To"] = toEmail
  33. sender.sendmail(email["user"],toEmail,message.as_string())
  34. # log
  35. os.system("echo "+time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) +": Get flag -- "+toEmail+" >> /tmp/variant_of_cat.log")
  36. print("send success")
  37. # 监听合约事件的函数
  38. def event():
  39. # 从网络中的事件日志中抓取符合这一合约的日志信息
  40. flag_logs = w3.eth.getLogs({
  41. "address":contract_address,
  42. "topic0":contract_topic0
  43. })
  44. if flag_logs is not []:
  45. for flag_log in flag_logs:
  46. data = flag_log["data"][2:]
  47. length = int(data[64*2:64*3].replace('00', ''),16)
  48. data = data[64*3:][:length*2]
  49. b64email = binascii.unhexlify(data).decode('utf-8')
  50. try:
  51. email = base64.b64decode(b64email).decode('utf-8')
  52. sendflag(email)
  53. except:
  54. errmsg = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())+":decode or send to b64 - {} fail".format(b64email)
  55. os.system("echo " + errmsg + ">> /tmp/variant_of_cat_error.log")
  56. print(errmsg)
  57. # 循环运行
  58. while(True):
  59. event()
  60. time.sleep(30)

运行上述脚本就可以实现一旦调用合约的getFlag函数就能执行发送flag邮件的操作了。
不过这里还有一点小毛病,就是sleep(30)可能短于新区块的产生时间,导致会连续发送多个邮件过来(我猜测是这个原因,具体后面再推断)。

参考资料

智能合约攻击面及ctf出题指南

原文链接:http://www.cnblogs.com/KRDecad3/p/10798383.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号