diff --git a/pupy/commands/gen.py b/pupy/commands/gen.py index 2048f868..f5b47828 100644 --- a/pupy/commands/gen.py +++ b/pupy/commands/gen.py @@ -11,7 +11,7 @@ from pupylib.PupyOutput import Info, Warn, Success, Error from pupylib.utils.listener import get_listener_ip, get_listener_port from pupylib.utils.listener import get_listener_ip_with_local -import pupygen +from pupylib.cli import pupygen usage = 'Generate payload' @@ -20,12 +20,14 @@ def parser(server, handler, config): def do(server, handler, config, args): handler.display(Info("Raw user arguments given for generation: {0}".format(str(args.launcher_args)))) + if not args.launcher: handler.display(Info("Launcher/connection method not given. It is set to 'connect' now")) args.launcher = 'connect' + #launcher method 'connect' or 'auto_proxy' if args.launcher and args.launcher in ('connect', 'auto_proxy'): - transport = None #For saving the transport method (default or given by user) + transport = config.get("pupyd", "listen") #For saving the transport method (default or given by user) transport_idx = None host = None #Host for listening point (not for launcher args) port = None #Port for listening point (not for launcher args) diff --git a/pupy/conf/.bashrc b/pupy/conf/.bashrc deleted file mode 100644 index a470fcfa..00000000 --- a/pupy/conf/.bashrc +++ /dev/null @@ -1,22 +0,0 @@ -export PATH=$PATH:/bin:/usr/sbin:~/.local/bin - -alias pupysh=/opt/pupy/pupysh.py -alias pupygen=/opt/pupy/pupygen.py -alias gen=/opt/pupy/pupygen.py - -project=default - -if [ -f /home/pupy/.project ]; then - project=`cat /home/pupy/.project` -fi - -case $- in *i*) - if [ -z "$TMUX" ] && [ ! -z "$SSH_CLIENT" ]; then - echo -ne "\033]0;[ PUPY:${project} ]\007" - ( tmux -2 attach || tmux -2 new-session \ - -c "/projects/${project}" \ - -s pupy \ - -n "${project}" /opt/pupy/pupysh.py ) - [ $? -eq 0 ] && exit 0 - fi -esac diff --git a/pupy/conf/Dockerfile.default b/pupy/conf/Dockerfile.default deleted file mode 100644 index 84196db2..00000000 --- a/pupy/conf/Dockerfile.default +++ /dev/null @@ -1,49 +0,0 @@ -FROM debian:stretch-slim - -LABEL maintainer "alxchk@gmail.com" - -ENV DEBIAN_FRONTEND noninteractive -RUN echo 'deb http://ftp.debian.org/debian stretch-backports main' >>/etc/apt/sources.list && \ - apt-get update && \ - mkdir -p /usr/share/man/man1/ && \ - apt-get install -t stretch-backports --no-install-recommends -y build-essential libssl1.0-dev libffi-dev \ - python-dev python-pip openssh-server tmux sslh libcap2-bin \ - john vim-tiny less osslsigncode nmap net-tools libmagic1 swig cython \ - autoconf automake unzip libtool locales ncurses-term bash tcpdump libpam-cap netbase \ - git fuse && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* /usr/share/doc* /usr/share/man/* /usr/share/info/* -RUN echo 'en_US.UTF-8 UTF-8' >/etc/locale.gen; locale-gen; echo 'LC_ALL=en_US.UTF-8' >/etc/default/locale -RUN useradd -m -d /home/pupy -s /bin/bash pupy -RUN mkdir -p /var/run/sshd /home/pupy/.config/pupy /home/pupy/.ssh /projects -RUN ln -sf /projects/keys/authorized_keys /home/pupy/.ssh/authorized_keys - -COPY conf/pupy.conf.docker /home/pupy/.config/pupy/pupy.conf -COPY conf/.bashrc /home/pupy/.bashrc.pupy -COPY conf/capability.conf /etc/security/capability.conf - -RUN chmod +s /usr/sbin/tcpdump -RUN chown pupy:pupy -R /home/pupy; chmod 700 /home/pupy/.ssh -RUN echo 'source /home/pupy/.bashrc.pupy' >> /home/pupy/.bashrc - -RUN python -m pip install --upgrade pip six setuptools wheel - -COPY . /opt/pupy -RUN cd /opt/pupy && pip install --upgrade -r requirements.txt - -ADD https://github.com/gentilkiwi/mimikatz/releases/download/2.2.0-20200519/mimikatz_trunk.zip \ - /opt/mimikatz/mimikatz.zip -RUN cd /opt/mimikatz && unzip mimikatz.zip && rm -f mimikatz.zip -RUN mkdir /opt/uacme -RUN apt-get remove -y autoconf automake python-dev libtool build-essential && \ - apt-get -y autoremove && rm -rf /root/.cache/pip && \ - rm -f /etc/ssh/ssh_host_*; rm -f /tmp/requirements.txt - -ENV LANG en_US.UTF-8 -ENV LC_ALL en_US.UTF-8 - -EXPOSE 22 1080 5454 5454/udp 8080 -VOLUME [ "/projects" ] - -ENTRYPOINT [ "/opt/pupy/conf/pupyenv.sh" ] -CMD [ "default" ] diff --git a/pupy/conf/Dockerfile.env b/pupy/conf/Dockerfile.env deleted file mode 100644 index 3cfdab6f..00000000 --- a/pupy/conf/Dockerfile.env +++ /dev/null @@ -1,46 +0,0 @@ -FROM debian:buster-slim - -LABEL maintainer "alxchk@gmail.com" - -ENV DEBIAN_FRONTEND noninteractive - -RUN \ - echo 'deb http://ftp.debian.org/debian buster-backports main' >> \ - /etc/apt/sources.list && \ - apt-get update --fix-missing && \ - mkdir -p /usr/share/man/man1/ && \ - apt-get install -t buster-backports --no-install-recommends -y \ - libssl-dev libffi-dev python-dev python-pip swig \ - unzip libtool locales ncurses-term tcpdump \ - netbase fuse build-essential cython && apt-get clean && \ - rm -rf /var/lib/apt/lists/* /usr/share/doc* /usr/share/man/* /usr/share/info/* && \ - echo 'en_US.UTF-8 UTF-8' >/etc/locale.gen && \ - locale-gen && echo 'LC_ALL=en_US.UTF-8' >/etc/default/locale - -RUN \ - mkdir -p /project && \ - mkdir -p /pupy && \ - mkdir -p /build - -COPY requirements.txt /build/ -COPY external/pykcp /build/external/pykcp - -RUN \ - python -m pip install --no-cache-dir --upgrade pip six setuptools wheel && \ - cd /build && \ - python -m pip install --no-cache-dir --upgrade -r requirements.txt - -RUN \ - apt-get remove -y \ - autoconf automake libssl1.0-dev libffi-dev python-dev \ - libtool build-essential && apt-get -y autoremove && \ - rm -rf /root/.cache /build - -ADD \ - https://github.com/gentilkiwi/mimikatz/releases/download/2.2.0-20200519/mimikatz_trunk.zip \ - /opt/mimikatz - -ENV LANG en_US.UTF-8 -ENV LC_ALL en_US.UTF-8 - -ENTRYPOINT [ "python", "-OB", "/pupy/pupysh.py", "--workdir", "/project" ] diff --git a/pupy/conf/capability.conf b/pupy/conf/capability.conf deleted file mode 100644 index 2cd59838..00000000 --- a/pupy/conf/capability.conf +++ /dev/null @@ -1,2 +0,0 @@ -cap_net_broadcast,cap_net_raw,cap_net_bind_service,cap_net_admin pupy -none * diff --git a/pupy/conf/pupy.conf.docker b/pupy/conf/pupy.conf.docker deleted file mode 100644 index 264da145..00000000 --- a/pupy/conf/pupy.conf.docker +++ /dev/null @@ -1,67 +0,0 @@ -[pupyd] -transport = ec4 -port = 8080 -ipv6 = false -igd = false -httpd = false -webserver = true -dnscnc = localhost:5454 -use_gnome_keyring = false -allow_requests_to_external_services = false - -[cmdline] -display_banner = yes -colors = yes - -[httpd] -secret = true - -[paths] -prefer_workdir = yes -downloads = data/downloads/%c -memstrings = data/memstrings/%c -searches = data/searches/%c -screenshots = data/screenshots/%c/%t -pcaps = data/pcaps/%c/%t.pcap -logs = data/logs/%c/%t-%M -creds = data/creds -crypto = crypto -wwwroot = data/wwwroot -webstatic = webstatic -records = data/%c -keystrokes = data/keylogger/%c/%t.log -mouseshots = data/mouselogger/%c/%w-%t.png -payload_output = output -plugins = data/plugindata -ad = data/ad/%c/%r/%n.json - -[on_connect] -#run_module = gather/keylogger start - -[default_viewers] -image_viewer = eog -sound_player = totem - -[mimikatz] -exe_Win32=/opt/mimikatz/Win32/mimikatz.exe -exe_x64=/opt/mimikatz/x64/mimikatz.exe - -[aliases] -info = get_info -pyexec = pyexec -exec = shell_exec -shell = interactive_shell -kill = process_kill -mount = drives - -[listeners] -ssl = 443=8443 -obfs3 = 9090 -rsa = 9091 -ec4 = 80=1234 -kc4 = 123=1234 -tcp_cleartext = 80=1234 -udp_cleartext = 123=1234 -websocket = 80=8081 -http = 80=8080 -ecm = 1235 diff --git a/pupy/conf/pupyenv.sh b/pupy/conf/pupyenv.sh deleted file mode 100755 index 1256d99e..00000000 --- a/pupy/conf/pupyenv.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/sh - -mkdir -p /projects/keys -mkdir -p /projects/hostkeys - -chown root /projects/hostkeys -chmod 700 /projects/hostkeys - -chown pupy /projects/keys -chmod 700 /projects/keys - -if [ ! -f /projects/hostkeys/ssh_host_rsa_key ]; then - ssh-keygen -f /projects/hostkeys/ssh_host_rsa_key -N '' -t rsa -fi - -if [ ! -f /projects/hostkeys/ssh_host_dsa_key ]; then - ssh-keygen -f /projects/hostkeys/ssh_host_dsa_key -N '' -t dsa -fi - -if [ ! -f /projects/hostkeys/ssh_host_ecdsa_key ]; then - ssh-keygen -f /projects/hostkeys/ssh_host_ecdsa_key -N '' -t ecdsa -fi - -if [ ! -f /projects/hostkeys/ssh_host_ed25519_key ]; then - ssh-keygen -f /projects/hostkeys/ssh_host_ed25519_key -N '' -t ed25519 -fi - -for k in /projects/hostkeys/*; do - cp -af $k /etc/ssh/ -done - -if [ ! -d "/projects/$1" ]; then - mkdir -p "/projects/$1" - chown pupy "/projects/$1" -fi - -/sbin/setcap cap_net_broadcast,cap_net_raw,cap_net_bind_service+eip /usr/bin/python2.7 -/usr/bin/python2.7 --version >/dev/null 2>/dev/null -if [ ! $? -eq 0 ]; then - echo "[!] Xattrs not supported" - echo "[!] You can start container with --priviliged option" - /sbin/setcap -r /usr/bin/python2.7 -fi - -echo "$1" >/home/pupy/.project - -cd /opt/pupy - -find -type f -exec md5sum {} ';' >/projects/integrity.txt - -echo 'Copy your authorized_keys here!' >/projects/keys/README - -cat >>/projects/README <<__EOF__ -SSH user: pupy -Port: 22 - -cp ~/.ssh/authorized_keys /projects/keys/authorized_keys - -Example: - -mkdir /tmp/projects/keys -cp ~/.ssh/authorized_keys /projects/keys/authorized_keys -docker run -D -p 2022:22 -p 9999:9999 -v /tmp/projects:/projects pupy:latest -ssh -p 2022 pupy@127.0.0.1 -__EOF__ - -/usr/sbin/sshd -D diff --git a/pupy/conf/pupysh.sh b/pupy/conf/pupysh.sh deleted file mode 100755 index 0b948e08..00000000 --- a/pupy/conf/pupysh.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -if [ ! -f /project/config/pupy.conf ]; then - echo "[+] Copy default configuration to config/pupy.conf" - mkdir -p /project/config/ - cp -f /opt/pupy/conf/pupy.conf.docker /project/config/pupy.conf -fi - -for dir in data crypto output; do - if [ ! -d /project/$dir ]; then - mkdir /project/$dir - fi -done - -cd /project - -exec /opt/pupy/pupysh.py diff --git a/pupy/external/pykcp b/pupy/external/pykcp index fdca1d59..ce9dff06 160000 --- a/pupy/external/pykcp +++ b/pupy/external/pykcp @@ -1 +1 @@ -Subproject commit fdca1d59f7a31540f30ca851b3d19156d29eef1c +Subproject commit ce9dff065b9e0c0eb942b1809c4fb48dbcc6f29c diff --git a/pupy/modules/duplicate.py b/pupy/modules/duplicate.py index 951c36c1..c5d47890 100644 --- a/pupy/modules/duplicate.py +++ b/pupy/modules/duplicate.py @@ -12,7 +12,7 @@ from pupylib.PupyModule import config, PupyModule, PupyArgumentParser from modules.lib.windows.memory_exec import exec_pe from modules.lib.linux.exec_elf import mexec -import pupygen +from pupylib.cli import pupygen __class_name__ = 'MemoryDuplicate' diff --git a/pupy/modules/lib/linux/migrate.py b/pupy/modules/lib/linux/migrate.py index b46ac4f2..a7e6301b 100644 --- a/pupy/modules/lib/linux/migrate.py +++ b/pupy/modules/lib/linux/migrate.py @@ -3,7 +3,7 @@ from __future__ import division from __future__ import print_function from __future__ import unicode_literals -import pupygen +from pupylib.cli import pupygen import time import gzip diff --git a/pupy/modules/lib/windows/migrate.py b/pupy/modules/lib/windows/migrate.py index 176b8a56..ab8154df 100644 --- a/pupy/modules/lib/windows/migrate.py +++ b/pupy/modules/lib/windows/migrate.py @@ -8,7 +8,7 @@ from __future__ import unicode_literals import sys import time -import pupygen +from pupylib.cli import pupygen from pupylib.payloads.dependencies import Target diff --git a/pupy/modules/lib/windows/powerloader.py b/pupy/modules/lib/windows/powerloader.py index 0afd926e..5b3e9eff 100644 --- a/pupy/modules/lib/windows/powerloader.py +++ b/pupy/modules/lib/windows/powerloader.py @@ -13,7 +13,7 @@ from io import open from os import unlink from threading import Event -from pupygen import generate_binary_from_template +from pupylib.cli.pupygen import generate_binary_from_template from pupylib.payloads.dotnet import DotNetPayload DEFAULT_TIMEOUT = 90 diff --git a/pupy/modules/persistence.py b/pupy/modules/persistence.py index 96a1478e..b32d3e28 100644 --- a/pupy/modules/persistence.py +++ b/pupy/modules/persistence.py @@ -26,7 +26,7 @@ from __future__ import print_function from __future__ import unicode_literals from pupylib.PupyModule import config, PupyModule, PupyArgumentParser from pupylib.PupyCompleter import remote_path_completer -import pupygen +from pupylib.cli import pupygen __class_name__ = "Persistence" diff --git a/pupy/pupy.conf.default b/pupy/pupy.conf.default index c86aa815..f2e4e26f 100644 --- a/pupy/pupy.conf.default +++ b/pupy/pupy.conf.default @@ -68,7 +68,7 @@ allow_by_default = true # Default ports and args # Ensure ports are different for all enabled listeners # Or remove listener(s) from pupyd.listen parameter -ssl = 443 +ssl = 443=8443 obfs3 = 9090 rsa = 9091 ec4 = 80=1234 diff --git a/pupy/pupylib/PupyConfig.py b/pupy/pupylib/PupyConfig.py index 4836af9d..b948b56c 100644 --- a/pupy/pupylib/PupyConfig.py +++ b/pupy/pupylib/PupyConfig.py @@ -29,12 +29,15 @@ import random import string import datetime import errno +import shutil +import os from network.lib.convcompat import ( as_unicode_string, as_native_string ) from .PupyLogger import getLogger +from pupylib import ROOT logger = getLogger('config') if sys.version_info.major > 2: @@ -100,16 +103,17 @@ class Tags(object): class PupyConfig(RawConfigParser): def __init__(self, config='pupy.conf'): - self.root = path.abspath(path.join(path.dirname(__file__), '..')) + self.root = path.abspath(ROOT) self.user_root = path.expanduser(path.join('~', '.config', 'pupy')) - self.project_path = path.join('config', config) + self.default_file = path.join(self.root, config+'.default') self.user_path = path.join(self.user_root, config) + if not os.path.exists(self.user_path): + shutil.copyfile(self.default_file, self.user_path) + logger.info("No default pupy config file, creating one in {}".format(self.user_path)) + self.files = [ - path.join(self.root, config+'.default'), - path.join(self.root, config), - self.user_path, - self.project_path, - config + self.default_file, + self.user_path ] self.randoms = {} self.command_line = {} @@ -121,7 +125,7 @@ class PupyConfig(RawConfigParser): self.read_file(open(file, 'r')) logger.info( - 'Loaded config data from %s', self.files + 'Loaded config data from %s', file ) except (IOError, OSError) as e: if e.errno == errno.EEXIST: diff --git a/pupy/pupylib/PupyServer.py b/pupy/pupylib/PupyServer.py index 450e4418..a846a7ba 100644 --- a/pupy/pupylib/PupyServer.py +++ b/pupy/pupylib/PupyServer.py @@ -1234,6 +1234,7 @@ class PupyServer(object): if error: del self.listeners[name] + self.handler.display_error(error) self.display(message, error, motd) diff --git a/pupy/pupylib/__init__.py b/pupy/pupylib/__init__.py index aaa05367..38e1bf15 100644 --- a/pupy/pupylib/__init__.py +++ b/pupy/pupylib/__init__.py @@ -11,12 +11,39 @@ __all__ = [ import os import sys import platform +import re ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) HOST_SYSTEM = platform.system() HOST_CPU_ARCH = platform.architecture()[0] HOST_OS_ARCH = platform.machine() +USE_PIPX = False +# hotpatch for pipx installs. TODO: do this a cleaner way +if "/pipx/venv" in ROOT: + res = re.findall("(.*/pipx/venvs/[^/]+)", ROOT) + if len(res) == 1: + ROOT = os.path.join(res[0], "data") + USE_PIPX = True + +if USE_PIPX: + LIBDIR = os.path.join(ROOT, "pupy") +else: + LIBDIR = ROOT + +DEPS = [ + os.path.abspath(os.path.join(LIBDIR, 'library_patches_py3')), + os.path.abspath(os.path.join(LIBDIR, 'packages', 'all')), + ] + +for dep in DEPS: + if not os.path.exists(dep): + raise Exception("Dependency path not found : {}".format(dep)) + if "library_patches" in dep: + sys.path.insert(0, dep) + else: + sys.path.append(dep) + # dirty, TODO: refactor PupyCompiler to be able to call it standalone if not getattr(sys, '__from_build_library_zip_compiler__', False): from .PupyLogger import getLogger diff --git a/pupy/pupylib/cli/__init__.py b/pupy/pupylib/cli/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pupy/pupygen.py b/pupy/pupylib/cli/pupygen.py similarity index 99% rename from pupy/pupygen.py rename to pupy/pupylib/cli/pupygen.py index 72418ee4..bbd166fb 100755 --- a/pupy/pupygen.py +++ b/pupy/pupylib/cli/pupygen.py @@ -21,12 +21,6 @@ import tempfile import shutil import subprocess -if __name__ == '__main__': - sys.path.insert(0, os.path.join( - os.path.abspath(os.path.join(os.path.dirname(__file__))), - 'library_patches' - )) - import marshal import base64 import os @@ -62,7 +56,7 @@ from pupylib.PupyCredentials import Credentials, EncryptionError logger = getLogger('gen') HARDCODED_CONF_SIZE = 500000 -ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__))) +from pupylib import ROOT if sys.version_info.major > 2: unicode = str @@ -777,6 +771,7 @@ def pupygen(args, config, pupsrv, display): scriptlets = load_scriptlets(args.os, args.arch) if args.list: + print("ok") display(MultiPart([ Table( [{ diff --git a/pupy/pupysh.py b/pupy/pupylib/cli/pupysh.py similarity index 95% rename from pupy/pupysh.py rename to pupy/pupylib/cli/pupysh.py index fac2fe6c..832c14c5 100755 --- a/pupy/pupysh.py +++ b/pupy/pupylib/cli/pupysh.py @@ -45,12 +45,7 @@ import argparse args = None - -if __name__ == '__main__': - ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__))) - sys.path.insert(0, os.path.join(ROOT, 'library_patches_py3')) - sys.path.append(os.path.join(ROOT, 'packages', 'all')) - +def parse_args(): parser = argparse.ArgumentParser(prog='pupysh', description="Pupy console") parser.add_argument( '--loglevel', '-d', @@ -72,8 +67,21 @@ if __name__ == '__main__': help='Do not encrypt configuration', action='store_true') parser.add_argument('--sound', dest='sounds', help='Play a sound when a session connects', action='store_true') - args = parser.parse_args() + return parser +try: + import pupylib.PupySignalHandler + assert pupylib.PupySignalHandler +except ImportError: + pass + +from pupylib import ( + PupyServer, PupyCmdLoop, PupyCredentials, PupyConfig +) + +def main(): + parser = parse_args() + args = parser.parse_args() if args.workdir: os.chdir(args.workdir) @@ -99,18 +107,6 @@ if __name__ == '__main__': root_logger.addHandler(logging_stream) root_logger.setLevel(args.loglevel) - -try: - import pupylib.PupySignalHandler - assert pupylib.PupySignalHandler -except ImportError: - pass - -from pupylib import ( - PupyServer, PupyCmdLoop, PupyCredentials, PupyConfig -) - -if __name__ == "__main__": PupyCredentials.DEFAULT_ROLE = 'CONTROL' if args.not_encrypt: PupyCredentials.ENCRYPTOR = None @@ -143,3 +139,5 @@ if __name__ == "__main__": pupyServer.stop() pupyServer.finished.wait() +if __name__ == "__main__": + main() diff --git a/pupy/pupylib/payloads/ps1_oneliner.py b/pupy/pupylib/payloads/ps1_oneliner.py index c318f1e2..ab1d82b7 100644 --- a/pupy/pupylib/payloads/ps1_oneliner.py +++ b/pupy/pupylib/payloads/ps1_oneliner.py @@ -9,7 +9,7 @@ from base64 import b64encode from time import sleep import sys -import pupygen +from pupylib.cli import pupygen import socket import errno diff --git a/pupy/requirements.txt b/requirements.txt similarity index 57% rename from pupy/requirements.txt rename to requirements.txt index d87e873d..816e44eb 100644 --- a/pupy/requirements.txt +++ b/requirements.txt @@ -5,7 +5,7 @@ rsa netaddr ecdsa==0.13 paramiko==2.0.2 -https://github.com/alxchk/tinyec/archive/master.zip +tinyec @ https://github.com/alxchk/tinyec/archive/master.zip psutil netifaces pylzma @@ -19,8 +19,8 @@ http-parser cerberus logutils secretstorage==2.3.1 -https://github.com/AlessandroZ/pypykatz/archive/master.zip -https://github.com/warner/python-ed25519/archive/master.zip +pypykatz @ https://github.com/AlessandroZ/pypykatz/archive/master.zip +ed25519==1.5 pygments requests tornado @@ -40,10 +40,10 @@ xattr dukpy pyaes chardet -https://github.com/alxchk/urllib-auth/archive/master.zip +urllib-auth @ https://github.com/alxchk/urllib-auth/archive/master.zip http_request --e external/pykcp +kcp @ git+https://github.com/n1nj4sec/pykcp flake8 flake8-per-file-ignores ushlex; python_version<'3' -git+https://github.com/n1nj4sec/pyuv@fix-building-against-python311 +pyuv @ git+https://github.com/n1nj4sec/pyuv@fix-building-against-python311 diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..999b3544 --- /dev/null +++ b/setup.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +# -*- coding: UTF8 -*- + +from setuptools import setup, find_packages +import os +import sys + +requirements = [x.strip() for x in open("requirements.txt", "r").readlines()] +#requirements = [f"{line.split('#egg=')[-1]} @ {line}" if "#egg=" in line else line for line in requirements] + +def generate_data_files(): + data_files = [("data", ["pupy/pupy.conf.default"])] + data_dirs = ('pupy/library_patches_py3', 'pupy/library_patches_py2', 'pupy/packages') + for data_dir in data_dirs: + for path, dirs, files in os.walk(data_dir): + if "__pycache__" in path: + continue + install_dir = os.path.join("data", path) + list_entry = (install_dir, [os.path.join(path, f) for f in files if not f.startswith('.')]) + data_files.append(list_entry) + return data_files + +setup( + name='pupy', + version='3.0.0', + packages=find_packages(where='pupy', include=['pupy*', 'pupylib*', 'network*', 'commands*', 'modules*', 'scriptlets*', 'triggers*']), + package_dir={"": "pupy"}, + data_files=generate_data_files(), + license_files = ('LICENSE'), + author='n1nj4sec', + author_email='contact@n1nj4.eu', + description='Pupy C2 is an opensource, cross-platform (Windows, Linux, OSX, Android) remote administration and post-exploitation tool in python', + #long_description='Pupy C2 Framework', + #long_description_content_type='text/x-rst', + url='https://github.com/n1nj4sec/pupy', + keywords=["python", "pentest", "cybersecurity", "redteam", "C2", "command and control", "post-exploitation"], + entry_points={ + 'console_scripts': [ + 'pupysh = pupylib.cli.pupysh:main' + ] + }, + install_requires=requirements +)