├── LICENSE ├── README.md ├── cyberbot.py ├── modules ├── helloworld │ ├── config.json │ ├── helloworld.py │ └── peoples.txt ├── mongodb_unauth_access │ └── mongodb_unauth_access.py └── redis_unauth_access │ └── redis_unauth_access.py └── screenshots └── console_monitor.gif /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cyberbot 2 | 3 | Cyberbot is a lightweight batch scanning framework based on gevent. Security researchers wrote many sample PoCs for vulnerabilities, using cyberbot framework to do batch scanning easily. 4 | 5 | Install 6 | ---- 7 | 8 | Cyberbot framework based on [gevent](http://www.gevent.org) library, you must install gevent library for the first: 9 | 10 | pip install gevent 11 | 12 | Then clone this repository: 13 | 14 | git clone https://github.com/RickGray/cyberbot.git cyberbot 15 | 16 | Cyberbot framework works out of the box with [Python](http://www.python.org/download/) version **2.7.x** and [gevent](http://www.gevent.org) support. 17 | 18 | Usage 19 | ---- 20 | 21 | Start with a JSON configuration file loaded: 22 | 23 | python cyberbot.py -c modules/helloworld/config.json 24 | 25 | Or override options with commands: 26 | 27 | python cyberbot.py -n helloworld \ 28 | -r modules/helloworld/helloworld.py \ 29 | -t modules/helloworld/peoples.txt \ 30 | --poc-func=run \ 31 | --poc-callback=callback \ 32 | --task-dir=tasks/test_helloworld \ 33 | --proc-num=4 \ 34 | --pool-size=20 \ 35 | --pool-timeout=120 36 | 37 | To get a list of all options use: 38 | 39 | python cyberbot.py -h 40 | 41 | Also can run console monitor with `--enable-console` option: 42 | 43 | ![](screenshots/console_monitor.gif) 44 | -------------------------------------------------------------------------------- /cyberbot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | import os 5 | import sys 6 | import json 7 | import math 8 | import time 9 | import shutil 10 | import curses 11 | import logging 12 | 13 | from io import StringIO 14 | from argparse import ArgumentParser 15 | from itertools import chain 16 | from itertools import islice 17 | from multiprocessing import Queue 18 | from multiprocessing import Process 19 | from multiprocessing import current_process 20 | 21 | from gevent import pool 22 | from gevent import monkey 23 | from gevent import timeout 24 | 25 | monkey.patch_socket() 26 | 27 | 28 | def count_file_linenum(filename): 29 | """ Count the number of lines in file 30 | 31 | Args: 32 | filename: A file path need to count the number of lines 33 | 34 | Returns: 35 | A Integer, the number of lines in file. 36 | """ 37 | with open(filename) as f: 38 | n = f.readlines().__len__() 39 | return n 40 | 41 | 42 | def split_file_by_linenum(filename, linenum_of_perfile=30*10**6): 43 | """ Split one file into serval files with a solit line number 44 | 45 | Args: 46 | filename: A file path need to split with linenum 47 | linenum_of_perfile: The line number of per file 48 | 49 | Returns: 50 | Filenames list has already splited. 51 | """ 52 | def chunks(iterable, n): 53 | iterable = iter(iterable) 54 | while True: 55 | yield chain([next(iterable)], islice(iterable, n-1)) 56 | 57 | filenames = [] 58 | with open(filename) as f: 59 | for i, lines in enumerate(chunks(f, linenum_of_perfile)): 60 | _ = '{}_{:02d}'.format(filename, i) 61 | filenames.append(_) 62 | with open(_, 'w') as wf: 63 | wf.writelines(lines) 64 | return filenames 65 | 66 | 67 | def split_file_by_filenum(filename, filenum): 68 | """ Split one file into serval files with a number of files """ 69 | if filenum <= 1: 70 | filenames = [filename] 71 | else: 72 | linenum = count_file_linenum(filename) 73 | if linenum < filenum: 74 | raise OptException('proc_num more than line number of seed file') 75 | linenum_of_perfile = int(math.ceil(linenum / float(filenum))) 76 | filenames = split_file_by_linenum(filename, linenum_of_perfile) 77 | return filenames 78 | 79 | 80 | class OptException(Exception): 81 | pass 82 | 83 | 84 | class Config(object): 85 | scanname = None # scanning task name 86 | seedfile = None # seed file path to process 87 | task_dir = None # task files stored directory 88 | proc_num = None # process number to use 89 | pool_size = None # pool task size of per process 90 | pool_timeout = None # pool task timeout of per process 91 | poc_file = None # poc file path 92 | poc_func = None # function to run in poc file 93 | poc_callback = None # callback function in poc file 94 | 95 | enable_console = None # console monitor on/off 96 | 97 | scan_func = None # function method instance 98 | scan_callback = None # callback method instance 99 | 100 | def from_keys(self, keys): 101 | for k, v in keys.items(): 102 | if hasattr(self, k) and v is not None: 103 | setattr(self, k, v) 104 | 105 | def from_jsonfile(self, jsonfile): 106 | """ Load options from json file """ 107 | with open(jsonfile) as f: 108 | content = f.read() 109 | keys = json.loads(content) 110 | self.from_keys(keys) 111 | 112 | @property 113 | def __dict__(self): 114 | return dict(scanname=self.scanname, 115 | seedfile=self.seedfile, 116 | task_dir=self.task_dir, 117 | proc_num=self.proc_num, 118 | pool_size=self.pool_size, 119 | pool_timeout=self.pool_timeout, 120 | poc_file=self.poc_file, 121 | poc_func=self.poc_func, 122 | poc_callback=self.poc_callback) 123 | 124 | 125 | class ConsoleMonitor(object): 126 | """ Console monitor with buildin module "curses" 127 | dococument: https://docs.python.org/2/library/curses.html 128 | """ 129 | def __init__(self, config, processes, progress_queue, output_queue): 130 | self.config = config 131 | self.processes = processes 132 | self.progress_queue = progress_queue 133 | self.output_queue = output_queue 134 | 135 | self.stdscr = None 136 | self.pgsscr = None 137 | self.cntscr = None 138 | self.optscr = None 139 | 140 | self.stdscr_size = None 141 | self.pgsscr_size = None 142 | self.cntscr_size = None 143 | self.optscr_size = None 144 | 145 | self.task_total = None 146 | self.task_num = None 147 | self.start_time = time.time() 148 | self.progress = {} 149 | self.contents = [] 150 | 151 | self.init_scr() 152 | 153 | def init_scr(self): 154 | self.stdscr = curses.initscr() 155 | curses.noecho() 156 | curses.curs_set(0) 157 | 158 | self.stdscr_size = self.stdscr.getmaxyx() 159 | self.task_total = count_file_linenum(self.config.seedfile) 160 | 161 | self.pgsscr_size = (self.config.proc_num + 2, 40) 162 | self.pgsscr = curses.newpad(*self.pgsscr_size) 163 | self.cntscr_size = (4, 40) 164 | self.cntscr = curses.newpad(*self.cntscr_size) 165 | self.optscr_size = (18, 80) 166 | self.optscr = curses.newpad(*self.optscr_size) 167 | 168 | def build_progress_screen(self): 169 | c_rows = max(self.config.proc_num + 2, 6) 170 | c_columns = (40 if self.stdscr_size[1] / 2 < 40 171 | else self.stdscr_size[1] / 2) 172 | c_rows, c_columns = int(c_rows), int(c_columns) 173 | self.pgsscr_size = (c_rows, c_columns) 174 | self.pgsscr.resize(*self.pgsscr_size) 175 | bar_max = (25 if self.pgsscr_size[1] < 40 176 | else self.pgsscr_size[1] - 15) 177 | 178 | while not self.progress_queue.empty(): 179 | proc_name, count, task_total = self.progress_queue.get() 180 | self.progress[proc_name] = count 181 | i = int(proc_name.split('-')[1]) 182 | pct = float(count) / task_total 183 | bar = ('='*int(pct*bar_max)).ljust(bar_max) 184 | o = ' {:<2d} [{}{:>6.2f}%] '.format(i, bar, pct*100) 185 | self.pgsscr.addstr(i, 0, o) 186 | 187 | self.pgsscr.refresh(0, 0, 0, 0, c_rows, c_columns) 188 | 189 | def build_status_screen(self): 190 | c_rows = max(self.config.proc_num + 2, 6) 191 | c_columns = (40 if self.stdscr_size[1] / 2 < 40 192 | else self.stdscr_size[1] / 2) 193 | c_rows, c_columns = int(c_rows), int(c_columns) 194 | self.cntscr_size = (c_rows, c_columns) 195 | self.task_num = sum([v for k, v in self.progress.items()]) 196 | running_time = time.strftime('%H:%M:%S', 197 | time.gmtime(time.time()-self.start_time)) 198 | self.cntscr.resize(*self.cntscr_size) 199 | self.cntscr.addstr(1, 0, 'Total: {}'.format(self.task_total)) 200 | self.cntscr.addstr(2, 0, 'Current: {}'.format(self.task_num)) 201 | self.cntscr.addstr(4, 0, 'Running Time: {}'.format(running_time)) 202 | self.cntscr.refresh(0, 0, 0, c_columns, c_rows, c_columns*2) 203 | 204 | def build_output_screen(self): 205 | without_stream_logger = logging.getLogger('output.without.stream') 206 | offset_rows = int(max(self.pgsscr_size[0], self.cntscr_size[0])) 207 | c_rows = self.stdscr_size[0] - offset_rows 208 | c_columns = self.stdscr_size[1] 209 | c_rows, c_columns = int(c_rows), int(c_columns) 210 | 211 | self.optscr_size = (c_rows, c_columns) 212 | self.optscr.resize(*self.optscr_size) 213 | self.optscr.border(1, 1, 0, 0) 214 | 215 | if len(self.contents) > c_rows: 216 | self.contents = self.contents[len(self.contents)-c_rows+1:] 217 | else: 218 | self.contents.extend(['']*(c_rows-len(self.contents)-1)) 219 | 220 | while not self.output_queue.empty(): 221 | proc_name, output = self.output_queue.get() 222 | # o = ('[{}]({}):{}' 223 | # .format(time.strftime('%T %d,%B %Y', time.localtime()), 224 | # proc_name.strip(), output)) 225 | o = '{}'.format(output) 226 | without_stream_logger.info(o) 227 | 228 | self.contents = self.contents[1:] 229 | self.contents.append(o if len(o) < c_columns else o[:c_columns]) 230 | self.optscr.move(0, 0) 231 | self.optscr.clrtobot() 232 | for i, v in enumerate(self.contents): 233 | self.optscr.addstr(i, 0, v) 234 | 235 | self.optscr.refresh(0, 0, offset_rows, 0, 236 | c_rows + offset_rows, c_columns) 237 | 238 | def run(self): 239 | while any(_.is_alive() for _ in self.processes): 240 | time.sleep(0.1) 241 | self.stdscr_size = self.stdscr.getmaxyx() 242 | self.build_progress_screen() 243 | self.build_status_screen() 244 | self.build_output_screen() 245 | 246 | # terminate manually when all tasks finished 247 | if self.task_num == self.task_total: 248 | for _ in self.processes: 249 | _.terminate() 250 | 251 | self.stdscr.addstr(self.stdscr_size[0] - 2, 0, 252 | 'Done! please type "q" to exit.') 253 | self.stdscr.refresh() 254 | while self.stdscr.getch() != ord('q'): 255 | time.sleep(1) 256 | 257 | curses.endwin() 258 | 259 | 260 | class ProcessIO(StringIO): 261 | def __init__(self, output_queue, *args, **kwargs): 262 | super(StringIO, self).__init__(*args, **kwargs) 263 | self.output_queue = output_queue 264 | self.proc_name = current_process().name 265 | 266 | def write(self, s): 267 | if s == '\n': 268 | return 269 | self.output_queue.put((self.proc_name, s.strip())) 270 | 271 | 272 | class ProcessTask(object): 273 | def __init__(self, scan_func, pool_size, pool_timeout): 274 | self.scan_func = scan_func 275 | self.pool_size = pool_size 276 | self.pool_timeout = pool_timeout 277 | 278 | @staticmethod 279 | def callback(result): 280 | return result 281 | 282 | def pool_task_with_timeout(self, line): 283 | seed = line.strip() 284 | result = dict(seed=seed, data=None, exception=None) 285 | try: 286 | data = timeout.with_timeout(self.pool_timeout, 287 | self.scan_func, 288 | seed) 289 | except (Exception, timeout.Timeout) as ex: 290 | result['exception'] = str(ex) 291 | else: 292 | result['data'] = data 293 | return result 294 | 295 | def run(self, seedfile, progress_queue, output_queue): 296 | task_total = count_file_linenum(seedfile) 297 | proc_name = current_process().name 298 | sys.stdout = ProcessIO(output_queue) 299 | 300 | def progress_tracking(greenlet): 301 | count = getattr(progress_tracking, 'count', 0) + 1 302 | setattr(progress_tracking, 'count', count) 303 | progress_queue.put((proc_name, count, task_total)) 304 | return greenlet 305 | 306 | po = pool.Pool(self.pool_size) 307 | with open(seedfile) as f: 308 | for line in f: 309 | g = po.apply_async(func=self.pool_task_with_timeout, 310 | args=(line, ), 311 | kwds=None, 312 | callback=self.callback) 313 | g.link(progress_tracking) 314 | po.add(g) 315 | 316 | try: 317 | po.join() 318 | except (KeyboardInterrupt, SystemExit) as ex: 319 | print(str(ex)) 320 | po.kill() 321 | 322 | 323 | class Launcher(object): 324 | def __init__(self, options): 325 | self.config = Config() 326 | self._init_conf(options) 327 | self._init_env() 328 | self._init_mod() 329 | self._init_logger() 330 | 331 | def _init_conf(self, options): 332 | config = options.CONFIG 333 | opts = vars(options) 334 | opts.pop('CONFIG') 335 | opts = dict((k.lower(), v) for k, v in opts.items()) 336 | self.config.from_keys(opts) 337 | if config: 338 | self.config.from_jsonfile(config) 339 | 340 | # check options required 341 | for k, v in opts.items(): 342 | if hasattr(self.config, k): 343 | value = getattr(self.config, k) 344 | if value is None: 345 | raise OptException('{} option required, ' 346 | 'use -h for help'.format(k)) 347 | 348 | def _init_env(self): 349 | cwd = os.getcwd() 350 | task_dir = os.path.realpath(os.path.join(cwd, self.config.task_dir)) 351 | seedfile = os.path.realpath(os.path.join(cwd, self.config.seedfile)) 352 | poc_file = os.path.realpath(os.path.join(cwd, self.config.poc_file)) 353 | 354 | try: 355 | self.config.proc_num = int(self.config.proc_num) 356 | self.config.pool_size = int(self.config.pool_size) 357 | self.config.pool_timeout = int(self.config.pool_timeout) 358 | except ValueError as ex: 359 | raise OptException('wrong option type, "{}"'.format(str(ex))) 360 | 361 | if not os.path.exists(seedfile): 362 | raise OptException('seed file not exists, {}'.format(seedfile)) 363 | if not os.path.exists(poc_file): 364 | raise OptException('poc file not exists, {}'.format(poc_file)) 365 | 366 | if not os.path.exists(task_dir): 367 | os.makedirs(task_dir) 368 | 369 | # timestamp = time.strftime('%Y%m%d-%H%M%S', time.localtime()) 370 | # task_runtime_dir = os.path.join(task_dir, timestamp) 371 | # if not os.path.exists(task_runtime_dir): 372 | # os.makedirs(task_runtime_dir) 373 | task_runtime_dir = task_dir 374 | 375 | shutil.copy(seedfile, task_runtime_dir) 376 | self.config.seedfile = os.path.realpath(os.path.join(task_runtime_dir, 377 | os.path.basename(seedfile))) 378 | shutil.copy(poc_file, task_runtime_dir) 379 | self.config.poc_file = os.path.realpath(os.path.join(task_runtime_dir, 380 | os.path.basename(poc_file))) 381 | self.config.task_dir = task_dir 382 | 383 | # dump options to json file in task directory 384 | d_opts = vars(self.config) 385 | conffile = os.path.join(task_runtime_dir, 'config.json') 386 | with open(conffile, 'w') as f: 387 | f.write(json.dumps(d_opts, indent=4, sort_keys=True)) 388 | 389 | os.chdir(task_runtime_dir) 390 | 391 | def _init_mod(self): 392 | sys.path.append( 393 | os.path.abspath(os.path.dirname(self.config.poc_file))) 394 | poc_name = os.path.splitext(os.path.basename(self.config.poc_file))[0] 395 | poc_mod = __import__(poc_name) 396 | self.config.scan_func = getattr(poc_mod, self.config.poc_func) 397 | if self.config.poc_callback: 398 | self.config.scan_callback = getattr(poc_mod, 399 | self.config.poc_callback) 400 | 401 | def _init_logger(self): 402 | output_file_handler = logging.FileHandler('output.log', mode='w') 403 | output_file_handler.setFormatter(logging.Formatter('%(message)s')) 404 | output_file_handler.setLevel(logging.INFO) 405 | 406 | output_stream_handdler = logging.StreamHandler() 407 | output_stream_handdler.setFormatter(logging.Formatter('%(message)s')) 408 | output_stream_handdler.setLevel(logging.INFO) 409 | 410 | with_stream_logger = logging.getLogger('output.with.stream') 411 | without_stream_logger = logging.getLogger('output.without.stream') 412 | 413 | with_stream_logger.addHandler(output_file_handler) 414 | with_stream_logger.addHandler(output_stream_handdler) 415 | with_stream_logger.setLevel(logging.DEBUG) 416 | 417 | without_stream_logger.addHandler(output_file_handler) 418 | without_stream_logger.setLevel(logging.DEBUG) 419 | 420 | def run(self): 421 | """ Start ProcessTask main function """ 422 | filenames = split_file_by_filenum(self.config.seedfile, 423 | self.config.proc_num) 424 | output_queue = Queue() 425 | progress_queue = Queue() 426 | processes = [] 427 | w = ProcessTask(self.config.scan_func, 428 | self.config.pool_size, 429 | self.config.pool_timeout) 430 | if self.config.scan_callback: 431 | w.callback = self.config.scan_callback 432 | 433 | for i, filename in enumerate(filenames): 434 | proc_name = 'Worker-{:<2d}'.format(i+1) 435 | p = Process(name=proc_name, 436 | target=w.run, 437 | args=(filename, progress_queue, output_queue)) 438 | if p not in processes: 439 | processes.append(p) 440 | 441 | for p in processes: 442 | p.start() 443 | 444 | if self.config.enable_console: 445 | monitor = ConsoleMonitor(self.config, 446 | processes, 447 | progress_queue, 448 | output_queue) 449 | monitor.run() 450 | 451 | else: 452 | progress = {} 453 | task_total = count_file_linenum(self.config.seedfile) 454 | task_num = 0 455 | with_stream_logger = logging.getLogger('output.with.stream') 456 | 457 | while any(p.is_alive() for p in processes): 458 | time.sleep(0.1) 459 | while not progress_queue.empty(): 460 | proc_name, count, task_total = progress_queue.get() 461 | progress[proc_name] = count 462 | task_num = sum([v for k, v in progress.items()]) 463 | while not output_queue.empty(): 464 | proc_name, output = output_queue.get() 465 | with_stream_logger.info('{}'.format(output)) 466 | 467 | if task_num == task_total: 468 | for _ in processes: 469 | _.terminate() 470 | 471 | 472 | DESC = 'A lightweight batch scanning framework based on gevent.' 473 | 474 | 475 | def commands(): 476 | parser = ArgumentParser(description=DESC) 477 | 478 | parser.add_argument('-c', '--config', dest='CONFIG', default=None, 479 | type=str, help='config file of launcher') 480 | parser.add_argument('-n', '--scanname', dest='SCANNAME', 481 | type=str, help='alias name of launcher') 482 | parser.add_argument('-t', '--seedfile', dest='SEEDFILE', 483 | type=str, help='seed file path to scan') 484 | parser.add_argument('-r', '--poc-file', dest='POC_FILE', 485 | type=str, help='poc file path to load') 486 | parser.add_argument('-f', '--poc-func', dest='POC_FUNC', 487 | default='run', type=str, 488 | help='function name to run in poc file') 489 | parser.add_argument('-b', '--poc-callback', dest='POC_CALLBACK', 490 | default='callback', type=str, 491 | help='callback function name in poc file') 492 | 493 | parser.add_argument('--task-dir', dest='TASK_DIR', 494 | default='tasks/', type=str, 495 | help='task files stored directory (default: "tasks/")') 496 | parser.add_argument('--proc-num', dest='PROC_NUM', 497 | default=4, type=int, 498 | help='process numbers to run (default: 4)') 499 | parser.add_argument('--pool-size', dest='POOL_SIZE', 500 | default=100, type=int, 501 | help='pool size in per process (default: 100)') 502 | parser.add_argument('--pool-timeout', dest='POOL_TIMEOUT', 503 | default=180, type=int, 504 | help='pool timeout in per process') 505 | 506 | parser.add_argument('--enable-console', dest='ENABLE_CONSOLE', 507 | action='store_true', default=False, 508 | help='enable real-time console monitor') 509 | 510 | return parser.parse_args() 511 | 512 | 513 | if __name__ == '__main__': 514 | launcher = Launcher(commands()) 515 | launcher.run() 516 | -------------------------------------------------------------------------------- /modules/helloworld/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "poc_callback": "callback", 3 | "poc_file": "./modules/helloworld/helloworld.py", 4 | "poc_func": "run", 5 | "pool_size": 20, 6 | "pool_timeout": 120, 7 | "proc_num": 4, 8 | "scanname": "helloworld", 9 | "seedfile": "./modules/helloworld/peoples.txt", 10 | "task_dir": "./tasks/test_helloworld" 11 | } 12 | -------------------------------------------------------------------------------- /modules/helloworld/helloworld.py: -------------------------------------------------------------------------------- 1 | import time 2 | import random 3 | 4 | 5 | def run(seed): 6 | """ function to run 7 | 8 | Args: 9 | seed: The value of each line striped in seed file 10 | 11 | Returns: 12 | String, object, list, directory, etc. 13 | """ 14 | 15 | name, age = seed.split(',') 16 | return 'Hello World! {}, {}'.format(seed, int(age)) 17 | 18 | 19 | def callback(result): 20 | """ callback function to call 21 | 22 | Args: 23 | result: ProcessTask instance pool_task_with_timeout() method returned 24 | 25 | result = { 26 | 'seed': 'Jone', 27 | 'data': 'Hello World! Jone', 28 | 'exception': None 29 | } 30 | 31 | result = { 32 | 'seed': 'Jone', 33 | 'data': None, 34 | 'exception': 'ValueError: invalid literal' 35 | } 36 | 37 | Returns: 38 | Anything want to return. 39 | """ 40 | 41 | seed = result['seed'] 42 | data = result['data'] 43 | exception = result['exception'] 44 | time.sleep(random.random() * random.random() / 50) 45 | print('seed: "{}", data: "{}", exception: "{}"' 46 | .format(seed, data, exception)) 47 | -------------------------------------------------------------------------------- /modules/mongodb_unauth_access/mongodb_unauth_access.py: -------------------------------------------------------------------------------- 1 | import gevent 2 | import pymongo 3 | 4 | gevent.monkey.patch_all() 5 | 6 | 7 | def run(seed): 8 | try: 9 | ip, port = seed.split(':') 10 | except ValueError as ex: 11 | ip, port = seed, 27017 12 | 13 | conn = pymongo.MongoClient(ip, int(port), connectTimeoutMS=2000, 14 | serverSelectionTimeoutMS=2000, 15 | maxPoolSize=1000, waitQueueMultiple=1000, 16 | connect=False) 17 | if conn.database_names(): 18 | info = conn.server_info() 19 | return info 20 | 21 | 22 | def callback(result): 23 | seed = result['seed'] 24 | data = result['data'] 25 | exception = result['exception'] 26 | 27 | if data: 28 | version = data.get('version', '') if data else None 29 | 30 | print('seed: "{}", version: "{}", exception: "{}"' 31 | .format(seed, version, exception)) 32 | 33 | 34 | 35 | if __name__ == '__main__': 36 | import sys 37 | if len(sys.argv) < 2: 38 | print('Usage: python {} '.format(sys.argv[0])) 39 | sys.exit() 40 | 41 | callback(dict(seed=sys.argv[1].strip(), 42 | data=run(sys.argv[1].strip()), 43 | exception=None)) 44 | -------------------------------------------------------------------------------- /modules/redis_unauth_access/redis_unauth_access.py: -------------------------------------------------------------------------------- 1 | import redis 2 | 3 | 4 | def run(seed): 5 | try: 6 | ip, port = seed.split(':') 7 | except ValueError as ex: 8 | ip, port = seed, 6379 9 | 10 | r = redis.Redis(ip, int(port), socket_connect_timeout=5) 11 | info = r.info() 12 | return info 13 | 14 | 15 | def callback(result): 16 | seed = result['seed'] 17 | data = result['data'] 18 | exception = result['exception'] 19 | 20 | if data: 21 | version = data.get('redis_version', '') if data else None 22 | os = data.get('os', '') if data else None 23 | 24 | print('seed: "{}", version: "{}", os: "{}", exception: "{}"' 25 | .format(seed, version, os, exception)) 26 | 27 | 28 | if __name__ == '__main__': 29 | import sys 30 | if len(sys.argv) < 2: 31 | print('Usage: python {} '.format(sys.argv[0])) 32 | sys.exit() 33 | 34 | callback(dict(seed=sys.argv[1].strip(), 35 | data=run(sys.argv[1].strip()), 36 | exception=None)) 37 | -------------------------------------------------------------------------------- /screenshots/console_monitor.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RickGray/cyberbot/2bf63939b14faaf4f0bbd88d5cc43bbdaa290471/screenshots/console_monitor.gif --------------------------------------------------------------------------------