第三届长城杯半决赛-AWDP-部分WEB解
上午的 AWDP 就修了一个,一个也没打通,下午的渗透就打了个Shiro,不嘻嘻 :(
AWDP
easy_time
Break
开始是一个登录界面,可以弱口令登录,密码是secret

或者根据源码index.py里可以看到,admin的密码是硬编码的,是经过了两次MD5加密,并且这里如果登录成功,就会设置Cookie中visited=yes,user为登录用户名,这要设置一下这俩就可以伪造Cookie未授权登录了


在docker-compose.yaml中可以看到靶机内部存在80端口,在Dockerfile中可以看到存放的是html中的三个文件,这就可以想到找SSRF去打这个端口

访问/about路由可以找到可能存在SSRF的地方

去源码中看,可以 POST 传参avatar_url,这个参数是可控的

然后在下面的这里会调用fetch_remote_avatar_info(current['avatar_url'])

这里的fetch_remote_avatar_info()函数就是可以打SSRF,限制只能使用http或https协议

所以可以构造如下请求包:
1 | |

很显然是成功了的,但是源码中放在html目录下的三个文件都没什么用,但是在后台页面中可以看到有上传插件的功能

是支持上传压缩包并解压缩的,所以如果我构造好一个压缩包上传,如果能存在目录穿越之类的漏洞,我就可以将解压的文件传到html目录下,然后就能通过上面的SSRF从而可以实现RCE

去看源码,是会调用safe_upload()这个函数实现上传的

再去看safe_upload()这个函数,发现是直接使用的info.filename,这是可控的,os.path.join只会做字符串拼接,不会过滤目录穿越需要的字符

所以只要将上传的压缩包中的文件名修改为../../../../../../var/www/html/shell.php,就可以通过目录穿越,将构造的恶意文件上传到html目录下,因为windows中命名文件不允许写/,所以这里可以利用脚本来生成压缩包:
1 | |
运行脚本生成shell.zip文件,然后直接上传即可

此时就可以通过SSRF去访问shell.php文件并进行RCE
1 | |

flag在/tmp/flag,还有要注意的是这里不能使用空格,不然命令不会执行成功,可以随便找个绕过空格的方法即可,我用的${IFS}
1 | |

Fix
感觉应该可以对SSRF的部分过滤本地回环地址之类的,还有上传压缩包的地方对文件名限制目录穿越的,具体的修复也没环境尝试
MediaDrive
这一题是当时唯一修好的一个,但是没打
Fix
先随便上传个文件

然后抓包看看,这里抓的preview的包,会发现Cookie中是一段URL编码的序列化数据,其中有个basePath属性是指定的文件路径,然后我就想到这里是不是可以通过修改这个值从而进行目录穿越

然后我就去看源码了

在preview.php中,通过file_get_contents()函数来读文件内容的

这里传入的$convertedPath是对$rawPath经过编码转换后的

而$rawPath就是$user->basePath和$f的拼接结果,这里是最重要的,意味着之前的想法是可能实现的

并且过滤了一些字符串,也不能大小写绕过

这里basePath就是从Cookie中提取的basePath属性的值,$f是通过 GET 方式传入的f参数

这里尝试一下,将basePath修改为空,注意要进行URL编码,然后f改为/etc/passwd
1 | |
没问题,想法可行,确实存在漏洞

至于另一个download.php中是没有使用basePath,而是用的写死的/var/www/html/uploads,也就不存在漏洞

到了这里我就想到了修,是不是可以直接将preview.php中的像download.php中的一样写死路径,就可以check成功了,事实证明是可以的

Break
然后是打,直接读根目录下的flag是不行的,因为过滤了flag关键词,也不能大小写绕过,当时想到了利用编码转换来进行绕过,因为这题存在编码转换的功能的,但是当时没看到源码中的,一直以为是下面这里

关键是下面这部分,可以将Cookie中的user的编码转化为UTF-8编码

所以只要将/flag转化为其他编码,比如UTF-16就可以绕过了,因为会有些不可见字符,所以URL编码一下,转换脚本:
1 | |
还有就是Cookie中的也编码为UTF-16,可以根据lib目录下的User.php内容修改

脚本:
1 | |
构造的请求包:
1 | |
成功绕过获取flag

IntraBadge
Break
没招了,codex五分钟秒了,跟着AI写的WP复现了
漏洞点是在utils.py中的fetch_resource()函数中存在SSRF,这里可以使用redis://协议,可以通过这个点连接到靶机的 Redis 服务,并读取任意键

然后去找哪里会调用到这个函数,在app.py中,可以找到在/avatar/refresh路由中,这个路由是用来从外部URL获取用户头像的,并将其存储到 Redis 数据库中,无论指定的URL指向什么,返回的内容都会放在avatarbin:{user}和avatarctype:{user}中

在/preview中就直接将其暴露给用户模板了

所以可以将任意 Redis 键的内容缓存为“头像”,再把模板改成{{ avatar_raw_text() }},即可在 /preview 页面直接读出 Redis 键值
修改模板的话可以利用/template路由实现

在/debug/diag也是存在提示的(下面是翻译后的结果),就是利用缓存头像,并且告知了 Redis 在127.0.0.1:6379

先修改模板内容,可以先在/preview路由中看一下头像是什么,可以看到现在默认设置的是No Avatar,点击Edit Template按钮编辑模板

找到No Avatar,将其替换为{{ avatar_raw_text() }}后save保存

然后来到/dashboard路由,修改头像的URL地址为redis://127.0.0.1:6379/0/flag,也就是去读flag键,然后Save URL保存,再Refresh Cache刷新下头像缓存,让后端去读flag键

最后回到/preview就可以在头像地方看到flag了


Fix
修这个的话我想到的是直接禁用掉redis://协议,或者把flag键给加个waf过滤掉,或者对头像的URL限制不能用回环地址,或者直接删掉avatar_raw_text()和avatar_raw_b64()这俩函数,没有check环境就不能复现试试了
wso2
Break
…
Fix
当时比赛的时候好像直接rm /flag就可以过了
ISW
ISW3
复现平台的就提供了开始的Shiro和pkexec提权
开始很容易可以看出是Shiro的,当时比赛时的截图:

直接用工具打

写入冰蝎的内存马

用冰蝎连接

第一个flag就是在根目录下的flag文件中

然后是提权,可以SUID提权,利用pkexec
1 | |

但是这个复现环境搭的有点问题,pkexec打不通,不过我自己搭了单独的复现环境,写了笔记:https://yschen20.github.io/2026/03/23/pkexec%E6%8F%90%E6%9D%83%EF%BC%88CVE-2021-4034%EF%BC%89/
这题第二部分的flag在root目录下,不过环境变量没删,想要这题的flag的话就直接env了
再之后的横向就没环境了
当时比赛的时候就打Shiro进来了,提权也没看出来