Skip to content
This repository has been archived by the owner on Jan 29, 2020. It is now read-only.

IronPython Support [WIP] #1250

Open
wants to merge 8 commits into
base: dev
Choose a base branch
from
Open

Conversation

ihamburglar
Copy link
Contributor

@ihamburglar ihamburglar commented Oct 11, 2018

So I hope I have done something interesting and potentially useful. This is an initial PR to solicit feedback and we can potentially build on it from there. This PR would bring the capability to run python stagers on Windows hosts using nimble executables just a few kilobytes in size(demo), allowing for a full bypass of PowerShell protections while still being able to write dynamic .Net aware code. The flavor of Python that I have chosen for this is IronPython, a former MS project that hooks python up to the .Net CLR. What this means is that you can choose to write Python code very similar or in some cases identical to CPython or write Python code very similar to other .Net languages like PowerShell or C#.

The architecture that I have built hosts everything needed for the IronPython environment on the listener and the stager downloads these resources over http(s). The executables pull down the necessary .Net assemblies, which are not included in this PR but are slotted in place by install.sh, the executing file then loads the assemblies directly into memory using a modification to a trick that Jeffrey Richter developed. Costura, just to give you an example of this, is a C# assembly packing tool that uses this technique to bundle the assemblies as resources within the exe, I adapted this approach to load the assemblies over http(s) from the listener instead.

The next step is setting up the standard library, which is again slotted in by install.sh. This also is served by the listener and each library and dependency is downloaded on the fly by the httpimport.py file, which is based off of httpimport project by operatorequals. I have heavily modified it for my purposes and to work with IronPython instead of CPython(urllib2 is not available in our constrained environment until after it is loaded). This code definitely has the highest concentration of ugly hacks, but I think they are probably solvable.

This is all done by a C# binary that is the "stager", which basically sets this all up, and wraps the python stager code and at run time executes it.

I have a minidump module not included in this PR currently, but I'd like to get it cleaned up, and I'm really trying to keep the modules from requiring the standard library, so I need to convert some of the code to IronPython's .Net.

There are several steps that need to be done before anyone should use this outside of a test environment. This is barely out of the PoC stages.

  • Testing and better error checking. Testing also needs to happen on the normal python side of things
  • Fix built-in commands. I don't think 'ps' even works, but sysinfo does.
  • Build more modules. Even porting existing PowerShell modules to IronPython.
  • Potentially differentiate the agent/stager code so that it can be written in pure .Net, eliminating the StdLib dependency.
  • Fix .gitignore
  • Other stuff from your feedback.

I welcome your feedback and comments. If you want more info on IronPython take a look at the slides from my recent DerbyCon talk or SILENTTRINITY which was also debuted by @byt3bl33d3r also at DerbyCon.

if platform.python_implementation() == 'IronPython':
from System.Diagnostics import Process
from System import Environment
from System.Security.Principal import WindowsIdentity, WindowsPrincipal, WindowsBuiltInRole
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are IronPython specific imports that enable operating system enumeration via .Net rather than normal *nix style enumeration. This the stager should still do the normal thing on *nix envs.

@app.route('/download/stdlib/<folder>/<filename>')
def send_ipy_sub(folder,filename):
return send_from_directory('../../data/misc/IronPython/Lib/'+folder, filename)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently these do not require a routing packet. I think it makes sense that they should, but it looks like this isn't the only thing on the listener that doesn't require it.


#TODO:
#Dealing with stuff not actually in iPy
if name == "strop" or name == "_hashlib" or name == "nt" or name == "fcntl" or name == "posix" or name == "org" or name == "termios" or name == "msvcrt" or name == "EasyDialogs" or name == "pwd" or name == "grp":
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it isn't obvious what is going on here... sometimes imports have dependencies that they try to import in a try, except block. A normal import system handles this fine, but this custom importer doesn't, so I'm essentially blacklisting modules that can't successfully be imported. If someone has a suggestion for how better to do this let me know.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant