FAIL: Attempted Pickle Exploitation
This weeks exploitation demonstrates how to gain code execution if you have control over a string using Pickle. Pickling is the process of converting a Python object hierarchy into a byte stream to be written to a file. This process is known as sterilization. The converse process, known as Unpickling, turns the byte stream back into a Python object. Pickle has the ability to both store and reproduce dictionaries, lists, and references to other objects. Additionally, it stores object attributes and restores them back into the same state.
What is sterilization? According to one site, “Serialization is a mechanism to convert an object into stream of bytes so that it can be written into a file, transported through a network or stored into database” (https://beginnersbook.com/2014/07/java-serialization/). Simply stated, sterilization is used by application to make their storage easier.
According to Python’s documentation, The following types can be pickled (https://docs.python.org/3/library/pickle.html):
- None, True, and False
- integers, floating point numbers, complex numbers
- strings, bytes, bytearrays
- tuples, lists, sets, and dictionaries containing only picklable objects
- built-in functions defined at the top level of a module
- classes that are defined at the top level of a module
Step 1: Register as a new user. I used the username test
Step 2: Take the cookie session found in the response section of the HTTP history of the proxy and send it to the decoder.
Step 3: Decode the first portion of the header as Base64. Do the same with the second. These results show that this data is sanitized.
Step 4: Change the username parameter from test to admin.
Step 5: Encode the modified username into Base64.
Step 6: Go back to the proxy and send the successful login entry to the repeater.
Step 7: Replace the original header section in the session cookie with the new encoded header for the admin username. Click Go.
Step 8: The response returned shows that the session has been terminated.
Step 9: Go back to the browser and login once again with username test. This time, I checked the Remember me option.
Step 10: This time, you will see there are now two cookies. Once for the session, and one for the enabled remember me option. Highlight the remember me cookie and send it to the decoder.
Step 11: Decode the remember me cookie as Base64. The results are shown below and it shows that the data has been pickled as it is consistent with the pickled data format scheme.
The remember me functionality is much more susceptible to an attack. From this point, I decided that instead of passing the pickled object seen above, I built my own object, pickle it, Base64 encode it, and finally, pass it to the server.
Step 12: Create a new pickled object by opening a terminal and creating a simple Python object called pickle.py
Step 13: Write the script. (More information about the specifics of the program below).
import cPickle: The cPickle module supports serialization and de-serialization of Python objects, providing an interface and functionality nearly identical to the pickle module. There are several differences, the most important being performance and subclassability. First, cPickle can be up to 1000 times faster than pickle because the former is implemented in C. Second, in the cPickle module the callables Pickler() and Unpickler() are functions, not classes. This means that you cannot use them to derive custom pickling and unpickling subclasses. Most applications have no need for this functionality and should benefit from the greatly improved performance of the cPickle module (https://docs.python.org/2.3/lib/module-cPickle.html).
import os: The OS module in Python provides a way of using operating system dependent functionality. The functions that the OS module provides allows you to interface with the underlying operating system that Python is running on – be that Windows, Mac or
Linux. The os.system function is for executing a shell command, which is called later in the program. (http://www.pythonforbeginners.com/os/pythons-os-module).
import base64: This module provides data encoding and decoding as specified in RFC 3548. This standard defines the Base16, Base32, and Base64 algorithms for encoding and decoding arbitrary binary strings into text strings that can be safely sent by email, used as parts of URLs, or included as part of an HTTP POST request. The encoding algorithm is not the same as the uuencode program (https://docs.python.org/2/library/base64.html).
class pickledObject(object): Classes provide a means of bundling data and functionality together. Creating a new class creates a new type of object, allowing new instances of that type to be made. Each class instance can have attributes attached to it for maintaining its state. Class instances can also have methods (defined by its class) for modifying its state (https://docs.python.org/3/tutorial/classes.html). In this case, I created a new object called pickledObject and takes one argument object.
Def _reduce_(self): When the Pickler encounters an object of a type it knows nothing about — such as an extension type — it looks in two places for a hint of how to pickle it. One alternative is for the object to implement a __reduce__() method. If provided, at pickling time __reduce__() will be called with no arguments, and it must return either a string or a tuple. If a string is returned, it names a global variable whose contents are pickled as normal. The string returned by __reduce__() should be the object’s local name relative to its module; the pickle module searches the module namespace to determine the object’s module (http://docs.aakashlabs.org//apl/pyhelp/pydocs/library/pickle.html#object.__reduce__).
return (os.system,(“netcat -c ‘/bin/bash -i’ -l -p 1234 “,)): The return statement exits the enclosing function and returns an expression value as the result of the call to the function. In this case, the return statement binds a netcat connection to port 1234. netcat is “simple utility reads and writes data across TCP or UDP network connections” (http://sectools.org/tool/netcat/).
Step 14: Run the program by using the command python pickle.py
Step 15: Send the request to the repeater and replace the rememberme cookie with the new encoded pickle object. The first image above is the original and the bottom is the new encoded pickle object.
As you can see from the image above, my attempt at pickling failed. I read many pieces of documentation to ensure that the entire process was followed to a tee, but still was not able to successfully deploy commands on the target server. I am not sure if this is a Python version issue and perhaps my syntax is off? But, this blog is not only to show my successes, but also my failures. This is a process for me. Perhaps I will revisit this lab in the future. If you are reading this and can offer any insight how to successfully complete my objective, do not hesitate to share. I am hoping to learn and grow, and if you can be any assistance, the help is always welcomed and appreciated. Until next time!
Comments
Post a Comment