Skip to content

Commit

Permalink
Enhance Performance
Browse files Browse the repository at this point in the history
multiprocessing for new Flagger instances
new utils
enhance BinWalker
better nested searches
threading rotates
  • Loading branch information
juba0x00 committed Aug 22, 2023
1 parent bd5e092 commit 049b070
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 70 deletions.
123 changes: 58 additions & 65 deletions flagger.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
# global imports
from os import popen, path, mkdir, listdir, walk
from os import popen, path, mkdir, listdir
from colorama import Fore
from base64 import b16encode, b16decode, b32encode, b32decode, b64encode, b64decode, b85encode, b85decode
from base45 import b45encode, b45decode
Expand All @@ -11,17 +11,35 @@
from modules import oct
from modules import utils
from modules.binwalker import BinWalker

from multiprocessing import Process

class Flagger:
encoded_color = Fore.BLUE
flag_color = Fore.GREEN
online = utils.online()
flag_format: str
verbose: bool
silent: bool
flag_color = Fore.GREEN
online = utils.online() # check if online
flag_format: str # flag format for all instances
verbose: bool # unified verbose for all instances
silent: bool # unified silent for all instances

def __init__(self, filename, no_rot):
valid_files = []
if path.exists(filename):
if path.isdir(filename): # get all the valid files in the directory
valid_files = utils.get_valid_files(filename)
for file in valid_files:
Process(target=Flagger, args=(file, no_rot)).start()
return None # don't fetch flags for the directory itself
else:
walker = BinWalker(filename)
if walker.extracted:
files = listdir(f'{filename}_extracted')
for extracted_file in files:
Process(target=Flagger, args=(f'{filename}_extracted/{extracted_file}', False)).start()

else:
print('File Not Found :(')
exit(0)

self.file_name = filename
self.no_rot = no_rot
self.check_functions = [
Expand All @@ -38,6 +56,7 @@ def __init__(self, filename, no_rot):
f'strings "{self.file_name}" | sort | uniq').read() # didn't use readlines() to remove \n in the following line
self.strings_lines = self.strings_output.split('\n')
del self.strings_output
self.__fetch()

@staticmethod
def echo(encoding, encoded_flag, decoded_flag):
Expand Down Expand Up @@ -88,7 +107,7 @@ def __check_base16_flag(data):
for match in matches:
if base16_flag.lower() in match.lower():
Flagger.echo('hexadecimal', encoded_flag=line,
decoded_flag=b16decode(match.upper()).decode('ascii').replace('\n', ''))
decoded_flag=b16decode(match.upper()).decode('ascii').replace('\n', ''))
# .upper() to avoid hexdecimal decoding errors (ABC..., instead of abc..ABC..., instead of abc....)

@staticmethod
Expand All @@ -114,8 +133,7 @@ def __check_base45_flag(data):
@staticmethod
def __check_base64_flag(data):
base64_flag = b64encode(Flagger.flag_format.encode('ascii')).decode('ascii').replace('=', '')

base64_flag = base64_flag[:len(base64_flag) - 1] # to avoid the last digit unmatchinglf.__check_base16_flag,
base64_flag = base64_flag[:len(base64_flag) - 1] # to avoid the last digit unmatching
for line in data:
matches = findall(r'\b[A-Za-z0-9+/]{4,}(?:==?|=\n)?', line)
for match in matches:
Expand All @@ -132,21 +150,23 @@ def __check_base85_flag(data):
if base85_flag in match:
Flagger.echo('base85', match, b85decode(line.encode('ascii')).decode('ascii'))

def rotator(self, data, key):
@staticmethod
def rotator(data, key):
rotated_lines = []
for line in data:
alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
't',
'u', 'v', 'w', 'x', 'y', 'z']
shifted_alphabet = [''] * len(alphabet)

# Fill shifted_alphabet
for i in range(len(alphabet)):
shifted_alphabet[i] = alphabet[(i + key) % len(alphabet)]

# Substitution
deciphered = [''] * len(line)
exists = False

for i in range(len(line)):
for j in range(len(shifted_alphabet)):
if line[i].casefold() == alphabet[j].casefold():
Expand All @@ -158,24 +178,18 @@ def rotator(self, data, key):

if not exists:
deciphered[i] = line[i]

# Put the result in a string
rotated = ''.join(deciphered)
with open(f'{self.file_name}_rotates/rot{key}', 'w') as saving_file:
if Flagger.flag_format.lower() in rotated:
Flagger.echo('rot', f"ROT{key}", rotated)
else:
saving_file.write(f'{rotated}\n')

def rotate(self):
if not path.exists(f'{self.file_name}_rotates'):
mkdir(f'{self.file_name}_rotates')

rotated_lines.append(''.join(deciphered))
return rotated_lines


def rotate(self, key):
# rotate and check after rotation
for rot in range(1, 26):
self.rotator(self.strings_lines[:], rot)


