2023香山杯决赛 ezcache Django 缓存反序列化
2023-11-29
| 2024-2-3
0  |  阅读时长 0 分钟
type
status
date
slug
summary
tags
category
icon
password
比赛时fix了但没利用成,和Django的底层实现有关,最近忙完考证啥的抽空做了一下,题目食用体验不错,也再次感受到AWDPlus fix先很重要‼️毕竟相比做出来,看懂代码逻辑后 fix 出来更快

0x01环境搭建

题目压缩包解压缩后,得到 src.zip 和 dist-packages.tar.gz ,再次解压两个压缩包,用 pycharm 打开,右键 dist-packages,选择 Mark Directory as Sources Root,然后运行 manage.py ,就会加载本地依赖了(毕竟比赛时断网),不过在加载 @cache_page 时报错
 
经过 debug 发现,发现 src/app/settings.py 下的 CACHES.default.LOCATION 是通过环境变量加载,然后我们本地没定义,为 None ,然后就报错了… (比赛时就注释掉装饰器继续做fix了)
 
我们传入个环境变量值即可,此外 STATIC_ROOT 改为 ./static/TEMPLATES[].DIRS 改为 ./app/templates。然后 ./src/app/views.py 第25行里的 /app/static 目录也要改为相对目录 ./static 即可

0x02 漏洞分析

题目基于django,核心代码(views.py)
 
generate_page 方法可以除了 .py 结尾以外的任意上传文件,不过注意 f.name 是无法穿越到,获取到是文件 basename,但 request.POST.get('filename') 可以获取我们输入的字符串为文件名,
 
这里有个小知识点,with open("./static/{}".format(filename), 'wb+') as ff 在 python3 是可以目录穿越的,python2 不行。
 
题目名字为 easycache,我们跟一下 django 的 @cache_page 装饰器实现,django/core/cache/init.py
 
发现会读取 settings.py 里的 BACKEND 也就是实现后端,题目定义的为
 
实现代码在 django/core/cache/backends/filebased.py 目录中,get 方法存在 pickle 反序列化
 
不过他的命名 841d31a6d146abdb7e05d9cea0273545.djcache 比较随机,而且 cache 目录从环境变量获取,我们需要知道 cache 的文件路径,然后通过任意文件上传覆盖,我们恶意构造的序列化数据。
 
那怎么获取文件路径咧?细心的同学会发现,generate_page 方法中的
 
存在格式化字符串漏洞,那就可以读取任意 user 对象里的内容,不过发现常用的都被ban了
 
adminconfig. 在黑名单中,继续找找,找到了条不在黑名单中的(其实最好是这个脚本,看看有哪些访问路径能获取到,挖坑)
 
notion image
 
同理,通过下面 payload 分别可以获得项目运行根目录和static静态文件路径
现在路径拿到了,还差 cache 的名字了
 
看下 cache 名字的核心生成逻辑,其实是固定的,主要是根据请求的 url 来生成
 
有的东西需要改改,因为很多值是django启动时动态获取的,仿写
 
脚本运行结果
notion image
 
和 Django 生成的一样
notion image
 
题目中的序列化方式是
 
仿照逻辑写一个恶意序列化类
 
本地打成功了,比赛环境不出网(应该),但 os.system 这种执行方式,直接输出回显到控制台,而不是返回页面,
notion image
 
notion image
 
 
返回值执行成功是 0,执行到下一个函数会报错,而且题目 debugFalse,我们无法利用报错抛出异常来获取结果
 
不过题目提供一个读文件的 static 路径,我们把 flag 文件移过去然后访问即可
 
notion image
 
当然pickle反序列化无回显也有像报错注入和时间注入这种姿势,可以参考 https://www.cnblogs.com/sijidou/p/16305695.html
 
总体利用思路
  1. 通过格式化字符串漏洞获取django的运行路径、缓存路径和静态文件路径,并得到缓存路径相对于静态文路径
  1. 根据 Django cache 路由拼接的 url 生成缓存文件名,构造恶意序列化数据
  1. 通过文件上传目录穿越至缓存目录
  1. 然后Django cache 路由触发反序列化 rce,并访问 static 静态资源路径获取命令执行结果
完整利用 exp 放在文末

0x03 FIX

经过分析,得知利用漏洞前提是需要获取缓存目录,而获取缓存目录需要利用利用格式化字符串漏洞,因此ban掉即可
 
注意不能直接ban掉目录穿越的字符 .. 因为会导致check失败
 

0x04 One More Thing

题目源码下载(里面也有exp)
 
完整利用 exp
 
  • CTF比赛
  • Writeup
  • ISO27001考证记WIZ EKS Cluster Games CTF WriteUp
    • GitTalk
    目录