hassh/python/hasshGen/hasshgen.py
Patrick Kelley 169641c514 Initial
2025-05-07 14:12:22 -04:00

193 lines
7.4 KiB
Python

#!/usr/bin/env python3
# Copyright (c) 2018, salesforce.com, inc.
# All rights reserved.
# Licensed under the BSD 3-Clause license.
# For full license text, see the LICENSE file in the repo root
# or https://opensource.org/licenses/BSD-3-Clause
import argparse
import json
import docker
import time
from subprocess import Popen
__author__ = "Adel '0x4D31' Karimi"
__email__ = "akarimishiraz@salesforce.com"
__version__ = "1.0"
__copyright__ = "Copyright (c) 2018, salesforce.com, inc."
__license__ = "BSD 3-Clause License"
# Default command for running hassh.py
HASSH_COMMAND = 'python3 ../hassh.py -i en1 -l json -o fingerprint.json'
# Dockerfiles directory
DOCKERFILE_DIR = 'dockerfiles'
def parse_cmd_args():
"""parse command line arguments"""
desc = "A python script to automate building docker images with different\
SSH clients/versions."
parser = argparse.ArgumentParser(description=(desc))
helptxt = 'Docker image name. e.g. alpine, ubuntu'
parser.add_argument('-i', '--image', type=str, help=helptxt)
helptxt = 'Docker image version. e.g. 18.04, latest'
parser.add_argument('-iV', '--image_ver', type=str, help=helptxt)
helptxt = 'SSH client name'
parser.add_argument('-c', '--sshclient', type=str, help=helptxt)
helptxt = 'SSH client version'
parser.add_argument('-cV', '--sshclient_ver', type=str, help=helptxt)
helptxt = 'Specify the Dockerfile'
parser.add_argument('-d', '--docker_file', type=str, help=helptxt)
helptxt = 'Specify the server address to test the SSH connection'
parser.add_argument(
'-s', '--server', type=str, required=True, help=helptxt)
helptxt = 'Bulk mode; Specify an input file containing a list of docker\
image, image version, sshclient and sshclient version'
parser.add_argument('-iF', '--input_file', type=str, help=helptxt)
helptxt = 'Set this option to automatically run hassh.py for capturing SSH\
client fingerprints (HASSH). Specify the command for running hassh.py\
using --cmd arg.'
parser.add_argument(
'-f', '--fingerprint', action="store_true", help=helptxt)
helptxt = 'Enter the command for running hassh.py. Use with\
-f/--fingerprint arg'
parser.add_argument(
'--cmd', type=str, default=HASSH_COMMAND, help=helptxt)
return parser.parse_args()
def command_exec(container, server, ssh_client, rm):
"""Runs the container and exec SSH command"""
client = docker.DockerClient(
base_url='unix://var/run/docker.sock',
version='auto')
if 'openssh' in ssh_client:
cmd = ('ssh -o UserKnownHostsFile=/dev/null '
'-o StrictHostKeyChecking=no {}').format(server)
elif 'dropbear' in ssh_client:
cmd = 'dbclient -y {}'.format(server)
elif 'paramiko' in ssh_client:
cmd = 'python /tmp/paramiko_conn.py {}'.format(server)
try:
client.containers.run(container, command=cmd)
except Exception as e:
errorMsg = str(e)
pass
if ('Permission denied' in errorMsg or 'paramiko.ssh_exception' in errorMsg
or 'dbclient: Connection' in errorMsg):
out = "[+] Command successfully executed!"
else:
out = "[-] Error: {}".format(errorMsg)
# Delete the image
if rm:
client.images.remove(image=container, force=True, noprune=True)
return out
def main():
"""Intake arguments from the user to build docker images and initiate SSH
connections for generating client HASSHs"""
args = parse_cmd_args()
tag_id = 0
tag_name = "hasshgen:{img}{id}"
client = docker.DockerClient(
base_url='unix://var/run/docker.sock',
version='auto')
if args.input_file:
with open(args.input_file) as file:
input_list = json.load(file)
# Run hassh.py
proc = None
if args.fingerprint and not proc:
proc = Popen(args.cmd, shell=True)
time.sleep(1)
for record in input_list:
# Find the Dockerfile
if record['image'] in ('debian', 'ubuntu'):
docker_file = "{}/Dockerfile.debian".format(DOCKERFILE_DIR)
elif record['image'] in ('centos', 'fedora'):
docker_file = "{}/Dockerfile.centos".format(DOCKERFILE_DIR)
else:
docker_file = "{}/Dockerfile.{}".format(
DOCKERFILE_DIR,
record['image'])
# Build the docker images
tag_id += 1
container = tag_name.format(img=record['image'], id=tag_id)
try:
output = client.images.build(
path='.',
dockerfile=docker_file,
tag=container,
nocache=True,
rm=True,
forcerm=True,
buildargs={"IMAGE": record['image'],
"IMAGE_VER": record['image_ver'],
"SSHCLIENT": record['sshclient'],
"SSHCLIENT_VER": record['sshclient_ver']})
# Docker image successfully built
print("[+]", output[0], "successfully built")
print(" - image: {}:{}, ssh client: {} {}".format(
record['image'], record['image_ver'], record['sshclient'],
record['sshclient_ver']))
# Run the container and exec SSH command
out = command_exec(
container, args.server, record['sshclient'], rm=False)
if out:
print(out)
except Exception as e:
print("[-] Error:", e)
# One more command_exec to make sure all captured (bug)
command_exec(container, args.server, record['sshclient'], rm=True)
# Kill hassh.py
if proc:
proc.kill()
elif (args.image and args.image_ver and args.sshclient_ver
and args.sshclient):
container = tag_name.format(img=args.image, id=tag_id)
try:
output = client.images.build(
path='.',
dockerfile=args.docker_file,
tag=container,
nocache=True,
rm=True,
forcerm=True,
buildargs={"IMAGE": args.image,
"IMAGE_VER": args.image_ver,
"SSHCLIENT": args.sshclient,
"SSHCLIENT_VER": args.sshclient_ver})
# Docker image successfully built
print("[+]", output[0], "successfully built")
print(" - image: {}:{}, ssh client: {} {}".format(
args.image, args.image_ver, args.sshclient, args.sshclient_ver))
# Run hassh.py
proc = None
if args.fingerprint and not proc:
proc = Popen(args.cmd, shell=True)
# Run the container and exec SSH command
time.sleep(1)
out = command_exec(
container, args.server, args.sshclient, rm=False)
time.sleep(1)
# One more command_exec to make sure all captured (bug)
out = command_exec(
container, args.server, args.sshclient, rm=True)
time.sleep(1)
if out:
print(out)
# Kill hassh.py
if proc:
proc.kill()
except Exception as e:
print("[-] Error:", e)
if __name__ == '__main__':
main()