Python Environments

INTRODUCTION

Background: Why write this?

The short answer is: I often forget how to do this, and I wanted a quick, no-B.S. reference for recreating a functional Python environment for hacking.

I know I’m not alone in believing that Python is the best tool for the job when you need something done quick and dirty. It’s great for writing proof-of-concept scripts, but also excels at console-based applications. If you’ve read enough of my walkthroughs, you’ll know that Python is my go-to language for automating all kinds of attacks, ranging from web to cryptography.

python-in-python

The problem with Python:

Python’s long-standing popularity in the infosec community is both it’s greatest strength and greatest weakness: You will often be required to use tools written in Python up to 20 years old. Very often, older tools will be written in Python 2.7, completely incompatible with a modern Python environment. As a hacker, you need to be comfortable in an environment simultaneously running Python 2.7 and Python 3.X.

To exacerbate this issue, the Python ecosystem handles code dependencies in way that often feels inadequate (although, to it’s credit, it’s a really easy-to-use). Over the years, Python has brandished a variety of solutions for package management: Often you’ll see code that uses an egg or a wheel and just shrug it off.

All of these factors come together to create the perfect storm of cluttering-up your system with incompatible libraries and tools. It might not happen right away, but eventually this will come back to bite you.

Mixing 2.7 and 3.X

Getting Python 2.7 to work properly

This guide assumes you are running a recent version of Kali linux.

Start by installing the latest version of Python 3 and Pip, if you haven’t already done so. In many cases, this will break your Python 2 environment. The following steps will allow you to set up a hybrid environment where both work without interfering with one another.

Follow the steps outlined in this guide, written for Kali: https://www.kali.org/docs/general-use/using-eol-python-versions/

pyenv should now be installed and set global to Python 2.7.18.

Next, reinstall pip aka pip2 using the particular EOL repo:

curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python get-pip.py

At this point, your system may be complaining about the location of pip/pip2/pip2.7 not being on the path. Add it to your zshrc or bashrc:

echo 'export PATH="/home/kali/.local/bin":$PATH"' >> ~/.zshrc

pip2 requires setuptools for all subsequent package installations. Go get it:

pip2 install --upgrade setuptools

Now, to test things out, try installing a package:

pip2 install termcolor # Success!

You should now have a fully-functional Python 2 + Pip environment. At any time, you can check what versions you have available by running pyenv versions. Then, you can globally enable a certain version, ex. pyenv global 2.7.18.

🚨 Remember to use pyenv global system to toggle back to the system python version (probably Python 3.9 or later)

Using a venv

What you require

If you’re like me, you frequently clone a repo from Github containing a Python program, and lack the dependencies to run it. Ideally, those dependencies will be written into a requirements file, but sometimes not. When there is no requirements file, often the easiest (not the fastest!) way to resolve the dependencies is like this:

  1. Run the program, seeing what dependency it complains about. If it actually runs, skip the rest of the steps.
  2. pip3 install whatever dependency it’s complaining about.
  3. Repeat step 1.

That’s all fine, but it will definitely clutter up your system with incompatible nonsense. To mitigate this, use a venv.

Yes, you can use pyenv to do this too, but the following method works even without pyenv, so it’s more general.

Applying a venv

As an example, I’ll use one of my repos, congenial-winner. It consists of a single python script, with dependencies but no requirements file:

git clone https://github.com/4wayhandshake/congenial-winner.git
cd congenial-winner
# Establish a venv inside this directory
python3 -m venv .  # There are now directories: bin, include, lib, lib64
# Activate the venv, 
source bin/activate

congenial-winner-example-1

Note that sourcing bin/activate has placed the directory-local version of python (and pip) at the start of your $PATH.

# Install dependencies
pip3 install subprocess itertools argparse
# Try running it
./known-plaintext.py

congenial-winner-example-2

Success! All dependencies are installed to the environment within this directory. When you’re done playing around with the code from that repo, you can simply delete the whole directory from your system with no consequences.

🚨 To deactivate your venv and return to your regular user- or system-installed python environment, simply run deactivate, which will be on your $PATH as long as you activated the venv:

deactivate

Pyenv

Setup

There is a wonderful tool called pyenv that can do both of the above tasks quite well. It allows you to install multiple versions of python without them interfering. Not only that, but you can install arbitrary versions of Python and use them in virtual environments.

Installation of pyenv is outside the scope of this article. Just google it if you need help.

First, install the version you want to use. For example:

pyenv install 3.6.1

To use the version, just set it to either the shell-, local-, or system-level python version and pyenv exec something:

local environment pyenv

Virtual environments

To create a named virtual environment, just give it any name that makes sense to you:

pyenv virtualenv 3.6.1 my-python3.6-env

This effectively adds a new, virtual installation of python using the specific version. It’s not particular to this directory, it’s effectively a separate system installation of that particular python version. To make it act like venv, change to the directory you want to use it in, and set it as the local python version:

cd project/using-old-python
pyenv local my-python3.6-env

Just like using a venv, you need to activate and deactivate the virtual environment:

# activate the environment
pyenv activate my-python3.6-env
# do some stuff using that version:
pyenv exec python3 ./janky_python3.6_script.py
# deactivate it when you're done
pyenv deactivate

CONCLUSION

You can isolate your individual projects/repos by using venv, and separate your various python versions from each other by using pyenv. Using a combination of the two, you can keep your system clean and (hopefully) free of conflicting package versions. With a little effort into setup, you can combine these two ideas using pyenv. Taking these steps will mitigate all the unfortunate nuances of Python dependency management. With any luck, you’ll be able to proceed for with your hacking for years to come, in blissful ignorance of conflicting packages and Python versions.

For more detail, please see the official Python guide for using venv with pip.


Thanks for reading

🤝🤝🤝🤝
@4wayhandshake