pyshv2

Attachmentsmisc - 8575 solves

Continuous delivery is awesome.
We deploy our code to production whenever we can.
No code, no vulnerability.
Everything works great.

Overview, Concept and Design Criteria

See pyshv1

Solution

Now things become a little bit harder, there are two difference between these two version.

diff --git a/pyshv1/task/home/task/securePickle.py b/pyshv2/task/home/task/securePickle.py
index da5db40..6eb82f4 100644
--- a/pyshv1/task/home/task/securePickle.py
+++ b/pyshv2/task/home/task/securePickle.py
@@ -11,7 +11,8 @@ class RestrictedUnpickler(pickle.Unpickler):
     def find_class(self, module, name):
         if module not in whitelist or '.' in name:
             raise KeyError('The pickle is spoilt :(')
-        return pickle.Unpickler.find_class(self, module, name)
+        module = __import__(module)
+        return getattr(module, name)


 def loads(s):

diff --git a/pyshv1/task/home/task/server.py b/pyshv2/task/home/task/server.py
index 7c008b7..3fc63be 100755
--- a/pyshv1/task/home/task/server.py
+++ b/pyshv2/task/home/task/server.py
@@ -4,13 +4,16 @@ import securePickle as pickle
 import codecs


-pickle.whitelist.append('sys')
+pickle.whitelist.append('structs')


 class Pysh(object):

 # ...

diff --git a/pyshv2/task/home/task/structs.py b/pyshv2/task/home/task/structs.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/pyshv2/task/home/task/structs.py

First thing is that we are only able to import an empty module structs now. Second thing is that we use __import__ here.

The trick of this challenge is monkey patching. __import__ is a builtin function in __builtins__, which is a dict shares among all modules.

We can overwrite __import__ by overwriting structs.__builtins__.

Overwrite __import__ with structs.__getattribute__, we can retrieve some attributes deeper inside, just like what we did in pyshv1.

You can find the final pickle bytecode here.