You are on page 1of 6

Safe Pickling - Restricting Globals

In unpickling, by default the class or function present in pickle data is imported.


Such behavior is unacceptable as it allows the unpickler to import and invoke any
random or arbitrary code.

Example

When the following hand-crafted pickle data stream is loaded:

import pickle

pickle.loads(b"cos\nsystem\n(S'echo hello everyone'\ntR.")


The output is:

hello everyone
0
In the above example, the unpickler imports the os.system function, and then
applies the string argument "echo hello everyone ". This is inoffensive, however,
it could have been a damaging one.

Safe Pickling - Restricting Globals


As learnt from the previous card, unpicked items must be controlled by customizing
Unpickler.find_class(). Unlike the name suggests, Unpickler.find_class() is called
whenever a global class or function is requested. Therefore, it is possible to
either forbid the globals, or restrict them to a safe subset.

Example

import builtins
import io
import pickle

safe_builtins = {
'range',
'complex',
'set',
'frozenset',
'slice',
}

class RestrictedUnpickler(pickle.Unpickler):

def find_class(self, module, name):


# Only allow safe classes from builtins.
if module == "builtins" and name in safe_builtins:
return getattr(builtins, name)
# Forbid everything else.
raise pickle.UnpicklingError("global '%s.%s' is forbidden" %
(module, name))

Safe Pickling - Restricting Globals


Example

def restricted_loads(s):
"""Helper function analogous to pickle.loads()."""
return RestrictedUnpickler(io.BytesIO(s)).load()
restricted_loads(pickle.dumps([5,3,range(20)]))
The above code generates the following output:

[5, 3, range(0, 20)]


When the following input is passed:

restricted_loads(b"cos\nsystem\n(S'echo hello everyone'\ntR.")


The output is:

>>> restricted_loads(b"cos\nsystem\n(S'echo hello everyone'\ntR.")


Traceback (most recent call last):
...
pickle.UnpicklingError: global 'os.system' is forbidden
>>> restricted_loads(b'cbuiltins\neval\n'
... b'(S\'getattr(__import__("os"), "system")'
... b'("echo hello everyone")\'\ntR.')
Traceback (most recent call last):
...
pickle.UnpicklingError: global 'builtins.eval' is forbidden
Therefore, always be careful about what is unpickled.

import os
import builtins
import pickle
import sys
sys.tracebacklimit=0
import traceback
import io
from logging import Logger

safe_builtins = {
'range',
'complex',
'set',
'frozenset'

class RestrictedUnpickler(pickle.Unpickler):

def find_class(self, module, name):


# Only allow safe classes from builtins.
if module == "builtins" and name in safe_builtins:
return getattr(builtins, name)
# Forbid everything else.
raise pickle.UnpicklingError("global '%s.%s' is forbidden" %(module, name))

def restricted_loads(s):
"""Helper function analogous to pickle.loads()."""
return RestrictedUnpickler(io.BytesIO(s)).load()

def func1(a):
try:
x = restricted_loads(pickle.dumps(a))
return x
except pickle.UnpicklingError:
s = traceback.format_exc()
print("Traceback (most recent call last):")
return s

def func2(s):
try:
x = restricted_loads(pickle.dumps(slice(0,8,3)))
return s[x]
except pickle.UnpicklingError:
s = traceback.format_exc()
print("Traceback (most recent call last):")
return s

if __name__ == "__main__":
a=range(int(input()))
b=func1(a)
print(b)
y=tuple(input())
z=func2(y)
print(z)

Input (stdin)

Run as Custom Input


|
Download
50
"a", "b", "c", "d", "e", "f", "g", "h"
Your Output (stdout)
range(0, 50)
Traceback (most recent call last):
_pickle.UnpicklingError: global 'builtins.slice' is forbidden
Expected Output

Download
range(0, 50)
Traceback (most recent call last):
_pickle.UnpicklingError: global 'builtins.slice' is forbidden

import os
import json

def func1(value):
a = json.loads(value)
datas = []
for item in a["data"]:
datas.append(item)

return datas

if __name__ == "__main__":
try:
data=input()
b=func1(data)
print(True)
print(b)
except ValueError as error:
print(False)

Input (stdin)

Run as Custom Input


|
Download
{"data":[{"name":"John", "age":30, "city":"New York"},{"name":"Smith", "age":35,
"city":"California"}]}
Your Output (stdout)
True
[{'name': 'John', 'age': 30, 'city': 'New York'}, {'name': 'Smith', 'age': 35,
'city': 'California'}]
Expected Output

Download
True
[{'name': 'John', 'age': 30, 'city': 'New York'}, {'name': 'Smith', 'age': 35,
'city': 'California'}]

import os
import json

def func1(value):
a = json.dumps(value)
b = json.loads(value)
return b

if __name__ == "__main__":
try:
data=input()
b=func1(data)
print(True)
print(b[1].values())
except ValueError as error:
print(False)

Input (stdin)

Run as Custom Input


|
Download
[{"1": "Student1", "Marks": 90}, {"2": "Student2", "Marks": 95}]
Your Output (stdout)
True
dict_values(['Student2', 95])
Expected Output

Download
True
dict_values(['Student2', 95])
value
# Enter your code here.
import pickle
import os
data = {"a":[5,9],"b":[5,6],"c":["Pickle is","helpful"]}
#Dump file in pickle
with open("test.pkl","wb") as f:
pickle.dump(data, f)
data.clear() #deleting dictionary data
#Read data back from pickle
with open("test.pkl","rb") as f:
data = pickle.load(f)
print(data)

pickles = []
for root,dirs,files in os.walk("./"):
# root is the dir we are currently in, f the filename that ends on ...
pickles.extend( (os.path.join(root,f) for f in files if f.endswith(".pkl")) )
pickles=str(pickles)
print(pickles)

with open('.hidden.txt','w') as outfile:


outfile.write(pickles)

user@workspacewx7zo5ahrmil21gz:/projects/challenge$ python3.5 prog.py


{'a': [5, 9], 'b': [5, 6], 'c': ['Pickle is', 'helpful']}
['./test.pkl']
============================= test session starts ==============================

platform linux -- Python 3.5.2, pytest-3.2.1, py-1.10.0, pluggy-0.4.0

rootdir: /projects/challenge, inifile:

collected 1 item

test.py .

=========================== 1 passed in 0.02 seconds ===========================

# Enter your code here.


import os
import pickle
class Player:
def __init__(self, name, runs):
self.name = name
self.runs = runs

#Write code here to access value for name and runs from class PLayer
myPlayer = Player("dhoni",10000)

#Write code here to store the object in pickle file


with open("test.pickle", "wb") as f:
pickle.dump(myPlayer, f)
del myPlayer

#Write code here to read the pickle file


with open("test.pickle", "rb") as f:
myPlayer = pickle.load(f)

You might also like