DEP and Pyinstaller

Previously, on our first V-Day payload release, we described using void pointer casting as a method to invoke shellcode. We also noted that when using this method, you may run into some problems with DEP enforcing systems as we memory location in memory is not explicitly marked as RWX. As most systems tend to default to an opt-in DEP enforcement policy, if the executable you’re running opts-in to this protection, this method will fail with an access violation.

We were recently investigating a weird quirk with these types of payloads: python void pointer payloads (currently) work when being run as a manual python .py file, but fail when packaged into an executable with Pyinstaller. We determined that while the python.exe interpreter used and packaged with the Pyinstaller binary is not DEP enabled, the resulting Pyinstaller payloads do in fact opt in to this protection. If you’re interested, you can check/confirm this using the GetProcessDEPPolicy system call.

So the next step was to determine how to convince Pyinstaller to generate executables that don’t opt into DEP protection. Pyinstaller binaries are conceptually somewhat simple: the python interpreter and necessary libraries are packaged together with the target script into a CArchive, and packed onto the end of a small loader executable. The Pyinstaller website concisely describes a CArchive as, “Very much like a .zip file. They are easy to create in Python and unpack from C code. CArchives can be appended to other files (like ELF and COFF executables, for example).” Pyinstaller holds precompiled copies of 32-bit and 64-bit loaders for Linux, OSX and Windows in ./pyinstaller-2.0/support/loader/* , then dynamically builds the CArchive structure and attaches it to the appropriate loader. When the resulting executable runs, the loader extracts the python environment and script from the CArchive, and uses the interpreter to run the packaged script.

These loader executables are what what were throwing us for a loop: all the windows loaders included with the project are compiled with DEP protection enabled. Luckily, the source for the loaders are included with the project in ./pyinstaller-2.0/source/* , and if you have Visual Studio installed on a Windows box, the binaries can easily be recompiled in a way to fit out needs.

The binaries utilize the WAF build system to build the loaders. Open up .\pyinstaller-2.0\source\wscript , and add conf.env.append_value(‘LINKFLAGS’, ‘/NXCOMPAT:NO’) right after the other flags on lines 209 and 211 (as seen on line 210 and 213 below). This will instruct the Visual Studio linker to turn off DEP compatibility:

 

wscript_dep

Then run

C:\pyinstaller-2.0\source\> python waf configure
C:\pyinstaller-2.0\source\> python waf 

to configure the build system to your environment and build all the loader executables. For our purposes, the only binary you need is  .\pyinstaller-2.0\source\build\releasew\runw.exe – copy this into the pyinstaller-2.0/support/loader/Windows-32bit/ install location used by Veil (found under PYINSTALLER_PATH in /etc/veil/settings.py).

Pyinstaller generated executables should now opt out of DEP protection, enabling you to use void pointer shellcode invocation on a much larger number of machines.