最近做了 ph 牛的 code-breaking,在做 picklecode 这一题时,没有搞懂那个 django 的 signed_cookies 引擎对 session 的操作,就 debug 了一下,做个总结,算是做了个代码审计吧

原文 : https://xz.aliyun.com/t/6265

0x01 获取 session_auth_hash

  • 题目 : https://github.com/phith0n/code-breaking/tree/master/2018/picklecode

  • django 使用的 SESSION_ENGINE 为 django.contrib.sessions.backends.signed_cookies

  • pycharm 开启 debug 模式,username 为 peri0d,password 为 123456

  • 入口文件在 views.py,第 34 行新建了用户并对密码进行了加密。第 35 行调用 auth_login() 函数,跳转到 auth\__init__.pylogin() 方法

  • 第 97 行,调用 user 类的 get_session_auth_hash() 方法来获取 session_auth_hash 的值,跟进 get_session_auth_hash()

  • key_salt 赋值后调用 salted_hmac(key_salt, self.password) 生成 session_auth_hash,这里的 password 是经过加密的,跟进 salted_hmac()

  • 在第 39 行对 key_salt + secret 进行 sha1 加密并以 byte 类型返回给 key。这里的 value 是经过加密后的 password。然后调用 hmac.new() 返回一个 sha1 模式的 hmac 对象

  • 流程梳理

    key_salt = '***'
    # SECRET_KEY
    secret = '******'
    key = hashlib.sha1(key_salt + secret).digest()
    sha1_obj = hmac.new(key, msg=password_enc, digestmod=hashlib.sha1)
    session_auth_hash = sha1_obj.hexdigest()

0x02 初始化 sessionid

  • 获取 session_auth_hash 后,单步调试,进入 base.py 执行 __contains__() 函数,参数为 _auth_user_id

  • 单步调试,然后执行 _get_session() 函数,返回缓存 session,是一个空字典

  • 在第 108 行执行 cycle_key(),使用新密钥保存相同的数据,调用 save(),它在请求结束时自动保存一个带有新密钥的 cookie 。

  • 跟进 save(),在第 41 行执行 _get_session_key() ,生成一个 base64 编码后的字符串作为 session key,继续跟进,它又调用了 signing.dumps()

  • 然后单步调试进入到 _get_session() 方法获取 self._session,从缓存中加载 session,此时为一个空字典,即 self._session == {}

  • 然后分别给 compress,salt,serializer 赋值,然后调用 signing.dumps() ,继续跟进,传入的参数 obj = {}, salt = 'django.contrib.sessions.backends.signed_cookies', compress = True

  • signing.dumps() 中对序列化之后的数据进行压缩,然后进行 base64 编码,再 decode() 为一个 Unicode 的 base64d,其值为 'gAN9cQAu' ,最后调用 TimestampSigner 类的 sign() 方法,继续跟进

  • TimestampSigner 类继承自 Signer 类,先调用它的 __init__ 方法进行初始化,key = 'zs%o-mvuihtk6g4pgd+xpa&1hh9%&ulnf!@9qx8_y5kk+7^cvm', sep = ':', salt = 'django.contrib.sessions.backends.signed_cookies'

  • 然后调用 TimestampSigner 类的 sign() 方法,根据 value='gAN9cQAu'septimestamp()value 进行重新赋值,其值为 'gAN9cQAu:1i5q6e' ,然后再次在 Signer.sign() 中重新赋值,得到最后结果 'gAN9cQAu:1i5q6e:wjJR2MUONx_wmPA3m8zYqTj5uCQ

  • 回到 save() ,继续单步调试,调用了 base.py 中第 170 行的 _set_session_key() 方法,将 value 赋值给 session_key_session_key

  • 回到 save() ,完成赋值,回到 cycle_key(),再回到 auth\__init__.pylogin() 方法的第 108 行,这时可以在变量列表看到设置的 session 信息了

  • 后面的代码是 django 对用户的持久化处理以及对 CSRF token 的验证等等,值得注意的是在第 126 行到 128 行,进行了 session 设置

  • 流程梳理

    _session = {}
    # SECRET_KEY
    secret = '******'
    salt='****' data = serializer().dumps(_session)
    compressed = zlib.compress(data)
    base64d = b64_encode(data).decode() session_key = TimestampSigner(SECRET_KEY, salt=salt).sign(base64d)

0x03 response 写入 session

  • 然后看它如何在 response 中设置 cookie 的,继续调试,在 contrib\sessions\middleware.py 中发现其对 cookie 的操作,从 44 行开始是设置 cookie 的存活时间,在第 58 行看到了 save() 函数,进行 cookie 的保存,单步调试进入

  • 在 save() 函数中,调用 _get_session_key() 函数,剩下的反序列化和前面的相同,只是 session 的值发生了改变,从空字典变为含有 3 个元素的字典,然后就是将 cookie 设置在返回包中,这就完成了 cookie 设置的分析

0x04 总结

  • 总结一下,它对 session 处理的核心机制在于 django.core.signing.dumps() 函数,其具体代码如下,可以看到,data 为 pickle 序列化之后的 byte 对象,我们只要将 data 改为构造好的 evil pickle code 即能实现任意的代码执行

    def dumps(obj, key=None, salt='django.core.signing', serializer=JSONSerializer, compress=False):
    
        data = serializer().dumps(obj)
    
        is_compressed = False
    
        if compress:
    compressed = zlib.compress(data)
    if len(compressed) < (len(data) - 1):
    data = compressed
    is_compressed = True
    base64d = b64_encode(data).decode()
    if is_compressed:
    base64d = '.' + base64d
    return TimestampSigner(key, salt=salt).sign(base64d)

