diff --git a/README.md b/README.md index 81100b8..77fa13d 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # Exploit Farm # -The utility for CTF hacker competition for lauching sploits for all teams +The utility for CTF hacker competition for launching sploits for all teams and submitting flags. ## Prepare ## 1. Set FLAG_FORMAT regexp in flag_format.py -2. Set TEAMS in team_list.py +2. Set teams in team_list.py 3. Edit submit_flags in start_posting.py for the checking system ## Usage ## diff --git a/flag_format.py b/flag_format.py index 9ceefae..4308845 100644 --- a/flag_format.py +++ b/flag_format.py @@ -1,2 +1,2 @@ # put the regexp for flag here -FLAG_FORMAT = b"[0-9A-Fa-f]{32}" +FLAG_FORMAT = b"[Mm]oved" diff --git a/start_posting.py b/start_posting.py index ff8aee0..e009617 100755 --- a/start_posting.py +++ b/start_posting.py @@ -12,13 +12,15 @@ from flag_format import FLAG_FORMAT FLAGS_IN_SUMBIT_ITERATION = 100 -RESTART_DELAY = 2 # in sec FLAGS_GLOB = "flags/*.txt" +HOST = '127.0.0.1' # checksystem hostaddr here +PORT = 31337 # checksystem port here +TIMEOUT = 5 # checksystem timeout +RESTART_DELAY = 2 # in sec def log(text): - print(strftime("%H:%M:%S") + " " + text) - + print(strftime("%H:%M:%S ") + text) class PostedFlags: GOOD_FLAGS_FILE = "posted_good_flags.txt" @@ -58,10 +60,6 @@ def submit_flags(flags, posted_flags): "YOU LIKELY HAVE TO EDIT THIS FUNCTION" # STAGE 0: connecting - HOST = '127.0.0.1' # checksystem hostaddr here - PORT = 31337 # checksystem port here - TIMEOUT = 5 # checksystem timeout - s = socket.create_connection((HOST, PORT), TIMEOUT) # just an example how to use sockets over SSL @@ -74,29 +72,29 @@ def submit_flags(flags, posted_flags): # do_handshake_on_connect=1 # ) - # STAGE 1: check if system greets us - greeting = s.recv(4096) - if b'Hello' not in greeting: - print("Not greeted: " + greeting) - return - - # STAGE 2: send the team name - s.sendall(b"hackerdom\n") - - # STAGE 3: check if system asks for a password - pass_greeting = s.recv(4096) - if b'pass' not in pass_greeting: - print("Not pass-greeted: %s" % pass_greeting) - return - - # STAGE 4: send the password - s.sendall(b"pass\n") - - # STAGE 5: check if system asks for flags - keys_prompt = s.recv(4096) - if b'keys' not in keys_prompt: - print("Not keys prompted %s" % keys_prompt) - return + # # STAGE 1: check if system greets us + # greeting = s.recv(4096) + # if b'Hello' not in greeting: + # print("Not greeted: " + greeting) + # return + # + # # STAGE 2: send the team name + # s.sendall(b"hackerdom\n") + # + # # STAGE 3: check if system asks for a password + # pass_greeting = s.recv(4096) + # if b'pass' not in pass_greeting: + # print("Not pass-greeted: %s" % pass_greeting) + # return + # + # # STAGE 4: send the password + # s.sendall(b"pass\n") + # + # # STAGE 5: check if system asks for flags + # keys_prompt = s.recv(4096) + # if b'keys' not in keys_prompt: + # print("Not keys prompted %s" % keys_prompt) + # return for flag in flags: # STAGE 6: send a flag @@ -128,21 +126,21 @@ def submit_flags(flags, posted_flags): ################################################## -def get_flags(): +def get_all_flags(): flags = list() - flag_files = glob(FLAGS_GLOB) # all files with flags + for flag_file in flag_files: file_contents = open(flag_file, "rb" , 1).read() flags += re.findall(FLAG_FORMAT, file_contents) + return flags # main posting cycle while True: begin_load_time = time() posted_flags = PostedFlags() - flags_set = set(get_flags()) - posted_flags.get() - flags = list(flags_set) + flags = list(set(get_all_flags()) - posted_flags.get()) # get new flags if len(flags) > FLAGS_IN_SUMBIT_ITERATION: flags = random.sample(flags, FLAGS_IN_SUMBIT_ITERATION) diff --git a/start_sploit.py b/start_sploit.py index fe17f58..e63d4c9 100755 --- a/start_sploit.py +++ b/start_sploit.py @@ -1,39 +1,35 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # author: Alexander Bersenev (Bay) from Hackerdom team # starts one sploit for all teams in a loop import re import sys import os +import multiprocessing +import threading +import queue from os.path import basename, splitext, abspath, exists from subprocess import Popen, PIPE, STDOUT -from threading import Thread from time import time, sleep, strftime -try: - from Queue import Queue, Empty -except ImportError: - from queue import Queue, Empty # python 3.x from flag_format import FLAG_FORMAT -from team_list import TEAMS +from team_list import * -MAX_RUNTIME = 60 # in secs, sploit will be restarted if it running too long +MAX_RUNTIME = 2 # in secs, sploit will be restarted if it running too long PAUSE = 10 # in secs, the time between sploit relaunches - def log(text): - print(strftime("%H:%M:%S") + " " + text) - + print(strftime("%H:%M:%S ") + text) -class TeamOwner(Thread): +class TeamOwner(): def __init__(self, sploit_name, team_name, team_ip): - Thread.__init__(self, name=team_name) self.sploit_name = sploit_name self.team_name = team_name self.team_ip = team_ip + # The name of the exploit file without an extension spl_short_name = splitext(basename(sploit_name))[0] self.flag_filename = "flags/%s_%s.txt" % (spl_short_name, team_name) @@ -41,85 +37,92 @@ def __init__(self, sploit_name, team_name, team_ip): savedflags = re.findall(FLAG_FORMAT, open(self.flag_filename, "rb").read()) - self.flags = set(savedflags) + self.flags = set(savedflags) # to avoid duplication self.cycle_num = 0 log("Starting hacking team %s, launching in a loop: %s %s" % (self.team_name, basename(self.sploit_name), self.team_ip)) - def run(self): - while True: - try: - self.cycle_num += 1 - self.last_launch_time = time() - self.launch_spl() - except Exception as E: - log("Exception, team %s: %s" % (self.team_name, E) + "\a") - finally: - if self.cycle_num == 1: - log("Sploit for team %s: hiding output" % self.team_name) - sleep(PAUSE) - - def launch_spl(self): - need_launch_in_shell = (os.name == "nt") - need_close_fd = (os.name != "nt") - # launch sploit proccess with team_ip as arg - spl = Popen([self.sploit_name, self.team_ip], - stdout=PIPE, stderr=STDOUT, bufsize=1, - shell=need_launch_in_shell, close_fds=need_close_fd) - q = Queue() - - # we are processing output in other thread to prevent blocking - def enqueue_output(queue, out): +# !!!!!!!!! 1) It prints the output of the exploit on the screen for the first iteration. Why? +# 2) Why do I need enqueue_output in different thread? ??"prevent blocking"?? + def launch_spl(self,lock): + try: + self.cycle_num += 1 + self.last_launch_time = time() + + need_launch_in_shell = (os.name == "nt") + need_close_fd = (os.name != "nt") + + # launch sploit proccess with team_ip as arg + spl = Popen([self.sploit_name, self.team_ip], + stdout=PIPE, stderr=STDOUT, bufsize=1, + shell=need_launch_in_shell, close_fds=need_close_fd) # !!!!!!!! close_fds why? + q = queue.Queue() + + # we are processing output in other thread to prevent blocking + def enqueue_output(queue, out): + while True: + line = out.readline() + queue.put(line) + if not line: + break + + t = threading.Thread(target=enqueue_output, args=(q, spl.stdout)) + t.daemon = True + t.start() + + # get output by lines until EOF while True: - line = out.readline() - queue.put(line) - if not line: + try: + remaining_time = MAX_RUNTIME - (time() - self.last_launch_time) + line = q.get(timeout=remaining_time) + except (Empty, ValueError): + log("Killing %s sploit(tried to run for more than %d secs)" % ( + self.team_name, MAX_RUNTIME)) break - t = Thread(target=enqueue_output, args=(q, spl.stdout)) - t.daemon = True - t.start() - - # get output by lines until EOF - while True: - try: - remaining_time = MAX_RUNTIME - (time() - self.last_launch_time) - line = q.get(timeout=remaining_time) - except (Empty, ValueError): - log("Killing %s sploit(tried to run for more than %d secs)" % ( - self.team_name, MAX_RUNTIME)) - break - - if not line: - break + if not line: + break - line = line.strip() - if not line: - continue + line = line.strip() + if not line: + continue + if self.cycle_num == 1: + print("%s: %s" % (self.team_name, line)) + + flags = re.findall(FLAG_FORMAT, line) + + for flag in flags: + if flag not in self.flags: + if self.cycle_num == 1: + log("Flag from %s: %s" % (self.team_name, flag)) + with open(self.flag_filename, "ab", 0) as f: + f.write(flag + b"\n") + + lock.acquire() + self.flags.add(flag) + lock.release() + else: + if self.cycle_num == 1: + log("Flag from %s: %s (dup)" % (self.team_name, flag)) + + except Exception as E: + log("Exception, team %s: %s" % (self.team_name, E) + "\a") + finally: if self.cycle_num == 1: - print("%s: %s" % (self.team_name, line)) - - flags = re.findall(FLAG_FORMAT, line) + log("Sploit for team %s: hiding output" % self.team_name) - for flag in flags: - if flag not in self.flags: - if self.cycle_num == 1: - log("Flag from %s: %s" % (self.team_name, flag)) - with open(self.flag_filename, "ab", 0) as f: - f.write(flag + b"\n") +def one_launch(): + while True: + owner = owners_queue.get() - self.flags.add(flag) - else: - if self.cycle_num == 1: - log("Flag from %s: %s (dup)" % (self.team_name, flag)) + if owner is None: + break - if os.name != "nt": - spl.kill() - else: - spl.communicate() + owner.launch_spl(lock) + owners_queue.task_done() # LETS ROCK !!! if len(sys.argv) < 2: @@ -128,57 +131,81 @@ def enqueue_output(queue, out): sploit_name = abspath(sys.argv[1]) if not exists(sploit_name): - print("Sploit doesn't exist: " + sploit_name) + print("Sploit doesn't exist: %s" % sploit_name) sys.exit(1) -# ensure that flag dir is exists +# ensure that flag directory is exists if not exists("flags"): os.makedirs("flags") -if os.name != "nt": - os.setpgrp() - if os.name == "nt": # Because Windows sucks at the proccess management log("Windows detected. Timeouts are not supported on this os!") log("Please write only short-time-running exploits") - MAX_RUNTIME = 0xFFFFFFFF + MAX_RUNTIME = 0xFFFFFFFF # !!!!!!!!!! Why? +lock = threading.Lock() owners = [] -for team_name, team_ip in TEAMS.items(): +owners_queue = queue.Queue() +# generate_teams() +for team_name, team_ip in teams.items(): owner = TeamOwner(sploit_name, team_name, team_ip) - owner.daemon = True owners.append(owner) -try: - for owner in owners: - owner.start() # start pwning thread for each team +workers = [] +for w in range(multiprocessing.cpu_count()): + w = threading.Thread(target=one_launch) + w.daemon = True + w.start() + workers.append(w) + +try: while True: + # generate_teams() + # generate stats in a loop + lock.acquire() + # We need to create a new object so we can later find new flags + # comparing two different sets last_flags = [set(o.flags) for o in owners] last_stats = [(len(o.flags), o.cycle_num) for o in owners] + lock.release() - sleep(60 - int(time()) % 60) # show stat on zero second + for o in owners: + owners_queue.put(o) - curr_flags = [set(o.flags) for o in owners] + sleep(1) # show stat at zero second + owners_queue.join() # block until all sploits are done + + curr_flags = [o.flags for o in owners] curr_stats = [(len(o.flags), o.cycle_num) for o in owners] - stats = [(owners[i].team_name, - curr_stats[i][0], curr_stats[i][0] - last_stats[i][0], - curr_stats[i][1], curr_stats[i][1] - last_stats[i][1], - list(curr_flags[i] - last_flags[i])) - for i in range(len(owners))] - last_flags = ["%s: %s" % (s[0], s[5]) for s in stats] - log("LAST MINUTE NEW FLAGS: " + "\n".join(last_flags)) + stats = [(owners[i].team_name, # stats[0] -- command name + + # stats[1] -- number of flags, stats[2] -- number of new flags + curr_stats[i][0], curr_stats[i][0] - last_stats[i][0], + # stats[3] -- number of cycles, stats[4] -- number of new cycles + curr_stats[i][1], curr_stats[i][1] - last_stats[i][1], + # stats[5] -- new flags + list(curr_flags[i] - last_flags[i])) + for i in range(len(owners))] + + new_flags = ["%s: %s" % (s[0], s[5]) for s in stats] + log("LAST MINUTE NEW FLAGS: " + "\n".join(new_flags)) + flag_stats = ["%s: %d(%d)" % (s[0], s[2], s[1]) for s in stats] log("LAST MINUTE FLAG STATS: " + ", ".join(flag_stats)) + iter_stats = ["%s: %d(%d)" % (s[0], s[4], s[3]) for s in stats] log("LAST MINUTE LAUNCHES STATS: " + ", ".join(iter_stats)) except KeyboardInterrupt: print("Ctrl-c received!") -# kill all sploits with the hardest fire I can cast log("Done") -if os.name != "nt": - os.killpg(0, 9) # UNIX only =( + +# stop workers +for i in range(multiprocessing.cpu_count()): + owners_queue.put(None) +for w in workers: + w.join() diff --git a/team_list.py b/team_list.py index 8044e6f..e542dc7 100644 --- a/team_list.py +++ b/team_list.py @@ -1,7 +1,37 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# import re +# import requests + + +# teams = {} +# def generate_teams(): + # teams = {} + # r = requests.get('https://vpn.ructfe.org/') + # s = r.text +# + # commandsData = re.findall('\s*? ([0-9]*) \s*? (.*) \s*?.\ + # *?\s*?.*?\s*?.*?\s*?.*?\s*?.*?\s*?.*?\ + # \s*?',s) +# + # for data in commandsData: + # for entry in data: + # if entry == "yes": + # A = str(int(60 + int(data[0]) / 256)) + # B = str(int(data[0]) % 256) + # teams[data[0]] = "10."+ A +"." + B + ".2" + # break + + # put the teamnames and ip addresses here -TEAMS = { - "team1" : "127.0.0.1", - "team2" : "127.0.0.2", +teams = { + "team1" : "172.217.4.3", + # "team2" : "127.0.0.2", # "team3" : "127.0.0.3", # "team4" : "127.0.0.4", # "team5" : "127.0.0.5",