Day1
AWDP
ezjs
1.Fix
大概把所有的路径穿越给 ban 掉就好了
用了一些奇怪的操作:new URL(`http://123/${path}`).pathname ,这样得到的就是过滤后的正常路径了。
patch 如下:
2.Break
打的时候没想到,后面才想到的
方法是往 node_modules 里写入文件比如 node_modules/ejss/index.js ,然后通过 render 渲染 ejss 为后缀的文件,即可做到RCE。
ShareCard
1.Fix
比赛的时候用的 filter,把所有传来的参数过滤一下即可。
*** app.py Thu Jul 11 14:33:06 2024--- app-fix.py Tue Jul 23 10:50:42 2024****************** 15,20 ****--- 15,26 ---- def is_safe_callable(self, obj) -> bool: return False+ def filter(str):+ banned_chrs = "{}%[]_"+ for ch in banned_chrs:+ if ch in str:+ return False+ return True class Info(BaseModel): name: str****************** 34,40 **** def create_card(): if request.method == "GET": return safer_render_template("create.html")! if request.form.get('style')!=None: open('templates/style.css','w').write(request.form.get('style')) info=Info(**request.form) if info.avatar not in os.listdir('avatars'):--- 40,46 ---- def create_card(): if request.method == "GET": return safer_render_template("create.html")! if request.form.get('style')!=None and filter(request.form.get('style')): open('templates/style.css','w').write(request.form.get('style')) info=Info(**request.form) if info.avatar not in os.listdir('avatars'):****************** 45,59 ****--- 51,71 ---- qrcode.make(share_url).save(qr_img,'png') qr_img.seek(0) share_img = base64.b64encode(qr_img.getvalue()).decode()+ if filter(share_url): return safer_render_template("created.html", share_url=share_url, share_img=share_img)+ else:+ return safer_render_template("created.html") @app.route("/showCard", methods=["GET"]) def show_card(): token = request.args.get("token") data = jwt.decode(token, rsakey.publickey().exportKey(), algorithms=jwt.algorithms.get_default_algorithms()) info = Info(**data)+ if filter (info.name) and filter(info.signature) and info.avatar: info.parse_avatar() return safer_render_template("show.html", info=info)+ else:+ return safer_render_template("show.html", info=None) @app.route("/", methods=["GET"]) def index():赛后发现很好修,把 render 的 sandbox 改回原来的类就行了
*** app.py Thu Jul 11 14:33:06 2024--- app-fix.py Tue Jul 23 10:41:17 2024****************** 24,30 **** self.avatar = base64.b64encode(open('avatars/'+self.avatar,'rb').read()).decode() def safer_render_template(template_name, **kwargs):! env = SaferSandboxedEnvironment(loader=current_app.jinja_env.loader) return env.from_string(open('templates/'+template_name).read()).render(**kwargs) app = Flask(__name__)--- 24,30 ---- self.avatar = base64.b64encode(open('avatars/'+self.avatar,'rb').read()).decode() def safer_render_template(template_name, **kwargs):! env = SandboxedEnvironment(loader=current_app.jinja_env.loader) return env.from_string(open('templates/'+template_name).read()).render(**kwargs) app = Flask(__name__)2.Break
因为只给了读权限,走style.css SSTI 拿全局变量的 RSA key,然后走前面打路径穿越
poc:
{{ info.__class__.parse_avatar.__globals__.rsakey.__dict__ }}update:比赛时没做出来,思路来自@mnixry 师傅
剩下两个 java 没看是队友打的,不管了
Day2
Pentest
给了两个可以打的公网 ip。一个是企业官网和考勤数据,另一个是 springboot 的好像 Ruoyi 的服务端(ERW)。
考勤数据可以注册 admin 覆盖密码提权(后面没看
ERW
Ruoyi 走堆泄露的 api 端口 heapdump 得到 shirokey,可以用 rememberme 洞拿到 rce,种马之后加用户或者 .ssh/authorized_keys 连 ssh 进内网。
内网有八台机子对应八道题,用 fscan 扫一下基本能匹配上。
Jenkins
直接扫弱密码,能扫到admin admin123 ,登录进去走 script console 拿到命令执行,可以选择用 msf 进行后渗透操作。
PC-…88(忘名字了
只开了 3306,弱密码 root 123456连上然后任意写文件上传 sys_exec库得到无回显 RCE。同样用 msf 拿到完整 shell 之后后渗透,提权开端口。
RODC
上一台中连上 RDP 之后发现桌面上 wps 点开发现有 RODC 主机上用户名和密码,随便连一个都是管理员权限。
Gitlab
Jenkins后台有 Gitlab 的token,拿到之后可以对 Gitlab 进行操作得到 RCE。
(好像是原题,可以参考https://fushuling.com/index.php/2023/10/10/春秋云境·privilege/
DC
打的太慢了,做到这里没什么时间了。
似乎是打黄金票据从RODC 提升到 DC。