Hack the Box INSANE题 ArtificialUniversity题解
字数 1823 2025-08-20 18:18:16
Hack the Box INSANE难度题目ArtificialUniversity题解
0x00 题目概述
这是一个Flask框架构建的Web应用程序,模拟了一个购物网站系统。题目难度为INSANE级别,涉及多个漏洞的串联利用,包括逻辑漏洞、路径穿越、SSRF、XSS和gRPC服务中的代码执行漏洞。
0x01 系统架构分析
路由结构
用户侧路由:
/register- 用户注册/login- 用户登录/product/<product_id>- 查看商品/checkout- 下单/checkout/success- 支付回调/subs- 查看订单/logout- 登出
管理员侧路由(需admin权限):
/admin/users- 查看用户列表/admin/products- 查看所有商品/admin/orders- 查看所有订单/admin/view-pdf- 查看PDF/admin/api-health- 查看API接口状态/admin/product-stream- 获取新产品/admin/save-product- 保存产品/admin/saved-products- 查看已保存产品
配置文件分析
config.py中关键配置:
class Config(object):
SECRET_KEY = os.urandom(50).hex()
ADMIN_EMAIL = "ed@artificialuniversity.htb"
ADMIN_PASS = os.urandom(32).hex()
管理员凭据是随机生成的,无法爆破。
0x02 漏洞分析与利用链
1. 逻辑漏洞+路径穿越
漏洞点1: 价格可控
在/checkout路由中,当不传入product_id时,价格参数完全可控:
@web.route("/checkout", methods=["GET"])
def checkout():
product_id = request.args.get("product_id")
if product_id and not session.get("loggedin"):
return render_template("error.html", title="Error", error="Must have an account in order to purchase"), 200
price = request.args.get("price") # 价格可控
title = request.args.get("title")
user_id = request.args.get("user_id")
email = request.args.get("email")
if not product_id and (not price or not title or not user_id or not email):
return render_template("error.html", title="Error", error="Missing external order details"), 400
db_session = Database()
payment_link = None
if product_id:
# 正常流程
else:
product_data = {
"title": title,
"price": int(price) # 可设置为负数
}
payment_link, payment_id = generate_payment_link(product_data["price"])
order_id = db_session.create_order(title, user_id, email, int(price), payment_id)
漏洞点2: 支付回调中的路径穿越
/checkout/success路由中的bot_runner函数会访问PDF文件,但payment_id可控:
def bot_runner(email, password, payment_id):
# ...
client.get(f"http://127.0.0.1:1337/static/invoices/invoice_{payment_id}.pdf")
# ...
通过设置payment_id为..admin/xxx#,浏览器会解析为http://127.0.0.1:1337/admin#pdf,而后端实际接收到的是http://127.0.0.1:1337/admin。
利用步骤:
- 访问
/checkout不传product_id,设置price=-1创建负价订单 - 在
/checkout/success回调中设置payment_id=..admin/xxx#实现路径穿越 - 利用bot自动登录管理员账号后访问admin路由
2. SSRF漏洞利用
漏洞点1: /admin/view-pdf
@web.route("/admin/view-pdf", methods=["GET"])
def admin_view_pdf():
pdf_url = request.args.get("url")
response = requests.get(pdf_url) # SSRF
漏洞点2: /admin/api-health
@web.route("/admin/api-health", methods=["GET", "POST"])
def api_health():
url = request.form.get("url")
status_code = get_url_status_code(url) # 使用curl实现的SSRF
def get_url_status_code(url):
curl_args = ["curl", "-o", "/dev/null", "-w", "%{http_code}", url]
result = subprocess.run(curl_args, capture_output=True, text=True, check=True)
3. PDF.js漏洞利用(CVE-2024-4367)
题目使用的Firefox 125.0.1版本存在PDF.js漏洞(CVE-2024-4367),允许通过特制PDF执行任意JavaScript代码。
利用方法:
- 构造恶意PDF触发XSS
- 通过XSS自动提交表单访问
/admin/api-health - 利用curl的SSRF功能攻击内网服务
4. gRPC服务代码执行
内网gRPC服务(50051端口)存在任意代码执行漏洞:
class ProductService(product_pb2_grpc.ProductServiceServicer):
def GenerateProduct(self):
if hasattr(self, "price_formula"):
price = eval(self.price_formula) # 任意代码执行
def DebugService(self, request, context):
input_dict = {k: v.string_value for k, v in request.input.items()}
self.UpdateService(input_dict, self) # 可设置price_formula属性
利用链:
- 通过
DebugService设置price_formula属性 - 调用
GetNewProducts触发GenerateProduct执行eval
5. 完整利用链
-
初始访问:
- 利用逻辑漏洞创建负价订单
- 通过路径穿越访问admin接口
-
权限提升:
- 利用
/admin/view-pdf的SSRF和PDF.js漏洞执行XSS - 通过XSS自动提交表单访问
/admin/api-health
- 利用
-
内网横向移动:
- 构造gopher协议请求攻击内网gRPC服务
- 通过
DebugService设置price_formula - 调用
GetNewProducts触发代码执行
0x03 防御建议
-
修复逻辑漏洞:
- 价格参数应由服务端计算,不可由客户端控制
- 支付回调应验证
payment_id格式
-
防止路径穿越:
- 规范化路径处理
- 验证文件名不包含特殊字符
-
SSRF防护:
- 限制URL访问范围(协议、域名、端口)
- 使用白名单机制
-
gRPC服务安全:
- 避免使用
eval等危险函数 - 对输入参数进行严格过滤
- 限制服务访问权限
- 避免使用
-
组件安全:
- 及时更新存在漏洞的组件版本
- 实施最小权限原则
0x04 参考链接
- CVE-2024-4367详情
- gRPC安全最佳实践
- SSRF防御指南