code-breaking picklecode中对signed_cookies引擎分析的更多相关文章

  1. jQuery中的Sizzle引擎分析

    我分析的jQuery版本是1.8.3.Sizzle代码从3669行开始到5358行,将近2000行的代码,这个引擎的版本还是比较旧,最新的版本已经到v2.2.2了,代码已经超过2000行了.并且还有个 ...

  2. MySQL中innodb引擎分析(初始化)

    MySQL的存储引擎是以插件形式工作的,这应该是MySQL的一大特色了吧! 依据<深入理解MySQL>的内容,5.1版本号时存储引擎的插件化都还不是彻底,确切的说是刚加入的特性.为MySQ ...

  3. 【原】 Spark中Worker源码分析(二)

    继续前一篇的内容.前一篇内容为: Spark中Worker源码分析(一)http://www.cnblogs.com/yourarebest/p/5300202.html 4.receive方法, r ...

  4. 在QT中使用Irrlicht引擎的方法与步骤

      Ø 相关库,插件安装部分 本篇文档介绍在Qt5.2.0下面使用lrrlicht引擎在Qt窗口中输出(开发环境:vs2012) 1. 首先安装好Qt5.2.0,下载地址: http://downlo ...

  5. Express ( MiddleWare/中间件 路由 在 Express 中使用模板引擎 常用API

    A fast, un-opinionated, minimalist web framework for Node.js applications. In general, prefer simply ...

  6. MySql中innodb存储引擎事务日志详解

    分析下MySql中innodb存储引擎是如何通过日志来实现事务的? Mysql会最大程度的使用缓存机制来提高数据库的访问效率,但是万一数据库发生断电,因为缓存的数据没有写入磁盘,导致缓存在内存中的数据 ...

  7. equals和==方法比较(二)--Long中equals源码分析

    接上篇,分析equals方法在Long包装类中的重写,其他类及我们自定义的类,同样可以根据需要重新equals方法. equals方法定义 equals方法是Object类中的方法,java中所有的对 ...

  8. AI框架中图层IR的分析

    摘要:本文重点分析一下AI框架对IR有什么特殊的需求.业界有什么样的方案以及MindSpore的一些思考. 本文分享自华为云社区<MindSpore技术专栏 | AI框架中图层IR的分析> ...

  9. 实时营销引擎在vivo营销自动化中的实践 | 引擎篇04

    作者:vivo 互联网服务器团队 本文是<vivo营销自动化技术解密>的第5篇文章,重点分析介绍在营销自动化业务中实时营销场景的背景价值.实时营销引擎架构以及项目开发过程中如何利用动态队列 ...

随机推荐

  1. sql-lib闯关61-65

    第六十一关 和六十关基本一样,就是变成了单引号和双括号,这好像是第一次遇见双括号 爆数据库名   ?id=1'))and extractvalue(1, concat(0x5c, (select da ...

  2. MySQL datetime类型详解

    研发反馈问题,数据库中datetime数据类型存储的值末尾会因四舍五入出现不一致数据,影响查询结果,比如:程序中自动获取带毫秒精度的日期'2019-03-05 01:53:55.63',存入数据库后变 ...

  3. python之线程和进程

    进程(process)和线程(thread)是操作系统的基本概念,但是它们比较抽象,不容易掌握.最近,我读到一篇材料,发现有一个很好的类比,可以把它们解释地清晰易懂. 1:计算机的核心是CPU,它承担 ...

  4. AC自动机(初步学习)

    一开始讲AC自动机就是在字典树上做一个KMP,吓得我感觉好难,不过了解了以后,感觉也就是有点难度,不吓人. 它只是在字典树上用了KMP的思想 典型问题:给n个模式串和一个文本串,问有多少个模式串在文本 ...

  5. [RH134] 10-NFS和Samba客户端

    NFS和samba服务器的配置,请参考: 这里,我们只讨论客户端的使用 1.NFS客户端的使用 nfs实现的是类Unix系统之间的远程共享目录. 假设我们已经有一个提供nfs服务的服务器,IP为192 ...

  6. IntelliJ IDEA 激活码 [已购买,分享给码友]

    一.前言 笔者在网上找了一圈,各种方法都试过了,之前那种在网上随便找个注册码,过了一段时间就被封了,想了想还是经常用的和朋友一起购买了,方便日后使用 二.下载最新的 IDEA 其实也可以从老版本直接升 ...

  7. Netty:Channel

    上一篇我们通过一个简单的Netty代码了解到了Netty中的核心组件,这一篇我们将围绕核心组件中的Channel来展开学习. Channel的简介 Channel代表着与网络套接字或者能够进行IO操作 ...

  8. 类实例调用静态方法(Java)

    前言 第一次看到在Java中是可以通过类实例调用静态方法,当然不推荐这么做,接下来会讲到,但是在C#中通过类实例调用静态方法在编译时就不会通过,这里做下记录. 类实例调用静态方法 首先我们来看一个简单 ...

  9. IIS 组成

    HTTP.sys      http.sys 侦听来自网络的 HTTP 请求,将它们传递到 IIS 并返回响应. 它是一种可以从命令行停止和启动的服务.      "NET STOP HTT ...

  10. 浅谈Java参数传递机制

    Java参数传递 ​ 才疏学浅,今天才知道Java中方法的参数是可以传递对象引用进去的. ​ Java的参数传递机制很简单,其实就是值传递. ​ 所谓值传递,也就是我们在给方法传递一个参数的时,传递的 ...