with open(f'{self.file_name}_rotates/rot{key}', 'w') as saving_file:
saving_file.writelines(f'{line}\n' for line in Flagger.rotator(self.strings_lines[:], key))
#? saving_file.writelines(f'{line}\n' for line in rotated_lines, key))
@staticmethod
def shift(text, shifts):
shifted_back = ""
Expand All @@ -188,14 +202,13 @@ def shift(text, shifts):
try: # avoid out of range code
shifted_back += chr(ord(char) - shifts)
shifted_forward += chr(ord(char) + shifts)



except Exception as e:
pass

if Flagger.flag_format in shifted_back:
Flagger.echo(f'shift{shifts}', line, shifted_back)

elif Flagger.flag_format in shifted_forward:
Flagger.echo(f'shift{shifts}', line, shifted_forward)
shifted_back = ""
Expand All @@ -219,60 +232,40 @@ def check_all_bases(self):

def check_all_rotations(self):
if not self.no_rot:
self.rotate()
for file in listdir(f'{self.file_name}_rotates/'):
flag_fetcher = Flagger(filename=f'{self.file_name}_rotates/{file}', no_rot=True) # don't rotate
flag_fetcher.fetch()
if not path.exists(f'{self.file_name}_rotates'):
mkdir(f'{self.file_name}_rotates')
for key in range(1, 26):
Thread(target=self.rotate, args=(key,)).start()
Process(target=Flagger, args=(f'{self.file_name}_rotates/', True)).start() # don't rotate, avoid infinite loop

def check_all_shifts(self):
for shifts in range(2, 26):
Thread(target=self.shift, args=[self.strings_lines[:], shifts]).start() if not self.no_rot else None

def check_all_hashes(self):
if Flagger.online:
for line in self.strings_lines[:]:
Thread(target=self.crack_md5, args=[line]).start()

def fetch(self):
def __fetch(self):
print(f'{"_" * 10} searching in {self.file_name} {"_" * 10}')
self.check_all_bases()

self.check_all_rotations()

self.check_all_shifts()

self.check_all_hashes()


def main():
args = utils.parse_arguments()
valid_files = []
if path.exists(args.file_name):
if path.isdir(args.file_name): # get all the valid files in the directory
for root, dirs, files in walk(args.file_name):
for file in files:
valid_files.append(path.join(root, file))
else: # only this file
valid_files.append(args.file_name)
else:
print('File Not Found :(')
exit(0)
Flagger.flag_format = args.flag_format # set the flag format for the class (all the instances)
# I added the previous line here to be executed at the first instance only
# , if it's in the constructor it will be executed in each instance creation
Flagger.verbose = args.verbose
Flagger.silent = args.silent

for file in valid_files: # iterate over all the valid files and fetch the flag
flag_fetcher = Flagger(filename=file, no_rot=args.no_rot)
flag_fetcher.fetch()
walker = BinWalker(flag_fetcher.file_name)
if walker.extracted:
files = listdir(f'{flag_fetcher.file_name}.extracted')
for extracted_file in files:
child_flag_fetcher = Flagger(filename=f'{flag_fetcher.file_name}.extracted/{extracted_file}',
no_rot=False)
child_flag_fetcher.fetch()
Process(target=Flagger, args=(args.file_name, args.no_rot)).start() # create an instance of the class


if __name__ == '__main__':
Expand Down
7 changes: 3 additions & 4 deletions modules/binwalker.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,14 @@ def __init__(self, binary_file):
binary_file (str): The binary file to be extracted.
"""
self.binary_file = binary_file
self.binwalk_installed = self.is_binwalk_installed

if self.binwalk_installed and self.extract():
self.extracted = True
else:
self.extracted = False

@property
def is_binwalk_installed(self):
def binwalk_installed(self):
"""
Checks if binwalk is installed.
Expand All @@ -45,11 +44,11 @@ def extract(self):
print('File does not exist')
return False

if path.exists(f'{self.binary_file}.extracted'):
if path.exists(f'{self.binary_file}_extracted'):
return True

subprocess.run(['binwalk', '-e', self.binary_file], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
if path.exists(f'{self.binary_file}.extracted'):
if path.exists(f'{self.binary_file}_extracted'):
return True
else:
return False
17 changes: 16 additions & 1 deletion modules/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from argparse import ArgumentParser
from requests import get
from PIL import Image
from os import walk, path
from re import match
from shutil import rmtree


def online():
Expand Down Expand Up @@ -34,4 +37,16 @@ def is_png(file_path):
with Image.open(file_path) as image:
return image.format == 'PNG'
except IOError:
return False
return False


def get_valid_files(directory: str) -> list:
valid_files = []
for root, _, files in walk(directory):
if match(r".*_rotates$", root):
rmtree(root)
else:
for file in files:
valid_files.append(path.join(root, file))

return valid_files

0 comments on commit 049b070

Please sign in to comment.