├── .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 | ![image-20210622144851380](pic/image-20210622144851380.png) 10 | 11 | 12 | 13 | ### 赛制启动模式 14 | 15 | 赛事启动模式分为两种: 16 | 17 | 第一种 18 | 19 | 1、选手设备、服务器、平台互相联通 20 | 2、选手设备与服务器互相联通、选手设备及服务器均无法连同平台 21 | 3、选手设备、服务器、平台均不互相联通 22 | 4、选手设备无法联通其他,服务器、平台互相联通 23 | 24 | ![image-20210622151138532](pic/image-20210622151138532.png) 25 | 26 | 27 | 28 | 第二种 29 | 30 | 1、选手设备、服务器、平台互相联通 31 | 2、选手设备无法联通其他,服务器、平台互相联通 32 | 3、选手设备、服务器、平台均不互相联通 33 | 4、选手设备无法联通其他,服务器、平台互相联通 34 | 35 | ![image-20210622151152740](pic/image-20210622151152740.png) 36 | 37 | 这两者最大的区别是第二步,关键在于先独立平台,还是先独立选手设备,这两个要根据比赛赛前调试来修改。 38 | 39 | 40 | 41 | ### 平台交互 42 | 43 | 44 | 45 | ![image-20210622144951320](pic/image-20210622144951320.png) 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 | ![image-20210622145034085](pic/image-20210622145034085.png) 94 | 95 | 上图是之前使用的框架,定义了robot的类,包括了图中这些方法,这些方法都是单线的流程走下去的,先调用get_question获取题目信息,然后保存成文件,然后再调用download,同时读取之前保存的题目细节文件,再通过download保存bin细节文件,所有的题目下载完成后,然后调用fuzz,所有的fuzz结束后,保存fuzz_info,之后才会调用exploit,所有的exploit结束后,最后调用submit提交答案。 96 | 这个结构有很多问题,中间有任何一个流程出现了问题,会导致后续的流程全部中断,比如一个二进制下载出问题,会导致所有的题目都无法fuzz; 97 | 不过这个结构很好作并发,所有的并发只要读取上一阶段的保存信息,然后批量执行就行,多进程并发会容易很多; 98 | 但容错性和鲁棒性都很差。 99 | 100 | ![image-20210622145042080](pic/image-20210622145042080.png) 101 | 102 | 上图是修改后的结构框架,定义一个机器人,然后心跳包单独出去,定义competion类,用来执行题目信息获取。然后robot根据获取的题目信息,生成大量的bin实例,每个实例都有自己的下载、fuzz、exploit、提交等功能,每个bin都是多进程并发出去的。 103 | 这样的话,每个bin的工作流程都互相不影响,即便是有一个出现问题,其他bin都会照常运行,稳定性要高很多。 104 | 105 | ![image-20210622145050743](pic/image-20210622145050743.png) 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 | ![image-20210622145929021](pic/image-20210622145929021.png) 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 | 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 | 10 | 11 | 13 | 14 | 15 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 1616055158048 30 | 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 | --------------------------------------------------------------------------------