├── .DS_Store
├── Dockerfile
├── README.md
├── docker-compose.yml
├── pic
├── image-20210622144851380.png
├── image-20210622144914164.png
├── image-20210622144936099.png
├── image-20210622144951320.png
├── image-20210622145034085.png
├── image-20210622145042080.png
├── image-20210622145050743.png
├── image-20210622145929021.png
├── image-20210622151107225.png
├── image-20210622151110286.png
├── image-20210622151114531.png
├── image-20210622151120007.png
├── image-20210622151138532.png
└── image-20210622151152740.png
├── robot
├── .DS_Store
├── .idea
│ ├── inspectionProfiles
│ │ └── profiles_settings.xml
│ ├── misc.xml
│ ├── modules.xml
│ ├── robot.iml
│ ├── vcs.xml
│ └── workspace.xml
├── afl-fuzz
│ ├── .DS_Store
│ ├── afl-latest.tgz
│ ├── build_qemu_support.sh
│ ├── qemu-2.10.0.tar.xz
│ ├── setup_x32.sh
│ └── setup_x64.sh
├── attachments
│ ├── 13288893
│ │ ├── 13288893
│ │ ├── Dockerfile
│ │ ├── bin
│ │ │ └── cb
│ │ └── seed
│ │ │ └── sample.in
│ ├── .DS_Store
│ ├── 061837cd
│ │ ├── .DS_Store
│ │ ├── 061837cd
│ │ ├── Dockerfile
│ │ ├── bin
│ │ │ └── cb
│ │ └── seed
│ │ │ └── sample.in
│ ├── 0f3abf1d
│ │ ├── .DS_Store
│ │ ├── 0f3abf1d
│ │ ├── Dockerfile
│ │ ├── bin
│ │ │ └── cb
│ │ └── seed
│ │ │ └── sample.in
│ ├── 498d84f2
│ │ ├── 498d84f2
│ │ ├── Dockerfile
│ │ ├── README.txt
│ │ ├── bin
│ │ │ └── cb
│ │ └── seed
│ │ │ └── sample.in
│ ├── 57193dae
│ │ ├── 57193dae
│ │ ├── Dockerfile
│ │ ├── bin
│ │ │ └── cb
│ │ └── seed
│ │ │ └── sample.in
│ ├── 62059e6d
│ │ ├── 62059e6d
│ │ ├── Dockerfile
│ │ ├── bin
│ │ │ └── cb
│ │ └── seed
│ │ │ └── sample.in
│ ├── d8e4af1d
│ │ ├── Dockerfile
│ │ ├── bin
│ │ │ └── cb
│ │ ├── d8e4af1d
│ │ └── seed
│ │ │ └── sample.in
│ └── d93eef08
│ │ ├── Dockerfile
│ │ ├── bin
│ │ └── cb
│ │ ├── d93eef08
│ │ └── seed
│ │ └── sample.in
├── bin.py
├── competion.py
├── fuzz_afl.py
├── local_info.txt
├── log.txt
├── robot.py
└── sub_answer.py
└── start.sh
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/.DS_Store
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:16.04
2 |
3 | RUN sed -i "s/http:\/\/archive.ubuntu.com/http:\/\/mirrors.tuna.tsinghua.edu.cn/g" /etc/apt/sources.list
4 | RUN sed -i "s/http:\/\/security.ubuntu.com/http:\/\/mirrors.tuna.tsinghua.edu.cn/g" /etc/apt/sources.list
5 |
6 | RUN apt-get update && apt-get -y dist-upgrade
7 | RUN apt-get install -y lib32z1 xinetd
8 | RUN apt-get install -y openssh-server vim zsh git curl wget screen
9 |
10 | RUN apt-get install -y python python-dev python-pip python-numpy
11 | RUN apt-get install -y libtool libtool-bin automake bison libglib2.0-dev
12 |
13 | #更改pip源
14 | RUN mkdir /root/.pip
15 | RUN echo "[global]\nindex-url = https://pypi.tuna.tsinghua.edu.cn/simple\n[install]\ntrusted-host=mirrors.aliyun.com" > /root/.pip/pip.conf
16 |
17 | RUN pip install requests numpy
18 |
19 | # oh-my-zsh
20 | RUN sh -c "$(curl -fsSL https://gitee.com/awwwj/zsh/raw/master/install.sh)"
21 |
22 | # 指定文件夹
23 | WORKDIR /home/ctf
24 |
25 | # 写入配置文件
26 | RUN mkdir /home/ctf/robot
27 | COPY ./robot /home/ctf/robot
28 | COPY ./start.sh /
29 |
30 | # 配置afl-fuzz
31 | RUN chmod 755 /home/ctf/robot/afl-fuzz/setup_x32.sh
32 | WORKDIR /home/ctf/robot/afl-fuzz
33 | RUN sh -v -c /home/ctf/robot/afl-fuzz/setup_x32.sh
34 |
35 |
36 | # 给start.sh可执行权限
37 | RUN chmod 755 /start.sh
38 | WORKDIR /home/ctf/robot/
39 |
40 | #启动docker
41 | CMD ["/start.sh"]
42 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RHG & AutoPwn Robot
2 |
3 | ## 赛制
4 |
5 | 国内现有的自动化攻防的比赛有bctf的autopwn,以及rhg比赛,这是国内主要的两场自动化挖掘利用的比赛,还有国外的CGC比赛,本文主要讲的是这两种比赛的Robot结构
6 |
7 | 下图是选手整体的一个接入图,选手是最左边的电脑,往右接入高性能服务器,高性能服务器接入比赛平台,这些服务器的性能是非常强悍的,所以robot要采用多进程,多并发的方式,这样才能让最大化利用高性能服务器。
8 |
9 | 
10 |
11 |
12 |
13 | ### 赛制启动模式
14 |
15 | 赛事启动模式分为两种:
16 |
17 | 第一种
18 |
19 | 1、选手设备、服务器、平台互相联通
20 | 2、选手设备与服务器互相联通、选手设备及服务器均无法连同平台
21 | 3、选手设备、服务器、平台均不互相联通
22 | 4、选手设备无法联通其他,服务器、平台互相联通
23 |
24 | 
25 |
26 |
27 |
28 | 第二种
29 |
30 | 1、选手设备、服务器、平台互相联通
31 | 2、选手设备无法联通其他,服务器、平台互相联通
32 | 3、选手设备、服务器、平台均不互相联通
33 | 4、选手设备无法联通其他,服务器、平台互相联通
34 |
35 | 
36 |
37 | 这两者最大的区别是第二步,关键在于先独立平台,还是先独立选手设备,这两个要根据比赛赛前调试来修改。
38 |
39 |
40 |
41 | ### 平台交互
42 |
43 |
44 |
45 | 
46 |
47 |
48 |
49 | 服务器和平台之间的交互内容,主要是有这四个交互,分别是心跳包,获取题目信息,下载附件,提交答案这四个功能,其他的功能都是服务器在内部进行运算的
50 |
51 | ### 提交内容
52 |
53 | 这两个赛制的最大的区别就是最后提交内容的区别:RHG需要提交的是flag,需要robot对靶机进行攻击,多了自动化利用(AEG)的功能;
54 |
55 | ```python
56 | RHG:flag
57 |
58 | {
59 | user:"team1"
60 | pwd:"pwd"
61 | answer:"flag{1234}"
62 | }
63 | ```
64 |
65 | autopwn需要提交的是让elf崩溃的payload,payload需要base64编码一下。
66 |
67 | ```python
68 | AutoPwn:payload
69 |
70 | {
71 | RoundID:1
72 | user:"team1"
73 | pwd:"pwd"
74 | Payload:{
75 | ChallengeID:"dc87311d"
76 | Crash:"QUFBQUFBQUFBQQ=="
77 | #Popcal:"QUFBQUFBQUFBQQ=="
78 | }
79 | }
80 | ```
81 |
82 | 当然,autopwn也有自动化利用Popcal的题目,目的也是自动化漏洞利用,控制EIP。但是今年的第一场autopwn的题目只有crashme类型,所以本文主要涉及crashme的内容。
83 |
84 | 需要注意的是,autopwn提交时需要提交RoundID,所以提交是需要获取一下当前的round_id,否则比如说fuzz了半个小时才出结果,而轮次都更新3轮了,提交fuzz时的轮次会失败。
85 |
86 |
87 |
88 |
89 |
90 |
91 | ## 结构框架
92 |
93 | 
94 |
95 | 上图是之前使用的框架,定义了robot的类,包括了图中这些方法,这些方法都是单线的流程走下去的,先调用get_question获取题目信息,然后保存成文件,然后再调用download,同时读取之前保存的题目细节文件,再通过download保存bin细节文件,所有的题目下载完成后,然后调用fuzz,所有的fuzz结束后,保存fuzz_info,之后才会调用exploit,所有的exploit结束后,最后调用submit提交答案。
96 | 这个结构有很多问题,中间有任何一个流程出现了问题,会导致后续的流程全部中断,比如一个二进制下载出问题,会导致所有的题目都无法fuzz;
97 | 不过这个结构很好作并发,所有的并发只要读取上一阶段的保存信息,然后批量执行就行,多进程并发会容易很多;
98 | 但容错性和鲁棒性都很差。
99 |
100 | 
101 |
102 | 上图是修改后的结构框架,定义一个机器人,然后心跳包单独出去,定义competion类,用来执行题目信息获取。然后robot根据获取的题目信息,生成大量的bin实例,每个实例都有自己的下载、fuzz、exploit、提交等功能,每个bin都是多进程并发出去的。
103 | 这样的话,每个bin的工作流程都互相不影响,即便是有一个出现问题,其他bin都会照常运行,稳定性要高很多。
104 |
105 | 
106 |
107 | 这是bin类主要功能的流程,初始化然后下载,下载完成执行fuzz,最后执行submit提交
108 |
109 | ### 安装部署
110 |
111 | docker-compose
112 |
113 | ```yaml
114 | #docker-compose.yml
115 | version: '3'
116 | services:
117 | robotcontainter:
118 | build:
119 | context: .
120 | dockerfile: Dockerfile
121 | privileged: true #root权限
122 | ```
123 |
124 | 为了robot的移植性比较好,所以采用了docker-compose部署。这是docker-compose.yml的文件,主要的是最后一行,privileged设置为true,这样给了docker容器最大的权限来调用外部资源
125 |
126 | Dockerfile
127 |
128 | ```c
129 | FROM ubuntu:16.04
130 |
131 | RUN sed -i "s/http:\/\/archive.ubuntu.com/http:\/\/mirrors.tuna.tsinghua.edu.cn/g" /etc/apt/sources.list
132 | RUN sed -i "s/http:\/\/security.ubuntu.com/http:\/\/mirrors.tuna.tsinghua.edu.cn/g" /etc/apt/sources.list
133 |
134 | RUN apt-get update && apt-get -y dist-upgrade
135 | RUN apt-get install -y lib32z1 xinetd
136 | RUN apt-get install -y openssh-server vim zsh git curl wget
137 |
138 | RUN apt-get install -y python python-dev python-pip python-numpy
139 | RUN apt-get install -y libtool libtool-bin automake bison libglib2.0-dev
140 |
141 | #更改pip源
142 | RUN mkdir /root/.pip
143 | RUN echo "[global]\nindex-url = https://pypi.tuna.tsinghua.edu.cn/simple\n[install]\ntrusted-host=mirrors.aliyun.com" > /root/.pip/pip.conf
144 |
145 | RUN pip install requests numpy
146 |
147 | # oh-my-zsh
148 | RUN sh -c "$(curl -fsSL https://gitee.com/awwwj/zsh/raw/master/install.sh)"
149 |
150 | # 指定文件夹
151 | WORKDIR /home/ctf
152 |
153 | # 写入配置文件
154 | RUN mkdir /home/ctf/robot
155 | COPY ./robot /home/ctf/robot
156 | COPY ./start.sh /
157 |
158 | # 配置afl-fuzz
159 | RUN chmod 755 /home/ctf/robot/afl-fuzz/setup.sh
160 | WORKDIR /home/ctf/robot/afl-fuzz
161 | RUN sh -v -c /home/ctf/robot/afl-fuzz/setup.sh
162 |
163 |
164 | # 给start.sh可执行权限
165 | RUN chmod 755 /start.sh
166 |
167 | #启动docker
168 | CMD ["/start.sh"]
169 | ```
170 |
171 | dockerfile安装了lib32z1等一系列依赖,这里我们使用的python版本还是2.7的版本,后续会考虑移植到python3的版本,最下面更改了pip的源,然后安装robot的pip依赖
172 |
173 | 这边安装了一下oh-my-zsh,ubuntu自带的bash终端太难用了,在输入命令上话费很多时间,这里用的是gitee,不是用的gitlab,现在很多地区访问github拉文件是都被ban了,要么超时,要么访问不了。
174 | 再下面就是拷贝robot文件,配置fuzz程序的安装脚本,最后启动start.sh脚本。
175 |
176 | ## 接口分析
177 |
178 | ### 平台题目信息分析
179 |
180 | 下面是RHG平台返回的题目信息
181 |
182 | ```json
183 | {"AiChallenge":
184 | [{"challengeID":1
185 | "vm_ip":"172.16.7.13"
186 | "vm_name":"Defcon-AI-test-Release-1-ZegaKdFm"
187 | "question_port":"9001"
188 | "binaryUrl":"https:\/\/172.20.1.1\/resources\/file\/bff4819cbce2f8e6"
189 | "flag_path":"\/home\/flag1.txt"
190 | "first_blood":"3"
191 | "current_time":1616917575
192 | "attacks_count":"7"
193 | "current_score":100
194 | "score":130
195 | "question_type":"1"},
196 | {"challengeID":2,"vm_ip":"172.16.7.13","vm_name":"Defcon-AI-test-Release-1-ZegaKdFm","question_port":"9002","binaryUrl":"https:\/\/172.20.1.1\/resources\/file\/7bb1dc381ac3e13a43","flag_path":"\/home\/flag2.txt","first_blood":"1","current_time":1616917575,"attacks_count":"1","current_score":130,"score":0,"question_type":"1"}],
197 | "PointsInfo":{"aiPoints":"280"},
198 | "status":1}
199 | ```
200 |
201 |
202 |
203 |
204 |
205 | 这里针对RHG的题目包分析,可以使用cURL和requests来处理。如果使用curl会很容易操作,但是对于接受回显回比较难。requests比较推荐,首先定义一下header,然后发送get请求就行,但是需要注意的是,该请求需要对用户名密码验证,验证方法base64编码就行。另外需要注意timeout和verify。
206 | verify是取消https证书验证,线上测试的时候证书一般都是没问题的,但是线下比赛时,都是内网ip地址,https肯定会报错,需要取消证书验证。
207 |
208 | `curl -k -X GET –user user:pwd https://rhg.ichunqiu.com/rhg/api/get_question_status`
209 |
210 | ```python
211 | def get_question(self):
212 | try:
213 | basic = self.username+':'+self.password
214 | auth=base64.b64encode(basic.encode("utf-8")).decode()
215 | header = {"Authorization": "Basic "+auth,'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063'}
216 | resp = requests.get(self.url_get_question, headers=header, timeout=5, verify=False)
217 | self.gamestatus = json.loads(resp.content)['status']
218 | self.challenge = json.loads(resp.content)["AiChallenge"]
219 | except Exception as e:
220 | self.log(str(e))
221 | self.challenge = 0
222 | self.gamestatus = 0
223 | ```
224 |
225 | 下面是AutoPwn平台返回的题目信息
226 |
227 | ```json
228 | {"CurrentRound":1,
229 | "CurrentChallenge":[
230 | {"cb_id":"061837cd",
231 | "score":3,
232 | "score_method":"Crash",
233 | "cb_url":"https://anquan.baidu.com/bctf/bctf_games/061837cd.tar",
234 | "cb_provider":"team_a"},
235 | {"cb_id":"0f3abf1d","score":3,"score_method":"Crash","cb_url":"https://anquan.baidu.com/bctf/bctf_games/1/ad8d413d/1458.tar","cb_provider":"team_a"}],
236 | "scoreboard":[
237 | {"score":99,"first_blood":15,"bugs":20,"rank":1,"team":"test3"},
238 | {"score":63,"first_blood":2,"bugs":4,"rank":3,"team":"test1"}]}
239 |
240 |
241 |
242 | ```
243 |
244 | 这是autopwn的题目信息接口,可以看到和rhg还是有一些差别的,首先多了round轮次,autopwn中轮次是非常重要的,同时没有给ip和端口,因为autopwn是不需要机器人攻击平台上的靶机的,只需要把payload提交给平台,平台自行验证,还有一个区别就是cb_url,rhg下载下来就是二进制elf,而autopwn下载下来是tar的压缩包,所以还需要下载接口写一个解压的功能
245 |
246 | `curl https://anquan.baidu.com/bctf/latest_round `
247 |
248 | ```python
249 | def get_question(self):
250 | try:
251 | header = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063'}
252 | resp = requests.get(self.url_get_question, headers=header, timeout=5, verify=False)
253 | ret_con = json.loads(resp.content)
254 | self.challenge = ret_con['CurrentChallenge']
255 | self.round = ret_con['CurrentRound']
256 | return True
257 | except Exception as e:
258 | log(str(e))
259 | return False
260 | ```
261 |
262 | 这是AutoPwn的题目请求方法,autopwn这里不需要用户名和密码,直接requests get就可以了,同样需要注意超时和https的问题。整个方法的返回是true和false,用来判断比赛是否开始,还没开始的话,获取challenge和round都会报错,直接返回false。
263 |
264 | ### 心跳包接口
265 |
266 | ```python
267 | import requests
268 | from requests.auth import HTTPBasicAuth
269 | import base64
270 | import json
271 | import time
272 | import threading
273 |
274 | def run(url_heartbeat,username,password):
275 | while 1:
276 | try:
277 | ...
278 | resp = requests.get(url_heartbeat,headers=header,timeout=5, verify=False)
279 | ...
280 | def heartbeat(url_heartbeat='api/heartbeat',username='student01',password='KayVdf'):
281 | t1 = threading.Thread(target=run,args=[url_heartbeat,username,password])
282 | t1.start()
283 |
284 | if __name__ == '__main__':
285 | heartbeat(url_heartbeat='api/heartbeat',username='student01',password='KayVdf')
286 | ```
287 |
288 | 这个是心跳包的接口,发给平台,证明机器人还存活着。
289 | 这里用的是threading多线程起了服务,不影响主要的功能运行,因为是大量的sleep,在多线程中不会去抢GIL锁,所以多线程就行,不需要起多进程
290 |
291 | ### 下载接口
292 |
293 | RHG
294 |
295 | ```python
296 | def download(self):
297 | try:
298 | self.dir = "attachments/"+str(self.id)
299 | os.system("wget {url} -O {dir} --no-check-certificate --timeout=10 --tries=3".format(url = self.download_url,dir = self.dir ))
300 | if os.path.isfile(self.dir):
301 | self.log(self.dir + " download ok")
302 |
303 | else:
304 | self.log(self.dir + " download failed")
305 |
306 | except Exception as e:
307 | self.log(self.dir + " download failed")
308 | ```
309 |
310 | 这个是rhg下载的接口,需要根据二进制的id确定保存位置,根据dir确定下载位置。
311 | 需要注意的是--no-check-certificate也是跳过https的验证,防止证书出问题。给了超时,还有tries=3,这是为了防止比赛刚开始,所有队伍访问平台,肯定会卡,所以多给几次重试。
312 | RHG的平台下载下来就是二进制elf文件,比较好弄一些
313 |
314 |
315 | AutoPwn
316 |
317 | ```python
318 | def download(self):
319 | try:
320 | self.dir = "attachments/"+str(self.id)
321 | self.bin_dir = self.dir+"/cb"
322 | self.bin_in = self.dir+"/in"
323 | self.bin_out = self.dir+"/out"
324 | self.submited_data = self.dir+"/submited.txt"
325 | file_addr = self.dir +"/"+ str(self.id)
326 |
327 | # 先检测本地是否已经下载
328 | if not os.path.isfile(self.bin_dir):
329 | os.system("mkdir "+self.dir )
330 | os.system("wget {url} -O {dir} --no-check-certificate --timeout=10 --tries=3".format(url = self.download_url,dir = file_addr ))
331 | os.system("tar xvf {file_addr} -C {dir}/ --strip-components=1".format(file_addr = file_addr,dir = self.dir ))
332 | if not os.path.isfile(self.bin_dir):
333 | os.system("cp "+ self.dir+"/bin/cb " + self.bin_dir)
334 | if not os.path.isdir(self.bin_out):
335 | os.system("mkdir "+ self.bin_out)
336 | if not os.path.isfile(self.submited_data):
337 | os.system("touch "+ self.submited_data)
338 | if not os.path.isdir(self.bin_in):
339 | os.system("cp -r "+ self.dir+"/seed " + self.bin_in)
340 | #拷贝以前的seed
341 | os.system("cp ./seed/* "+self.bin_in)
342 | #可能还需要解压功能
343 | if os.path.isfile(self.bin_dir):
344 | self.log(self.dir + " download ok")
345 | return True
346 | else:
347 | self.log(self.dir + " download failed")
348 | return False
349 | except Exception as e:
350 | self.log(self.dir + " download failed")
351 | return False
352 | ```
353 |
354 | 这是AutoPwn的下载接口,比rhg的复杂一些,主要是因为autopwn提供的是tar的压缩包,所以需要脚本进行解压。
355 | 先看一下定义的几个属性:
356 | dir是一个题目的总文件夹,用题目id来命名
357 | bin_dir是解压后的二进制位置
358 | bin_in是fuzz input文件夹
359 | bin_out是fuzz output文件夹
360 | submited_data是验证哪些payload已经提交过了
361 | file_addr是下载的压缩包后重命名的名称
362 | 检测是否已经下载,如果没下载的话,执行新建文件夹,下载压缩包,解压重命名,这里有一个参数比较特别,--strip-components=1,目的是去除掉第一层目录结构,具体看下面的对比
363 |
364 | ```shell
365 | ➜ test git:(master) ✗ file 061837cd
366 | 061837cd: POSIX tar archive (GNU)
367 | ➜ test git:(master) ✗ tar xf 061837cd
368 | ➜ test git:(master) ✗ tree
369 | .
370 | ├── 061837cd
371 | └── crashme_bctf_01
372 | ├── Dockerfile
373 | ├── bin
374 | │ └── cb
375 | └── seed
376 | └── sample.in
377 | 3 directories, 4 files
378 | ```
379 |
380 | ```shell
381 | ➜ test git:(master) ✗ tar xf 061837cd --strip-components=1
382 | ➜ test git:(master) ✗ tree
383 | .
384 | ├── 061837cd
385 | ├── Dockerfile
386 | ├── bin
387 | │ └── cb
388 | └── seed
389 | └── sample.in
390 | 2 directories, 4 files
391 | ```
392 |
393 | 从上面可以看到,下载下来的附件是tar的压缩包,如果直接tar xf解压的话,第一层会有一个crash_bctf_01文件夹,这个文件夹会有一定的有随机性,用正则匹配的话不一定稳定,所以加上--strip-components=1去掉第一层文件夹,文件夹部署就规律一些了,后面的文件夹就好处理了
394 |
395 | ### AFL Fuzz 接口
396 |
397 | AFL类
398 |
399 | ```python
400 | class AFL(object):
401 | def __init__(self, id, binary, afl='/home/robot/afl-2.52b/afl-fuzz', debug=False):
402 | self.__id = id
403 | self.bin_addr = binary
404 | self.afl_bin_addr = afl
405 | self.afl_dir = os.path.dirname(afl)
406 | self.bin_dir = os.path.dirname(binary)
407 | self.in_dir = os.path.join(self.bin_dir, 'in')
408 | self.out_dir = os.path.join(self.bin_dir, 'out')
409 | self.dic_dir = os.path.join(self.bin_dir, 'dic')
410 | self.__debug = debug
411 | ```
412 |
413 |
414 | 首先定义了AFL的一个类,参数中有afl的绝对地址,尽量不要用相对地址,否则查半天报错都找不到原因,。其他几个就是二进制的位置和输入输出文件夹,dic是一些字典,可以自定义
415 |
416 | AFL Fuzz 接口
417 |
418 | ```python
419 | def start(self):
420 | if not os.path.exists(self.in_dir):
421 | os.mkdir(self.in_dir)
422 | with open(os.path.join(self.in_dir, 'NEURON.txt'), 'w') as f:
423 | f.write('NEURON')
424 | if os.path.exists(self.out_dir+"/crashes"):
425 | self.in_dir = '-'
426 |
427 | os.chmod(self.bin_addr, 0775)
428 | else:
429 | self.__afl_process = subprocess.Popen(["screen -dmS {id} bash -c '{afl_path} -i {input} -o {output} -x {dic} -m none -Q -- {bin}'".format(id=self.__id,afl_path=self.afl_bin_addr,input=self.in_dir,output=self.out_dir,dic=self.dic_dir,bin=self.bin_addr )],shell=True, stdout=subprocess.PIPE)
430 | ```
431 |
432 | start方法定义了fuzz启动程序,首先判断input是否为空,防止主办方发来的seed文件夹里面是空的,空的会导致无法fuzz成功,为空的话就随便写点东西进去。
433 |
434 | 第二个判断先前是否fuzz出crash,如果有的话,将`input_dir`替换为`-`
435 |
436 | 再往下就是给775的权限,然后就调用了subprocess,单独启一个进程,这个进程并不是直接启动afl-fuzz,而是启动了一个screen的进程,screen这里主要的目的包括:不显示fuzz的大量回显;主进程异常退出后,fuzz进程仍然在screen里运行;方便screen -r进入,调试fuzz程序。用的参数就是screen -dmS 分屏名称 bash -c
437 | 最内层的是fuzz的命令
438 | afl-fuzz -i input -o output -x dic -m none -Q -- bin
439 | 这里-m是指定内存限制,设置为none,-Q是指定在Qemu虚拟机里运行,因为主办方给的bin都没有插过桩,只能用qemu来运行
440 |
441 | AFL Fuzz Qemu安装
442 |
443 | ```bash
444 | #!/bin/sh
445 |
446 | tar xvf ./afl-latest.tgz;
447 | cd ./afl-2.52b;
448 | make;
449 | make install;
450 |
451 | cd ./qemu_mode;
452 | apt-get install libtool libtool-bin automake bison libglib2.0-dev -y
453 | export CPU_TARGET=i386;
454 | ./build_qemu_support.sh;
455 | ```
456 |
457 | 这里插入一下AFL Fuzz的安装,以及Qemu的安装
458 | afl的安装比较简单,直接tar解压后,make&make install就行。
459 | qemu的安装要进入afl里qemu_mode的文件夹里,执行build_qemu_support.sh文件,但是执行的时候需要提前手动安装依赖
460 | 安装完依赖之后,需要确定robot的环境是x86还是64位,如果是x86 32位的话,就可以不用添加这个环境变量。
461 | 如果是64位的话,必须要添加这个环境变量,不加的话,会安装64位的qemu,而平台下发的二进制基本上都是32位的,在64位qemu里无法运行,而且没有任何报错的回显,完全不知道错在哪里
462 |
463 | ```python
464 | #AFL Fuzz 接口
465 |
466 | def main(id,file_name):
467 | try:
468 | afl_path = "/home/ctf/afl-2.52b/afl-fuzz"
469 | start_time = time.time()
470 | max_run_time = 7200
471 | afl = AFL(id,file_name, afl=afl_path, debug=False )
472 | afl.start()
473 | while True:
474 | if time.time() - start_time >max_run_time:
475 | break
476 | time.sleep(10)
477 | self.__afl_process.kill()
478 | except Exception as e:
479 | print(str(e))
480 | print("fuzz failed")
481 |
482 |
483 | ```
484 |
485 | 这个是afl fuzz 主函数,定义的延时是2个小时,afl.start()启动后,会一直等待时间结束,时间到了之后便会强制结束fuzz的进程
486 |
487 | 这里需要提一下平台赛题发放的一个坑。
488 | AutoPwn平台每10分钟为一轮,更新轮次和题目内容,但是平台并不是每一轮都会更新题目的。这个也是autopwn和rhg的一个大差别,rhg一轮一个小时左右,所以rhg对轮次并不敏感。但是autopwn每10分钟一轮,如果我们的robot也是10分钟重新下载题目,停止掉上一轮fuzz的进程,再启动新的fuzz进程,就会浪费非常多的时间在fuzz进程的启动和重启上。平台是将近2个小时才会真正更新一轮题目。所以这里robot中的fuzz和crash检测是异步结构,这也是为什么10分钟一轮,fuzz的超时却设置成了2个小时
489 |
490 | 同步处理crashes
491 |
492 | ```python
493 | def main(id,file_name):
494 | try:
495 | afl_path = "/home/ctf/afl-2.52b/afl-fuzz"
496 | start_time = time.time()
497 | max_run_time = 7200
498 | afl = AFL(id,file_name, afl=afl_path, debug=False )
499 | afl.start()
500 | self.crashes = afl.crashes()
501 | while True:
502 | if time.time() - start_time >max_run_time:
503 | break
504 | time.sleep(10)
505 | tmp = afl.crashes()
506 | if self.crashes != tmp:
507 | self.crashes = tmp
508 | self.__afl_process.kill()
509 | except Exception as e:
510 | print(str(e))
511 | print("fuzz failed")
512 |
513 | ```
514 |
515 |
516 | 上面是以前同步处理crashes的方法:这里获取crashes的方法是嵌入fuzz的方法里的,crash会在fuzz结束后检测并返回给robot。这样的写法问题非常多,比如:robot异常结束后,重启robot无法获取到crashes,除非重启整个fuzz进程;返回的时候是全部crashes返回,而不是只返回新增加的crashes,这在提交flag时也是一个坑
517 |
518 | ### 异步处理crashes
519 |
520 | ```python
521 | def main(id,file_name):
522 | try:
523 | afl_path = "/home/ctf/afl-2.52b/afl-fuzz"
524 | start_time = time.time()
525 | max_run_time = 7200
526 | afl = AFL(id,file_name, afl=afl_path, debug=False )
527 | afl.start()
528 | while True:
529 | if time.time() - start_time >max_run_time:
530 | break
531 | time.sleep(10)
532 | self.__afl_process.kill()
533 | except Exception as e:
534 | print(str(e))
535 | print("fuzz failed")
536 |
537 | ```
538 |
539 | 重新设计的结构是异步结构,fuzz只负责fuzz功能,crash由其他功能负责。
540 |
541 | ```python
542 | #异步处理crashes
543 | def get_crashes(self):
544 | try:
545 | if not os.path.exists(self.bin_out+ "/" +"crashes"):
546 | return []
547 | crashes=[]
548 | for crashes_dir in os.listdir(self.bin_out):
549 | if crashes_dir.find("crashes") != -1:
550 | for crash in os.listdir(self.bin_out+ "/" +crashes_dir):
551 | if crash != 'README.txt':
552 | crashes.append(self.bin_out+ "/" +crashes_dir+ "/" +crash)
553 | if crashes != self.crashes:
554 | last_crashes = self.crashes
555 | self.crashes = crashes
556 | for crash in last_crashes:
557 | crashes.remove(crash)
558 | self.new_crashes = crashes
559 | else:
560 | self.new_crashes = []
561 | except Exception as e:
562 | print(str(e))
563 | ```
564 |
565 | 上面是异步获取crashes的方法:
566 | 首先判断是否生成了crashes文件夹,如果没有,说明没有fuzz出crashes,直接结束该方法;如果有该文件夹,就开始遍历out文件夹里所有的crashes文件夹,再遍历每个crash文件夹里的payload,还得排除掉readme文件。
567 | 这里第一层遍历的是out文件夹,而不是直接遍历crashes文件夹的原因是:当第一次fuzz出crash之后,fuzz进程被停止,第二次重新fuzz后,会将原crashes文件夹重命名为crashes+时间,会形成多个crashes文件夹
568 |
569 | ```shell
570 | ➜ out ls
571 | crashes
572 | crashes.2021-06-04-05:43:06
573 | crashes.2021-06-04-06:12:22
574 | crashes.2021-06-04-08:13:14
575 | crashes.2021-06-04-09:11:09
576 |
577 | ```
578 |
579 | 再往下会对比新获取的crashes和之前的crashes是否相同,如果相同就更新self.crashes,并更新new_crashes,这个new_crashes会用在后面的submit功能里。
580 |
581 | 异步处理crashes
582 |
583 | ```python
584 |
585 | def get_pid(self,pid_name):
586 | try:
587 | p = subprocess.Popen(["ps -ef | grep -v 'grep' | grep '"+pid_name+"' | awk '{print $2}' "], shell=True,close_fds = True,stdout=subprocess.PIPE)
588 | list = p.stdout.readlines()
589 | if len(list) != 0:
590 | return True
591 | else:
592 | return False
593 | except Exception as e:
594 | return False
595 |
596 | def fuzz(self):
597 | try:
598 | if not self.get_pid(self.id):
599 | self.log(self.dir + " start fuzz")
600 | print(self.bin_dir,self.bin_in,self.bin_out)
601 | fuzz_afl.main(self.id,self.bin_dir)
602 | else:
603 | self.log(self.dir + " is fuzzing in backend")
604 | except Exception as e:
605 | print(str(e))
606 |
607 |
608 | ```
609 |
610 | 刚刚是异步获取crashes的方法,还需要的就是一直fuzz的异步功能,这里的get_pid和fuzz是bin类的方法,先看get_pid,参数为pid名称,使用ps -ef来获取匹配进程,其中需要注意的是grep -v 'grep',这是排除掉grep本身命令对搜索进程的影响,把stdout结果赋值给list,当list长度不为0时就说明当前系统中,存在本题目id的fuzz进程。下面的fuzz方法检测了pid,存在pid的话就不进行fuzz,不存在的话就会新建上面的AFL fuzz类。
611 | 这样的逻辑就是为了让fuzz能够一直不受影响的运行下去,而不会每次轮次更新时就被打断重新运行。
612 |
613 |
614 |
615 | ### 提交接口
616 |
617 | ```python
618 | def submit_payload(payload,id,round,username,password,url_submit_flag):
619 | try:
620 | template = {"RoundID":round,
621 | "Payload":{
622 | "ChallengeID":id,
623 | "Crash":payload}}
624 | submit_data = {"username": username, "password": password, "verify": template}
625 | temstr = json.dumps(submit_data)
626 | headers = {'User-Agent': 'Mozilla/5.0'}
627 |
628 | ret = requests.post(url_submit_flag, json = submit_data, headers=headers,timeout = 30)
629 | return ret.json()['error_code']
630 | except Exception as e:
631 | print(str(e))
632 | return 1
633 | ```
634 |
635 | 这个是submit的方法,内容比较简单,按照官网的要求编写json就行,Crash记得要base64编码,这里需要注意的是,submit返回的内容是json里error_code的,可以看最下面几个典型的error_code,0代表提交成功,125代表重复提交,126代表提交过快,间隔时间为60s。
636 |
637 | ```json
638 | {u'error_eng': u'ok', u'error_code': 0, u'error_chn': u'ok'}
639 | {u'error_eng': u'duplicate submit data', u'error_code': 125, u'error_chn': u'使用同一份答案提交'}
640 | {u'error_eng': u'one submition in 60 seconds', u'error_code': 126, u'error_chn': u'提交flag过于频繁'}
641 |
642 | ```
643 |
644 | 也正是因为它提交间隔60s非常长,所以还需要我们对提交的crash修改,只提交新的crashes,提交过的crash和出现过重复提交的crash,以后将不再提交,否则当总crashes超过10个的时候,后面新的crashes将都无法提交。当然,60s间隔是针对同一个题目的,如果是针对所有题目的提交接口的话,那就没法写多进程并发了。
645 |
646 | ```python
647 | from sub_answer import submit_payload
648 | def submit(self):
649 | try:
650 | self.get_crashes()
651 | if self.new_crashes != []:
652 | submited_data = open(self.submited_data,"r").read().split("\n")
653 | for crash in reversed(self.new_crashes):
654 | payload = base64.b64encode(open(crash,"rb").read())
655 | if payload in submited_data:
656 | continue
657 | error_code = submit_payload(payload,self.id,self.round,name,password,self.url)
658 | if error_code==125 or error_code==0:
659 | open(self.submited_data,"a").write(payload+"\n")
660 | sleep(61)
661 | self.log(self.dir + " submit success")
662 | except Exception as e:
663 | print(str(e))
664 | ```
665 |
666 | 这是bin类中submit的方法,刚刚是submit的一个函数,调用了刚刚的submit_payload函数,这个方法里,首先调用了get_crashes,然后判断new_crashes是否为空,为空就结束submit,如果不为空,则对new_crashes列表进行反序提交,反序提交的目的是将最新的crash优先提交。之后便是读取submited_data,这个是代表已重复提交的crash payload,将new_crashes里的内容和submited_data匹配,如果提交过就跳过,没提交过的话调用submit_payload,并判断返回的error_code,error_code 是125就代表重复提交,就需要在submited_data再添加最新的,同样返回0的时候也判断为提交成功,同样需要加入submited_data,然后等待61秒,平台提交间隔是60s,多一秒稳妥一点
667 |
668 | 
669 |
670 | bin主流程
671 |
672 | ```python
673 | def attack(self):
674 | self.download()
675 | self.fuzz()
676 | for i in range(0,300/5):
677 | self.submit()
678 | sleep(5)
679 |
680 | def timeout(self):
681 | for i in range(self.time_limit):
682 | sleep(1)
683 | self.p.terminate()
684 | print("sorrry, timeout")
685 |
686 | def auto(self):
687 | self.p = Process(target=self.attack) #, args=(str(i),))
688 | self.k = Process(target=self.timeout)
689 | self.p.start()
690 | self.k.start()
691 |
692 | ```
693 |
694 | 这是bin类的主流程了,调用了Process启用了多进程,attack是bin的流程结构,先下载二进制,然后调用fuzz。
695 |
696 | fuzz使用的是afl-fuzz,而rhg的exploit主要是用zeratool来进行aeg攻击,zeratool有局限性,它是基于afl-fuzz和angr来运行的,所以依赖于符号表,对于静态编译或者strip掉符号表的题目,会出现路径爆炸等特殊情况。zeratool大家感兴趣的话可以自己看看
697 |
698 | `https://github.com/ChrisTheCoolHut/Zeratool.git`
699 |
700 | 另外exploit还有一种方式就是利用特征化脚本,这个本质上有点离谱,那就是收集大量的exp脚本,写好对应的接口,拼的就是谁的脚本库大。这个方法往往有奇效,毕竟历史总是惊人的相似,这年头用往届原题的比赛数不胜数
701 |
702 | ## 异常处理
703 |
704 | ### 异常及log记录
705 |
706 | ```python
707 | def log(self,content):
708 | try:
709 | f = open("log.txt","a")
710 | f.write(content+"\n")
711 | f.close()
712 | except Exception as e:
713 | return 0
714 |
715 | def download(self,round_current=1):
716 | try:
717 | os.system("wget url -O dir --no-check-certificate --timeout=10 --tries=3")
718 | if os.path.isfile(self.dir):
719 | self.log(self.dir + " download ok")
720 |
721 | except Exception as e:
722 | self.log(self.dir + " download failed:"+str(e))
723 | ```
724 |
725 |
726 |
727 | ### 异常类型
728 |
729 | 访问平台失败
730 |
731 | * 平台ping不通
732 | * request超时
733 | * https证书验证失败
734 |
735 |
736 |
737 | 题目信息解析失败
738 |
739 | * request 返回的json格式问题
740 |
741 |
742 |
743 |
744 | round异常
745 |
746 |
747 | * round提前
748 | * round推后
749 |
750 | > 解决方法根据error_code,如果显示round异常,就需要根据实际时间来判断轮次
751 |
752 |
753 |
754 | 下载题目失败
755 |
756 |
757 | * 下载https证书问题
758 | * wget超时
759 | * 下载为空文件
760 |
761 | > 空文件是轮次错误导致,获取url时侯比如说是 9分59秒,下载的时候是10分01秒,这个时候之前的下载连接就会下载为空文件了,判断空文件时,需要调用轮次获取,重新下载
762 |
763 |
764 |
765 | 编译方式
766 |
767 | * 动态编译
768 |
769 | > 动态编译需要提前安装大量依赖库
770 |
771 | ```c
772 | lib库
773 | lib32z1
774 | libboost-all-dev
775 | lib32ncurses5
776 | libncurses5-dev
777 | libstdc++6
778 | lib32stdc++6
779 | libffi-dev
780 | ```
781 |
782 | * 静态编译
783 |
784 |
785 |
786 | fuzz失败
787 |
788 | * fuzz无法启动
789 | * 超时
790 | * memory error
791 | * seed崩溃
792 |
793 |
794 |
795 | exploit失败
796 |
797 |
798 | * 编译类型
799 | * libc版本
800 |
801 |
802 |
803 | submit失败
804 |
805 |
806 | * flag错误
807 | * 重复提交
808 | * 提交过快
809 | * round 错误
810 |
811 |
812 |
813 |
814 | 比赛开始判定
815 |
816 | * ping判定
817 | * 时间判定
818 | * request返回判定
819 |
820 |
821 |
822 | 比赛期间平台突然与服务器的连接
823 |
824 | * robot 异常
825 |
826 | * 每一轮检查比赛是否开始
827 |
828 | * damon 守护程序
829 |
830 | 以上只是部分异常的原因和处理方式,异常的处理在整个robot的结构中非常重要,前面提到的fuzz和exploit决定了分数的高低,而异常的处理决定了分数是否为0
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 | services:
3 | robotcontainter:
4 | build:
5 | context: .
6 | dockerfile: Dockerfile
7 | args:
8 | root_passwd: Hillstone@123#
9 | ctf_passwd: Hillstone@123#
10 | privileged: true #root权限
11 | # networks:
12 | # rhgrobot:
13 | # ipv4_address: 192.168.101.101
14 | #
15 | # networks:
16 | # rhgrobot:
17 | # driver: bridge
18 | # ipam:
19 | # driver: default
20 | # config:
21 | # - subnet: 192.168.101.0/24
22 |
--------------------------------------------------------------------------------
/pic/image-20210622144851380.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/pic/image-20210622144851380.png
--------------------------------------------------------------------------------
/pic/image-20210622144914164.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/pic/image-20210622144914164.png
--------------------------------------------------------------------------------
/pic/image-20210622144936099.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/pic/image-20210622144936099.png
--------------------------------------------------------------------------------
/pic/image-20210622144951320.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/pic/image-20210622144951320.png
--------------------------------------------------------------------------------
/pic/image-20210622145034085.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/pic/image-20210622145034085.png
--------------------------------------------------------------------------------
/pic/image-20210622145042080.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/pic/image-20210622145042080.png
--------------------------------------------------------------------------------
/pic/image-20210622145050743.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/pic/image-20210622145050743.png
--------------------------------------------------------------------------------
/pic/image-20210622145929021.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/pic/image-20210622145929021.png
--------------------------------------------------------------------------------
/pic/image-20210622151107225.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/pic/image-20210622151107225.png
--------------------------------------------------------------------------------
/pic/image-20210622151110286.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/pic/image-20210622151110286.png
--------------------------------------------------------------------------------
/pic/image-20210622151114531.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/pic/image-20210622151114531.png
--------------------------------------------------------------------------------
/pic/image-20210622151120007.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/pic/image-20210622151120007.png
--------------------------------------------------------------------------------
/pic/image-20210622151138532.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/pic/image-20210622151138532.png
--------------------------------------------------------------------------------
/pic/image-20210622151152740.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/pic/image-20210622151152740.png
--------------------------------------------------------------------------------
/robot/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/.DS_Store
--------------------------------------------------------------------------------
/robot/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/robot/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/robot/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/robot/.idea/robot.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/robot/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/robot/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | 1616055158048
30 |
31 |
32 | 1616055158048
33 |
34 |
35 |
36 |
37 |
46 |
47 |
--------------------------------------------------------------------------------
/robot/afl-fuzz/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/afl-fuzz/.DS_Store
--------------------------------------------------------------------------------
/robot/afl-fuzz/afl-latest.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/afl-fuzz/afl-latest.tgz
--------------------------------------------------------------------------------
/robot/afl-fuzz/build_qemu_support.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # american fuzzy lop - QEMU build script
4 | # --------------------------------------
5 | #
6 | # Written by Andrew Griffiths and
7 | # Michal Zalewski
8 | #
9 | # Copyright 2015, 2016, 2017 Google Inc. All rights reserved.
10 | #
11 | # Licensed under the Apache License, Version 2.0 (the "License");
12 | # you may not use this file except in compliance with the License.
13 | # You may obtain a copy of the License at:
14 | #
15 | # http://www.apache.org/licenses/LICENSE-2.0
16 | #
17 | # This script downloads, patches, and builds a version of QEMU with
18 | # minor tweaks to allow non-instrumented binaries to be run under
19 | # afl-fuzz.
20 | #
21 | # The modifications reside in patches/*. The standalone QEMU binary
22 | # will be written to ../afl-qemu-trace.
23 | #
24 |
25 |
26 | VERSION="2.10.0"
27 | QEMU_URL="http://download.qemu-project.org/qemu-${VERSION}.tar.xz"
28 | QEMU_SHA384="a2abc4cf72b96e7d037be7452658f5bdbfcb04001c4ada2423679126f0b4ac6e4db299aa980bbf6958fb1bcae6fb8941"
29 |
30 | echo "================================================="
31 | echo "AFL binary-only instrumentation QEMU build script"
32 | echo "================================================="
33 | echo
34 |
35 | echo "[*] Performing basic sanity checks..."
36 |
37 | if [ ! "`uname -s`" = "Linux" ]; then
38 |
39 | echo "[-] Error: QEMU instrumentation is supported only on Linux."
40 | exit 1
41 |
42 | fi
43 |
44 | if [ ! -f "patches/afl-qemu-cpu-inl.h" -o ! -f "../config.h" ]; then
45 |
46 | echo "[-] Error: key files not found - wrong working directory?"
47 | exit 1
48 |
49 | fi
50 |
51 | if [ ! -f "../afl-showmap" ]; then
52 |
53 | echo "[-] Error: ../afl-showmap not found - compile AFL first!"
54 | exit 1
55 |
56 | fi
57 |
58 |
59 | for i in libtool wget python automake autoconf sha384sum bison iconv; do
60 |
61 | T=`which "$i" 2>/dev/null`
62 |
63 | if [ "$T" = "" ]; then
64 |
65 | echo "[-] Error: '$i' not found, please install first."
66 | exit 1
67 |
68 | fi
69 |
70 | done
71 |
72 | if [ ! -d "/usr/include/glib-2.0/" -a ! -d "/usr/local/include/glib-2.0/" ]; then
73 |
74 | echo "[-] Error: devel version of 'glib2' not found, please install first."
75 | exit 1
76 |
77 | fi
78 |
79 | if echo "$CC" | grep -qF /afl-; then
80 |
81 | echo "[-] Error: do not use afl-gcc or afl-clang to compile this tool."
82 | exit 1
83 |
84 | fi
85 |
86 | echo "[+] All checks passed!"
87 |
88 | ARCHIVE="`basename -- "$QEMU_URL"`"
89 |
90 | CKSUM=`sha384sum -- "$ARCHIVE" 2>/dev/null | cut -d' ' -f1`
91 |
92 | if [ ! "$CKSUM" = "$QEMU_SHA384" ]; then
93 |
94 | echo "[*] Downloading QEMU ${VERSION} from the web..."
95 | rm -f "$ARCHIVE"
96 | wget -O "$ARCHIVE" -- "$QEMU_URL" || exit 1
97 |
98 | CKSUM=`sha384sum -- "$ARCHIVE" 2>/dev/null | cut -d' ' -f1`
99 |
100 | fi
101 |
102 | if [ "$CKSUM" = "$QEMU_SHA384" ]; then
103 |
104 | echo "[+] Cryptographic signature on $ARCHIVE checks out."
105 |
106 | else
107 |
108 | echo "[-] Error: signature mismatch on $ARCHIVE (perhaps download error?)."
109 | exit 1
110 |
111 | fi
112 |
113 | echo "[*] Uncompressing archive (this will take a while)..."
114 |
115 | # rm -rf "qemu-${VERSION}" || exit 1
116 | # tar xf "$ARCHIVE" || exit 1
117 |
118 | echo "[+] Unpacking successful."
119 |
120 | echo "[*] Configuring QEMU for $CPU_TARGET..."
121 |
122 | ORIG_CPU_TARGET="$CPU_TARGET"
123 |
124 | test "$CPU_TARGET" = "" && CPU_TARGET="`uname -m`"
125 | test "$CPU_TARGET" = "i686" && CPU_TARGET="i386"
126 |
127 | cd qemu-$VERSION || exit 1
128 |
129 | echo "[*] Applying patches..."
130 |
131 | patch -p1 <../patches/elfload.diff || exit 1
132 | patch -p1 <../patches/cpu-exec.diff || exit 1
133 | patch -p1 <../patches/syscall.diff || exit 1
134 |
135 | echo "[+] Patching done."
136 |
137 | # --enable-pie seems to give a couple of exec's a second performance
138 | # improvement, much to my surprise. Not sure how universal this is..
139 |
140 | CFLAGS="-O3 -ggdb" ./configure --disable-system \
141 | --enable-linux-user --disable-gtk --disable-sdl --disable-vnc \
142 | --target-list="${CPU_TARGET}-linux-user" --enable-pie --enable-kvm || exit 1
143 |
144 | echo "[+] Configuration complete."
145 |
146 | echo "[*] Attempting to build QEMU (fingers crossed!)..."
147 |
148 | make || exit 1
149 |
150 | echo "[+] Build process successful!"
151 |
152 | echo "[*] Copying binary..."
153 |
154 | cp -f "${CPU_TARGET}-linux-user/qemu-${CPU_TARGET}" "../../afl-qemu-trace" || exit 1
155 |
156 | cd ..
157 | ls -l ../afl-qemu-trace || exit 1
158 |
159 | echo "[+] Successfully created '../afl-qemu-trace'."
160 |
161 | if [ "$ORIG_CPU_TARGET" = "" ]; then
162 |
163 | echo "[*] Testing the build..."
164 |
165 | cd ..
166 |
167 | make >/dev/null || exit 1
168 |
169 | gcc test-instr.c -o test-instr || exit 1
170 |
171 | unset AFL_INST_RATIO
172 |
173 | echo 0 | ./afl-showmap -m none -Q -q -o .test-instr0 ./test-instr || exit 1
174 | echo 1 | ./afl-showmap -m none -Q -q -o .test-instr1 ./test-instr || exit 1
175 |
176 | rm -f test-instr
177 |
178 | cmp -s .test-instr0 .test-instr1
179 | DR="$?"
180 |
181 | rm -f .test-instr0 .test-instr1
182 |
183 | if [ "$DR" = "0" ]; then
184 |
185 | echo "[-] Error: afl-qemu-trace instrumentation doesn't seem to work!"
186 | exit 1
187 |
188 | fi
189 |
190 | echo "[+] Instrumentation tests passed. "
191 | echo "[+] All set, you can now use the -Q mode in afl-fuzz!"
192 |
193 | else
194 |
195 | echo "[!] Note: can't test instrumentation when CPU_TARGET set."
196 | echo "[+] All set, you can now (hopefully) use the -Q mode in afl-fuzz!"
197 |
198 | fi
199 |
200 | exit 0
201 |
--------------------------------------------------------------------------------
/robot/afl-fuzz/qemu-2.10.0.tar.xz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/afl-fuzz/qemu-2.10.0.tar.xz
--------------------------------------------------------------------------------
/robot/afl-fuzz/setup_x32.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | tar xvf ./afl-latest.tgz;
4 | cp ./qemu-2.10.0.tar.xz ./afl-2.52b/qemu_mode;
5 | cp ./build_qemu_support.sh ./afl-2.52b/qemu_mode/;
6 | cd ./afl-2.52b;
7 | make;
8 | make install;
9 |
10 | cd ./qemu_mode;
11 | tar xvf ./qemu-2.10.0.tar.xz ;
12 | apt-get install libtool-bin automake -y
13 | export CPU_TARGET=i386;
14 | ./build_qemu_support.sh;
15 |
--------------------------------------------------------------------------------
/robot/afl-fuzz/setup_x64.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | tar xvf ./afl-latest.tgz;
4 | cp ./qemu-2.10.0.tar.xz ./afl-2.52b/qemu_mode;
5 | cp ./build_qemu_support.sh ./afl-2.52b/qemu_mode/;
6 | cd ./afl-2.52b;
7 | make;
8 | make install;
9 |
10 | cd ./qemu_mode;
11 | tar xvf ./qemu-2.10.0.tar.xz ;
12 | apt-get install libtool-bin automake -y
13 | ./build_qemu_support.sh;
14 |
--------------------------------------------------------------------------------
/robot/attachments/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/attachments/.DS_Store
--------------------------------------------------------------------------------
/robot/attachments/061837cd/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/attachments/061837cd/.DS_Store
--------------------------------------------------------------------------------
/robot/attachments/061837cd/061837cd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/attachments/061837cd/061837cd
--------------------------------------------------------------------------------
/robot/attachments/061837cd/Dockerfile:
--------------------------------------------------------------------------------
1 | # sudo docker build -t bctf_test .
2 | # sudo docker run -d --rm -it bctf_test
3 |
4 | # use a 32-bit base image in case someone uses it on a 32-bit host
5 | FROM i386/ubuntu:16.04
6 |
7 | LABEL challenge="crash_antifuzz" \
8 | bin_arch="i386"
9 |
10 | ##### Docker Build Time CMD #######
11 |
12 | #Should always RUN 'apt-get update && apt-get install -y ' together to avoid cache issue
13 | #RUN apt-get update && \
14 | # apt-get install -y \
15 | # build-essential \
16 | # gcc gdb wget \
17 | # python
18 |
19 | RUN useradd -d /home/bctf/ -m -p ctf -s /bin/bash bctf
20 | RUN echo "bctf:bctf" | chpasswd
21 |
22 | #COPY data/popcalc /bin/
23 |
24 | WORKDIR /home/bctf
25 |
26 | COPY bin/cb /home/bctf/
27 | COPY seed/sample.in /home/bctf/
28 |
29 | RUN chown -R bctf:bctf /home/bctf
30 |
31 | USER bctf
32 |
33 | ####### Container Start Time CMD #######
34 | #cmd to run once container starts
35 | CMD ./cb - < sample.in > sample.out
36 |
--------------------------------------------------------------------------------
/robot/attachments/061837cd/bin/cb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/attachments/061837cd/bin/cb
--------------------------------------------------------------------------------
/robot/attachments/061837cd/seed/sample.in:
--------------------------------------------------------------------------------
1 | 2
2 | {"name":{"score":[12, 12]}}]}}
3 |
--------------------------------------------------------------------------------
/robot/attachments/0f3abf1d/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/attachments/0f3abf1d/.DS_Store
--------------------------------------------------------------------------------
/robot/attachments/0f3abf1d/0f3abf1d:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/attachments/0f3abf1d/0f3abf1d
--------------------------------------------------------------------------------
/robot/attachments/0f3abf1d/Dockerfile:
--------------------------------------------------------------------------------
1 | # sudo docker build -t bctf_test .
2 | # sudo docker run -d --rm -it bctf_test
3 |
4 | # use a 32-bit base image in case someone uses it on a 32-bit host
5 | FROM i386/ubuntu:16.04
6 |
7 | LABEL challenge="Crashme maze" \
8 | bin_arch="i386"
9 |
10 | ##### Docker Build Time CMD #######
11 |
12 | #Should always RUN 'apt-get update && apt-get install -y ' together to avoid cache issue
13 | #RUN apt-get update && \
14 | # apt-get install -y \
15 | # build-essential \
16 | # gcc gdb wget \
17 | # python
18 |
19 | RUN useradd -d /home/bctf/ -m -p ctf -s /bin/bash bctf
20 | RUN echo "bctf:bctf" | chpasswd
21 |
22 | #COPY data/popcalc /bin/
23 |
24 | WORKDIR /home/bctf
25 |
26 | COPY bin/cb /home/bctf/
27 | COPY seed/sample.in /home/bctf/
28 |
29 | RUN chown -R bctf:bctf /home/bctf
30 |
31 | USER bctf
32 |
33 | ####### Container Start Time CMD #######
34 | #cmd to run once container starts
35 | CMD ./cb - < sample.in > sample.out
36 |
37 |
--------------------------------------------------------------------------------
/robot/attachments/0f3abf1d/bin/cb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/attachments/0f3abf1d/bin/cb
--------------------------------------------------------------------------------
/robot/attachments/0f3abf1d/seed/sample.in:
--------------------------------------------------------------------------------
1 | 12130
2 |
--------------------------------------------------------------------------------
/robot/attachments/13288893/13288893:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/attachments/13288893/13288893
--------------------------------------------------------------------------------
/robot/attachments/13288893/Dockerfile:
--------------------------------------------------------------------------------
1 | # sudo docker build -t bctf_test .
2 | # sudo docker run -d --rm -it bctf_test
3 |
4 | # use a 32-bit base image in case someone uses it on a 32-bit host
5 | FROM i386/ubuntu:16.04
6 |
7 | LABEL challenge="crash_antifuzz" \
8 | bin_arch="i386"
9 |
10 | ##### Docker Build Time CMD #######
11 |
12 | #Should always RUN 'apt-get update && apt-get install -y ' together to avoid cache issue
13 | #RUN apt-get update && \
14 | # apt-get install -y \
15 | # build-essential \
16 | # gcc gdb wget \
17 | # python
18 |
19 | RUN useradd -d /home/bctf/ -m -p ctf -s /bin/bash bctf
20 | RUN echo "bctf:bctf" | chpasswd
21 |
22 | #COPY data/popcalc /bin/
23 |
24 | WORKDIR /home/bctf
25 |
26 | COPY bin/cb /home/bctf/
27 | COPY seed/sample.in /home/bctf/
28 |
29 | RUN chown -R bctf:bctf /home/bctf
30 |
31 | USER bctf
32 |
33 | ####### Container Start Time CMD #######
34 | #cmd to run once container starts
35 | CMD ./cb - < sample.in > sample.out
36 |
--------------------------------------------------------------------------------
/robot/attachments/13288893/bin/cb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/attachments/13288893/bin/cb
--------------------------------------------------------------------------------
/robot/attachments/13288893/seed/sample.in:
--------------------------------------------------------------------------------
1 | AAAAAAAA
2 |
--------------------------------------------------------------------------------
/robot/attachments/498d84f2/498d84f2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/attachments/498d84f2/498d84f2
--------------------------------------------------------------------------------
/robot/attachments/498d84f2/Dockerfile:
--------------------------------------------------------------------------------
1 | # sudo docker build -t bctf_test .
2 | # sudo docker run -d --rm -it bctf_test
3 |
4 | # use a 32-bit base image in case someone uses it on a 32-bit host
5 | FROM i386/ubuntu:16.04
6 |
7 | LABEL challenge="crash checksum" \
8 | bin_arch="i386"
9 |
10 | ##### Docker Build Time CMD #######
11 |
12 | #Should always RUN 'apt-get update && apt-get install -y ' together to avoid cache issue
13 | #RUN apt-get update && \
14 | # apt-get install -y \
15 | # build-essential \
16 | # gcc gdb wget \
17 | # python
18 |
19 | RUN useradd -d /home/bctf/ -m -p ctf -s /bin/bash bctf
20 | RUN echo "bctf:bctf" | chpasswd
21 |
22 | #COPY data/popcalc /bin/
23 |
24 | WORKDIR /home/bctf
25 |
26 | COPY bin/cb /home/bctf/
27 | COPY seed/sample.in /home/bctf/
28 |
29 | RUN chown -R bctf:bctf /home/bctf
30 |
31 | USER bctf
32 |
33 | ####### Container Start Time CMD #######
34 | #cmd to run once container starts
35 | CMD ./cb - < sample.in > sample.out
36 |
--------------------------------------------------------------------------------
/robot/attachments/498d84f2/README.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## 考核目标:checksum检查
4 |
5 | * 第一次输入25字节,对前20字节进行计算,得到的值与最后5字节组成的整数进行比较
6 | * 若通过检查,gets()函数导致简单栈溢出
--------------------------------------------------------------------------------
/robot/attachments/498d84f2/bin/cb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/attachments/498d84f2/bin/cb
--------------------------------------------------------------------------------
/robot/attachments/498d84f2/seed/sample.in:
--------------------------------------------------------------------------------
1 | 1111111111111111111122222
2 | assssssssssssssssssssssssssssss
3 |
--------------------------------------------------------------------------------
/robot/attachments/57193dae/57193dae:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/attachments/57193dae/57193dae
--------------------------------------------------------------------------------
/robot/attachments/57193dae/Dockerfile:
--------------------------------------------------------------------------------
1 | # sudo docker build -t bctf_test .
2 | # sudo docker run -d --rm -it bctf_test
3 |
4 | # use a 32-bit base image in case someone uses it on a 32-bit host
5 | FROM i386/ubuntu:16.04
6 |
7 | LABEL challenge="crash_antifuzz" \
8 | bin_arch="i386"
9 |
10 | ##### Docker Build Time CMD #######
11 |
12 | #Should always RUN 'apt-get update && apt-get install -y ' together to avoid cache issue
13 | #RUN apt-get update && \
14 | # apt-get install -y \
15 | # build-essential \
16 | # gcc gdb wget \
17 | # python
18 |
19 | RUN useradd -d /home/bctf/ -m -p ctf -s /bin/bash bctf
20 | RUN echo "bctf:bctf" | chpasswd
21 |
22 | #COPY data/popcalc /bin/
23 |
24 | WORKDIR /home/bctf
25 |
26 | COPY bin/cb /home/bctf/
27 | COPY seed/sample.in /home/bctf/
28 |
29 | RUN chown -R bctf:bctf /home/bctf
30 |
31 | USER bctf
32 |
33 | ####### Container Start Time CMD #######
34 | #cmd to run once container starts
35 | CMD ./cb - < sample.in > sample.out
36 |
--------------------------------------------------------------------------------
/robot/attachments/57193dae/bin/cb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/attachments/57193dae/bin/cb
--------------------------------------------------------------------------------
/robot/attachments/57193dae/seed/sample.in:
--------------------------------------------------------------------------------
1 | fsasfafasfasafsasf
--------------------------------------------------------------------------------
/robot/attachments/62059e6d/62059e6d:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/attachments/62059e6d/62059e6d
--------------------------------------------------------------------------------
/robot/attachments/62059e6d/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM i386/ubuntu:16.04
2 |
3 | LABEL challenge="mine demo" \
4 | bin_arch="i386"
5 |
6 | ##### Docker Build Time CMD #######
7 |
8 | #Should always RUN 'apt-get update && apt-get install -y ' together to avoid cache issue
9 | #RUN apt-get update && \
10 | # apt-get install -y \
11 | # build-essential \
12 | # gcc gdb wget \
13 | # python
14 |
15 | RUN useradd -d /home/bctf/ -m -p ctf -s /bin/bash bctf
16 | RUN echo "bctf:bctf" | chpasswd
17 |
18 | #COPY data/popcalc /bin/
19 |
20 | WORKDIR /home/bctf
21 |
22 | COPY bin/cb /home/bctf/
23 | COPY seed/sample.in /home/bctf/
24 |
25 | RUN chown -R bctf:bctf /home/bctf
26 |
27 | USER bctf
28 |
29 | ####### Container Start Time CMD #######
30 | #cmd to run once container starts
31 | CMD ./cb - < sample.in > sample.out
32 |
--------------------------------------------------------------------------------
/robot/attachments/62059e6d/bin/cb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/attachments/62059e6d/bin/cb
--------------------------------------------------------------------------------
/robot/attachments/62059e6d/seed/sample.in:
--------------------------------------------------------------------------------
1 | 7 4 1 12 12 0
2 |
--------------------------------------------------------------------------------
/robot/attachments/d8e4af1d/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM i386/ubuntu:16.04
2 |
3 | LABEL challenge="Loop demo" \
4 | bin_arch="i386"
5 |
6 | ##### Docker Build Time CMD #######
7 |
8 | #Should always RUN 'apt-get update && apt-get install -y ' together to avoid cache issue
9 | #RUN apt-get update && \
10 | # apt-get install -y \
11 | # build-essential \
12 | # gcc gdb wget \
13 | # python
14 |
15 | RUN useradd -d /home/bctf/ -m -p ctf -s /bin/bash bctf
16 | RUN echo "bctf:bctf" | chpasswd
17 |
18 | #COPY data/popcalc /bin/
19 |
20 | WORKDIR /home/bctf
21 |
22 | COPY bin/cb /home/bctf/
23 | COPY seed/sample.in /home/bctf/
24 |
25 | RUN chown -R bctf:bctf /home/bctf
26 |
27 | USER bctf
28 |
29 | ####### Container Start Time CMD #######
30 | #cmd to run once container starts
31 | CMD ./cb - < sample.in > sample.out
32 |
--------------------------------------------------------------------------------
/robot/attachments/d8e4af1d/bin/cb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/attachments/d8e4af1d/bin/cb
--------------------------------------------------------------------------------
/robot/attachments/d8e4af1d/d8e4af1d:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/attachments/d8e4af1d/d8e4af1d
--------------------------------------------------------------------------------
/robot/attachments/d8e4af1d/seed/sample.in:
--------------------------------------------------------------------------------
1 | s
2 |
--------------------------------------------------------------------------------
/robot/attachments/d93eef08/Dockerfile:
--------------------------------------------------------------------------------
1 | # sudo docker build -t bctf_test .
2 | # sudo docker run -d --rm -it bctf_test
3 |
4 | # use a 32-bit base image in case someone uses it on a 32-bit host
5 | FROM i386/ubuntu:16.04
6 |
7 | LABEL challenge="crash_antifuzz" \
8 | bin_arch="i386"
9 |
10 | ##### Docker Build Time CMD #######
11 |
12 | #Should always RUN 'apt-get update && apt-get install -y ' together to avoid cache issue
13 | #RUN apt-get update && \
14 | # apt-get install -y \
15 | # build-essential \
16 | # gcc gdb wget \
17 | # python
18 |
19 | RUN useradd -d /home/bctf/ -m -p ctf -s /bin/bash bctf
20 | RUN echo "bctf:bctf" | chpasswd
21 |
22 | #COPY data/popcalc /bin/
23 |
24 | WORKDIR /home/bctf
25 |
26 | COPY bin/cb /home/bctf/
27 | COPY seed/sample.in /home/bctf/
28 |
29 | RUN chown -R bctf:bctf /home/bctf
30 |
31 | USER bctf
32 |
33 | ####### Container Start Time CMD #######
34 | #cmd to run once container starts
35 | CMD ./cb - < sample.in > sample.out
36 |
--------------------------------------------------------------------------------
/robot/attachments/d93eef08/bin/cb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/attachments/d93eef08/bin/cb
--------------------------------------------------------------------------------
/robot/attachments/d93eef08/d93eef08:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0xaww/RHG-AutoPwn-Robot/d03894975441a144dc645d7983163cdbd6263f02/robot/attachments/d93eef08/d93eef08
--------------------------------------------------------------------------------
/robot/attachments/d93eef08/seed/sample.in:
--------------------------------------------------------------------------------
1 | 0
2 |
--------------------------------------------------------------------------------
/robot/bin.py:
--------------------------------------------------------------------------------
1 | #coding=utf-8
2 | from multiprocessing import Process
3 | import subprocess
4 | import os
5 | from time import sleep
6 | import fuzz_afl
7 | from sub_answer import submit_payload
8 | import base64
9 |
10 | class bin(object):
11 |
12 | def __init__(self, id, round, ip, port, download_url, submit_url, question_type, flag_path,username,password,url_submit_flag):
13 | super(bin, self).__init__()
14 | self.id = id
15 | self.round = round
16 | self.ip = ip
17 | self.port = port
18 | self.download_url = download_url
19 | self.submit_url = submit_url
20 | self.question_type = question_type
21 | self.flag_path = flag_path
22 | self.submited = 0
23 | self.time_limit = 300 #second
24 | self.bin_dir = ""
25 | self.crashes = []
26 | self.new_crashes = []
27 | self.username = username
28 | self.password = password
29 | self.url_submit_flag = url_submit_flag
30 | self.submited_data = ""
31 | def log(self,content):
32 | try:
33 | f = open("log.txt","a")
34 | f.write(content+"\n")
35 | f.close
36 | except Exception as e:
37 | return 0
38 |
39 | def get_pid(self,pid_name):
40 | try:
41 | p = subprocess.Popen(["ps -ef | grep -v 'grep' | grep '"+pid_name+"' | awk '{print $2}' "], shell=True,close_fds = True,stdout=subprocess.PIPE)
42 | list = p.stdout.readlines()
43 | if len(list) != 0:
44 | return True
45 | else:
46 | return False
47 | except Exception as e:
48 | return False
49 |
50 |
51 | def download(self):
52 | try:
53 | self.dir = "attachments/"+str(self.id)
54 | self.bin_dir = self.dir+"/cb"
55 | self.bin_in = self.dir+"/in"
56 | self.bin_out = self.dir+"/out"
57 | self.submited_data = self.dir+"/submited.txt"
58 | file_addr = self.dir +"/"+ str(self.id)
59 |
60 | # 先检测本地是否已经下载
61 | if not os.path.isfile(self.bin_dir):
62 | os.system("mkdir "+self.dir )
63 | os.system("wget {url} -O {dir} --no-check-certificate --timeout=10 --tries=3".format(url = self.download_url,dir = file_addr ))
64 | os.system("tar xvf {file_addr} -C {dir}/ --strip-components=1".format(file_addr = file_addr,dir = self.dir ))
65 | if not os.path.isfile(self.bin_dir):
66 | os.system("cp "+ self.dir+"/bin/cb " + self.bin_dir)
67 |
68 | if not os.path.isdir(self.bin_out):
69 | os.system("mkdir "+ self.bin_out)
70 |
71 | if not os.path.isfile(self.submited_data):
72 | os.system("touch "+ self.submited_data)
73 |
74 | if not os.path.isdir(self.bin_in):
75 | os.system("cp -r "+ self.dir+"/seed " + self.bin_in)
76 | #拷贝以前的seed
77 | os.system("cp ./seed/* "+self.bin_in)
78 | #可能还需要解压功能
79 | if os.path.isfile(self.bin_dir):
80 | self.log(self.dir + " download ok")
81 | return True
82 | else:
83 | self.log(self.dir + " download failed")
84 | return False
85 |
86 | except Exception as e:
87 | self.log(self.dir + " download failed")
88 | return False
89 |
90 |
91 | def fuzz(self):
92 | try:
93 | if not self.get_pid(self.id):
94 | self.log(self.dir + " start fuzz")
95 | print(self.bin_dir,self.bin_in,self.bin_out)
96 | fuzz_afl.main(self.id,self.bin_dir)
97 | else:
98 | self.log(self.dir + " is fuzzing in backend")
99 | except Exception as e:
100 | print(str(e))
101 |
102 |
103 | def exploit(self):
104 | # exploit为核心调用,传入题目信息,返回flag
105 | print("exploit")
106 | self.flag = "flag"
107 |
108 | def get_crashes(self):
109 | try:
110 | if not os.path.exists(self.bin_out+ "/" +"crashes"):
111 | return []
112 | crashes=[]
113 | for crashes_dir in os.listdir(self.bin_out):
114 | if crashes_dir.find("crashes") != -1:
115 | for crash in os.listdir(self.bin_out+ "/" +crashes_dir):
116 | if crash != 'README.txt':
117 | crashes.append(self.bin_out+ "/" +crashes_dir+ "/" +crash)
118 | # 保存新的crashes,用于提交
119 | if crashes != self.crashes:
120 | last_crashes = self.crashes
121 | self.crashes = crashes
122 | for crash in last_crashes:
123 | crashes.remove(crash)
124 | self.new_crashes = crashes
125 | else:
126 | self.new_crashes = []
127 | except Exception as e:
128 | print(str(e))
129 |
130 |
131 | def submit(self):
132 | try:
133 | self.get_crashes()
134 | if self.new_crashes != []:
135 | self.log(self.dir + " get new crashes")
136 | print(self.new_crashes)
137 | self.log(self.dir + " start submit")
138 | # 倒序先提交新的
139 | f_submited = open(self.submited_data,"r")
140 | submited_data = f_submited.read().split("\n")
141 | f_submited.close()
142 | for crash in reversed(self.new_crashes):
143 | file = open(crash,"rb").read()
144 | payload = base64.b64encode(file)
145 | if payload in submited_data:
146 | print("check has submited data")
147 | continue
148 | # print(payload,self.id,self.round,self.username,self.password,self.url_submit_flag)
149 | error_code = submit_payload(payload,self.id,self.round,self.username,self.password,self.url_submit_flag)
150 | if error_code==125 or error_code == 0:
151 | f = open(self.submited_data,"a")
152 | f.write(payload+"\n")
153 | f.close()
154 | print("wocao,youchongful")
155 | print(error_code)
156 | sleep(30)
157 | self.log(self.dir + " submit success")
158 | except Exception as e:
159 | print(str(e))
160 |
161 |
162 |
163 |
164 | def attack(self):
165 | self.download()
166 | self.fuzz()
167 | for i in range(0,300/5):
168 | self.submit()
169 | sleep(5)
170 |
171 |
172 | def timeout(self):
173 | for i in range(self.time_limit):
174 | # print("wait timeout " + str(i))
175 | sleep(1)
176 | self.p.terminate()
177 | print("sorrry, timeout")
178 |
179 | def auto(self):
180 | # k process用于超时检测
181 | # 因为BCTF一直运行fuzz,所以取消超时
182 | self.p = Process(target=self.attack) #, args=(str(i),))
183 | # self.k = Process(target=self.timeout)
184 | self.p.start()
185 | # self.k.start()
186 |
--------------------------------------------------------------------------------
/robot/competion.py:
--------------------------------------------------------------------------------
1 | #coding=utf-8
2 | import requests
3 | import base64
4 | import json
5 |
6 | class robot(object):
7 | def __init__(self, username,password,url_get_machines,url_get_question,url_submit_flag):
8 | super(robot, self).__init__()
9 | self.username = username
10 | self.password = password
11 | self.url_get_machines = url_get_machines
12 | self.url_get_question = url_get_question
13 | self.url_submit_flag = url_submit_flag
14 | self.challenge = {}
15 | self.round = 0
16 | self.local_env = False
17 |
18 | def get_question(self):
19 | try:
20 | if self.local_env == True:
21 | resp = open("local_info.txt","r").read()
22 | ret_con = json.loads(resp)
23 | self.challenge = ret_con['CurrentChallenge']
24 | self.round = ret_con['CurrentRound']
25 | return True
26 | elif self.local_env == False:
27 | header = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063'}
28 | resp = requests.get(self.url_get_question, headers=header, timeout=30, verify=False)
29 | ret_con = json.loads(resp.content)
30 | self.challenge = ret_con['CurrentChallenge']
31 | self.round = ret_con['CurrentRound']
32 | return True
33 | except Exception as e:
34 | print(str(e))
35 | return False
36 |
37 | if __name__ == '__main__':
38 | r = robot("student01","VXAdUBmb","url_get_machines","https://anquan.baidu.com/bctf/latest_round"," https://anquan.baidu.com/bctf/submit")
39 | r.get_question()
40 | print(r.challenge)
41 | print(r.round)
42 |
--------------------------------------------------------------------------------
/robot/fuzz_afl.py:
--------------------------------------------------------------------------------
1 | #coding=utf-8
2 | import subprocess
3 | import os
4 | import stat
5 | import signal
6 | import re
7 | import time
8 | import config
9 | import sys
10 |
11 |
12 | class AFL(object):
13 | bin_addr = None
14 | bin_dir = None
15 | afl_dir = None
16 | afl_bin_addr = None
17 | afl_proc = None
18 | in_dir = None
19 | out_dir = None
20 | dic_dir = None
21 |
22 | __debug = False
23 |
24 |
25 | def __init__(self, id, binary, afl='/home/ctf/robot/afl-fuzz/afl-2.52b/afl-fuzz', debug=False):
26 | self.__id = id
27 | self.bin_addr = binary
28 | self.afl_bin_addr = afl
29 | self.afl_dir = os.path.dirname(afl)
30 | self.bin_dir = os.path.dirname(binary)
31 | self.in_dir = os.path.join(self.bin_dir, 'in')
32 | self.out_dir = os.path.join(self.bin_dir, 'out')
33 | self.dic_dir = os.path.join(self.bin_dir, 'dic')
34 | self.__debug = False
35 |
36 |
37 | def _generate_afl_dic(self):
38 | afl_dic_script = """#!/bin/bash
39 |
40 | objdump -d "${1}" | grep -Eo '$0x[0-9a-f]+' | cut -c 2- | sort -u | while read const; do echo $const | python -c 'import sys, struct; sys.stdout.write("".join(struct.pack(" ${2}/$const; done
41 | i=0; strings "${1}"| while read line; do echo -n "$line" > ${2}/string_${i} ; i=$[ $i + 1 ] ; done
42 | """
43 | afl_dic_script_path = os.path.join(self.afl_dir, 'afl_dic.sh')
44 | if not os.path.exists(afl_dic_script_path):
45 | with open(afl_dic_script_path, 'w') as f:
46 | f.write(afl_dic_script)
47 | os.chmod(afl_dic_script_path, 0775)
48 |
49 | if not os.path.exists(self.dic_dir):
50 | os.mkdir(self.dic_dir)
51 |
52 | return subprocess.call([afl_dic_script_path, self.bin_addr, self.dic_dir])
53 |
54 | def start(self):
55 | self._generate_afl_dic()
56 | for f in os.listdir(self.dic_dir):
57 | filename = os.path.join(self.dic_dir, f)
58 | if os.stat(filename).st_size > 128:
59 | os.remove(filename)
60 | if not os.path.exists(self.in_dir):
61 | os.mkdir(self.in_dir)
62 | with open(os.path.join(self.in_dir, 'demo.txt'), 'w') as f:
63 | f.write('DEMO')
64 | if os.path.exists(self.out_dir+"/crashes"):
65 | self.in_dir = '-'
66 |
67 | os.chmod(self.bin_addr, 0775)
68 |
69 | if self.__debug:
70 | print "this function is debuging!"
71 | print self.afl_bin_addr, '-i', self.in_dir
72 | print "afl command:", self.afl_bin_addr, '-i', self.in_dir, '-o', self.out_dir, '-x', self.dic_dir, '-m none', '-Q', '--', self.bin_addr
73 |
74 | self.__afl_process = subprocess.Popen(
75 | [self.afl_bin_addr, '-i', self.in_dir, '-o', self.out_dir, '-x', self.dic_dir,
76 | '-m', 'none', '-Q', '--', self.bin_addr])
77 | else:
78 | print("screen -dmS {id} bash -c '{afl_path} -i {input} -o {output} -x {dic} -m none -Q -- {bin}'".format(id=self.__id,afl_path=self.afl_bin_addr,input=self.in_dir,output=self.out_dir,dic=self.dic_dir,bin=self.bin_addr ))
79 | self.__afl_process = subprocess.Popen(["screen -dmS {id} bash -c '{afl_path} -i {input} -o {output} -x {dic} -m none -Q -- {bin}'".format(id=self.__id,afl_path=self.afl_bin_addr,input=self.in_dir,output=self.out_dir,dic=self.dic_dir,bin=self.bin_addr )],shell=True, stdout=subprocess.PIPE)
80 |
81 |
82 | def stop(self):
83 | self.__afl_process.kill()
84 | self.__afl_process.wait()
85 |
86 | def is_alive(self):
87 | return self.__afl_process.poll() is None
88 |
89 |
90 |
91 |
92 | def main(id,file_name):
93 | try:
94 | afl_path = "/home/ctf/robot/afl-fuzz/afl-2.52b/afl-fuzz"
95 | start_time = time.time()
96 | max_run_time = 7200
97 | afl = AFL(id,file_name, afl=afl_path, debug=True )
98 | print "now fuzzing ", file_name
99 | afl.start()
100 | while True:
101 | if time.time() - start_time >max_run_time:
102 | break
103 | time.sleep(10)
104 | self.__afl_process.kill()
105 | except Exception as e:
106 | print(str(e))
107 | print("fuzz failed")
108 |
109 | if __name__ == '__main__':
110 | print(main(sys.argv[1]))
111 |
--------------------------------------------------------------------------------
/robot/local_info.txt:
--------------------------------------------------------------------------------
1 | {"CurrentRound":1,"CurrentChallenge":[{"cb_id":"061837cd","score":3,"score_method":"Crash","cb_url":"https://anquan.baidu.com/bctf/bctf_games/061837cd.tar","cb_provider":"team_a"},{"cb_id":"0f3abf1d","score":3,"score_method":"Crash","cb_url":"https://anquan.baidu.com/bctf/bctf_games/1/ad8d413d/1458.tar","cb_provider":"team_a"},{"cb_id":"13288893","score":3,"score_method":"Crash","cb_url":"https://anquan.baidu.com/bctf/bctf_games/1/ad8d413d/1458.tar","cb_provider":"team_a"},{"cb_id":"498d84f2","score":3,"score_method":"Crash","cb_url":"https://anquan.baidu.com/bctf/bctf_games/1/ad8d413d/1458.tar","cb_provider":"team_a"},{"cb_id":"57193dae","score":3,"score_method":"Crash","cb_url":"https://anquan.baidu.com/bctf/bctf_games/1/ad8d413d/1458.tar","cb_provider":"team_a"},{"cb_id":"62059e6d","score":3,"score_method":"Crash","cb_url":"https://anquan.baidu.com/bctf/bctf_games/1/ad8d413d/1458.tar","cb_provider":"team_a"},{"cb_id":"d8e4af1d","score":3,"score_method":"Crash","cb_url":"https://anquan.baidu.com/bctf/bctf_games/1/ad8d413d/1458.tar","cb_provider":"team_a"},{"cb_id":"d93eef08","score":3,"score_method":"Crash","cb_url":"https://anquan.baidu.com/bctf/bctf_games/1/ad8d413d/1458.tar","cb_provider":"team_a"}],"scoreboard":[{"score":99,"first_blood":15,"bugs":20,"rank":1,"team":"test3"},{"score":75,"first_blood":8,"bugs":12,"rank":2,"team":"test5"},{"score":63,"first_blood":2,"bugs":4,"rank":3,"team":"test1"}]}
2 |
--------------------------------------------------------------------------------
/robot/log.txt:
--------------------------------------------------------------------------------
1 | attachments/57193dae download failed
2 | attachments/d93eef08 download failed
3 | attachments/498d84f2 download failed
4 | attachments/d8e4af1d download failed
5 | attachments/061837cd download failed
6 | attachments/0f3abf1d download failed
7 | attachments/13288893 download failed
8 | attachments/62059e6d download failed
9 | attachments/57193dae download failed
10 | attachments/d8e4af1d download failed
11 | attachments/498d84f2 download failed
12 | attachments/061837cd download failed
13 | attachments/d93eef08 download failed
14 | attachments/0f3abf1d download failed
15 | attachments/62059e6d download failed
16 | attachments/13288893 download failed
17 | attachments/d93eef08 download ok
18 | attachments/498d84f2 download ok
19 | attachments/57193dae download ok
20 | attachments/d8e4af1d download ok
21 | attachments/061837cd download ok
22 | attachments/0f3abf1d download ok
23 | attachments/62059e6d download ok
24 | attachments/13288893 download ok
25 | attachments/57193dae download ok
26 | attachments/498d84f2 download ok
27 | attachments/d8e4af1d download ok
28 | attachments/d93eef08 download ok
29 | attachments/061837cd download ok
30 | attachments/62059e6d download ok
31 | attachments/0f3abf1d download ok
32 | attachments/13288893 download ok
33 |
--------------------------------------------------------------------------------
/robot/robot.py:
--------------------------------------------------------------------------------
1 | #coding=utf-8
2 | # from heartbeat import heartbeat
3 | # from get_ranking import get_ranking
4 | # from sub_answer import sub_answer
5 | # from reset_question import reset_question
6 | # from get_machines_info import get_machines_info
7 | # from download import download
8 | # from init import init
9 |
10 | from bin import *
11 | from competion import *
12 | from time import sleep
13 |
14 | username = "AWW"
15 | password = "102928wujiang"
16 | url_get_machines = "https://anquan.baidu.com/bctf/get_machines_info"
17 | url_get_question = "https://anquan.baidu.com/bctf/latest_round"
18 | url_submit_flag = "https://anquan.baidu.com/bctf/submit"
19 | detect_time = 10 #比赛开始检测时间
20 | round_time = 300 #每轮时间
21 |
22 |
23 | r = robot(username,password,url_get_machines,url_get_question,url_submit_flag)
24 | while 1:#检测比赛是否开始
25 | try:
26 | r.get_question()
27 | if r.challenge != {} : #没开始或接受错误回0
28 | break
29 | else:
30 | print("waiting game start")
31 | sleep(detect_time)
32 | except Exception as e:
33 | print(str(e))
34 |
35 |
36 | while 1:#循环进行进行fuzz测试
37 | try:
38 | if r.get_question() != True:
39 | print("game breaking ,waiting restart")
40 | sleep(detect_time)
41 | continue
42 | for cha in r.challenge:
43 | # cha = r.challenge[1]
44 | # if cha["cb_id"]!="061837cd":
45 | # continue
46 | b1 = bin(id = cha["cb_id"], round =r.round, ip = "none", port = "none", download_url = cha["cb_url"], submit_url = r.url_submit_flag, question_type = cha["score_method"], flag_path = "none",username = username,password = password, url_submit_flag = url_submit_flag)
47 | # b1进行并发,详细功能
48 | b1.auto()
49 | # break
50 | sleep(round_time)
51 | except Exception as e:
52 | print(str(e))
53 |
--------------------------------------------------------------------------------
/robot/sub_answer.py:
--------------------------------------------------------------------------------
1 | #coding=utf-8
2 | import requests
3 | from requests.auth import HTTPBasicAuth
4 | import base64
5 | import json
6 | import time
7 | import sys
8 | from competion import *
9 |
10 |
11 | def submit_payload(payload,id,round,username,password,url_submit_flag):
12 | try:
13 | template = {"RoundID":round,
14 | "Payload":{
15 | "ChallengeID":id,
16 | "Crash":payload}}
17 | submit_data = {"username": username, "password": password, "verify": template}
18 | temstr = json.dumps(submit_data)
19 | headers = {'User-Agent': 'Mozilla/5.0'}
20 |
21 | ret = requests.post(url_submit_flag, json = submit_data, headers=headers,timeout = 30)
22 | print ret.json()
23 | return ret.json()['error_code']
24 | except Exception as e:
25 | print(str(e))
26 | return 1
27 |
28 | # 125 重复提交
29 |
30 |
31 |
32 | def submit_test():
33 | username = "AWW"
34 | password = "102928wujiang"
35 | url_get_machines = "https://anquan.baidu.com/bctf/get_machines_info"
36 | url_get_question = "https://anquan.baidu.com/bctf/latest_round"
37 | url_submit_flag = "https://anquan.baidu.com/bctf/submit"
38 | detect_time = 10 #比赛开始检测时间
39 | round_time = 60 #每轮时间
40 |
41 | r = robot(username,password,url_get_machines,url_get_question,url_submit_flag)
42 | r.get_question()
43 | #
44 | round = r.round
45 | print "round:",round
46 |
47 | for id in r.challenge:
48 | if id["cb_id"]=="baffa440":
49 | print id["cb_id"]
50 | # crashes = ['attachments/061837cd/out/crashes/id:000001,sig:11,src:000000,op:arith8,pos:25,val:-9', 'attachments/061837cd/out/crashes/id:000000,sig:11,src:000000,op:arith8,pos:21,val:-9']
51 | # for crash in crashes:
52 | # file = open(crash,"rb").read()
53 | # encodeStr = base64.b64encode(file)
54 | # print encodeStr
55 | # print id["cb_id"]
56 | # print round
57 | # print username
58 | # print password
59 | # print url_submit_flag
60 | encodeStr = "YXNkZmFzbGRqZmFsa3NkZmFzZGZhc2Rhc2RmYXNsZGpmYWxrc2RmYXNkZmFzZGFzZGZhc2xkamZhbGtzZGZhc2RmYXNkYXNkZmFzbGRqZmFsa3NkZmFzZGZhc2Rhc2RmYXNsZGpmYWxrc2RmYXNkZmFzZGFzZGZhc2xkamZhbGtzZGZhc2RmYXNkYXNkZmFzbGRqZmFsa3NkZmFzZGZhc2Rhc2RmYXNsZGpmYWxrc2RmYXNkZmFzZGFzZGZhc2xkamZhbGtzZGZhc2RmYXNkYXNkZmFzbGRqZmFsa3NkZmFzZGZhc2Rhc2RmYXNsZGpmYWxrc2RmYXNkZmFzZGFzZGZhc2xkamZhbGtzZGZhc2RmYXNkYXNkZmFzbGRqZmFsa3NkZmFzZGZhc2Rhc2RmYXNsZGpmYWxrc2RmYXNkZmFzZGFzZGZhc2xkamZhbGtzZGZhc2RmYXNkYXNkZmFzbGRqZmFsa3NkZmFzZGZhc2Rhc2RmYXNsZGpmYWxrc2RmYXNkZmFzZGFzZGZhc2xkamZhbGtzZGZhc2RmYXNkYXNkZmFzbGRqZmFsa3NkZmFzZGZhc2Rhc2RmYXNsZGpmYWxrc2RmYXNkZmFzZGFzZGZhc2xkamZhbGtzZGZhc2RmYXNkYXNkZmFzbGRqZmFsa3NkZmFzZGZhc2Rhc2RmYXNsZGpmYWxrc2RmYXNkZmFzZGFzZGZhc2xkamZhbGtzZGZhc2RmYXNkYXNkZmFzbGRqZmFsa3NkZmFzZGZhc2Rhc2RmYXNsZGpmYWxrc2RmYXNkZmFzZGFzZGZhc2xkamZhbGtzZGZhc2RmYXNkYXNkZmFzbGRqZmFsa3NkZmFzZGZhc2Rhc2RmYXNsZGpmYWxrc2RmYXNkZmFzZGFzZGZhc2xkamZhbGtzZGZhc2RmYXNkCg=="
61 | submit(encodeStr,id["cb_id"],round,username,password,url_submit_flag)
62 |
63 |
64 | if __name__ == '__main__':
65 | submit_test()
66 |
--------------------------------------------------------------------------------
/start.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # Add your startup script
3 |
4 | # DO NOT DELETE
5 | service ssh start;
6 | sleep infinity;
7 |
--------------------------------------------------------------------------------