Skip to content

Commit fb078b2

Browse files
committed
feat(vulnTestServer): add shipping management module and fix task monitor
- Add shipping_handlers.py for shipping management functionality - Update database.py with shipping-related tables - Update server.py and base handler for shipping routes - Update frontend (index.html, app.js, style.css) for shipping UI - Remove deprecated req.txt - Fix task_monitor.py
1 parent 558a496 commit fb078b2

9 files changed

Lines changed: 588 additions & 24 deletions

File tree

src/backEnd/req.txt

Lines changed: 0 additions & 16 deletions
This file was deleted.

src/backEnd/utils/task_monitor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def get_max_tasks_count():
4646

4747

4848
def monitor(max_tasks_count=None):
49-
logger.debug("monitor triggered...")
49+
# logger.debug("monitor triggered...")
5050
# logger.debug(f"monitor -> id(DataStore.tasks): {id(DataStore.tasks)}")
5151
# logger.debug(f"monitor -> id(DataStore.current_db): {id(DataStore.current_db)}")
5252
local_max_tasks_count = 0

src/vulnTestServer/database.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,21 @@ def init_database():
135135
FOREIGN KEY (user_id) REFERENCES users(id)
136136
)
137137
''')
138+
139+
# 创建物流日志表(用于 XML SQL 注入演示)
140+
cursor.execute('''
141+
CREATE TABLE IF NOT EXISTS shipping_logs (
142+
id INTEGER PRIMARY KEY AUTOINCREMENT,
143+
tracking_number TEXT NOT NULL,
144+
carrier_code TEXT,
145+
status TEXT DEFAULT 'in_transit',
146+
location TEXT,
147+
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
148+
estimated_delivery TIMESTAMP,
149+
weight REAL,
150+
notes TEXT
151+
)
152+
''')
138153

139154
# 插入测试用户
140155
test_users = [
@@ -211,7 +226,25 @@ def init_database():
211226
''', secret)
212227
except:
213228
pass
214-
229+
230+
# 插入物流测试数据(用于 XML SQL 注入演示)
231+
test_shipping = [
232+
('TRK202403150001', 'SF', 'in_transit', '深圳转运中心', 1.5, '预计3天内送达'),
233+
('TRK202403150002', 'YT', 'delivered', '北京朝阳区派送站', 0.8, '已签收'),
234+
('TRK202403150003', 'ZT', 'pending', '等待揽收', 2.0, '等待快递员上门'),
235+
('TRK202403150004', 'JD', 'in_transit', '上海分拨中心', 1.2, '运输中'),
236+
('TRK202403150005', 'EMS', 'customs', '海关清关中', 3.5, '国际包裹清关'),
237+
]
238+
239+
for shipping in test_shipping:
240+
try:
241+
cursor.execute('''
242+
INSERT INTO shipping_logs (tracking_number, carrier_code, status, location, weight, notes)
243+
VALUES (?, ?, ?, ?, ?, ?)
244+
''', shipping)
245+
except:
246+
pass
247+
215248
conn.commit()
216249
conn.close()
217250
print("[*] Database initialized with test data")

src/vulnTestServer/handlers/base.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import json
1010
import os
1111
import time
12+
import html
1213
import xml.etree.ElementTree as ET
1314
from urllib.parse import unquote
1415

@@ -179,13 +180,10 @@ def get_post_data(self):
179180
except:
180181
return {}
181182
elif 'application/xml' in content_type or 'text/xml' in content_type:
182-
# XML解析
183+
# XML解析 - 支持多层嵌套、CDATA和实体编码
183184
try:
184185
root = ET.fromstring(post_data)
185-
result = {}
186-
for child in root:
187-
result[child.tag] = child.text or ''
188-
return result
186+
return self._parse_xml_element(root)
189187
except:
190188
return {}
191189
else:
@@ -214,3 +212,26 @@ def get_content_type(self):
214212
return 'xml'
215213
else:
216214
return 'form'
215+
216+
def _parse_xml_element(self, element):
217+
"""
218+
递归解析XML元素,支持多层嵌套、CDATA和实体编码
219+
220+
Args:
221+
element: xml.etree.ElementTree.Element 对象
222+
223+
Returns:
224+
dict: 解析后的字典数据
225+
"""
226+
result = {}
227+
for child in element:
228+
if len(child) > 0:
229+
# 有子元素,递归解析
230+
result[child.tag] = self._parse_xml_element(child)
231+
else:
232+
# 叶子节点,提取文本内容
233+
text = child.text or ''
234+
# XML实体解码 (如 T -> T)
235+
# CDATA 已被 ET 解析器自动处理
236+
result[child.tag] = html.unescape(text.strip()) if text else ''
237+
return result
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
"""
4+
VulnShop 物流查询处理器 - XML SQL 注入演示
5+
6+
包含:物流查询接口
7+
8+
注意:
9+
- 物流查询保留SQL注入漏洞(只读操作)
10+
- 支持 Error-based 和 Boolean-blind 双模式检测
11+
- 支持 CDATA 包装和 XML 实体编码绕过
12+
"""
13+
14+
import sqlite3
15+
import time
16+
17+
from config import DEBUG
18+
from database import get_db_connection
19+
from waf import get_waf
20+
from logger import sql_logger, logger
21+
22+
23+
class ShippingHandlerMixin:
24+
"""物流查询相关处理器Mixin"""
25+
26+
def handle_shipping_query(self, data):
27+
"""
28+
物流查询 - XML格式 - Error-based + Boolean-blind SQL注入
29+
30+
漏洞点:trackingNumber 参数直接拼接到SQL语句
31+
32+
支持的检测方式:
33+
1. Error-based: 注入导致SQL错误,错误信息在响应中返回
34+
Payload: TRK' AND 1=CAST((SELECT flag FROM secrets LIMIT 1) AS INT)--
35+
36+
2. Boolean-blind: 通过查询结果有无判断条件真假
37+
Payload: TRK' AND (SELECT SUBSTR(flag,1,1) FROM secrets)='F'--
38+
- 条件为真:返回物流信息
39+
- 条件为假:返回空结果
40+
41+
3. CDATA绕过(针对WAF):
42+
<trackingNumber><![CDATA[TRK' OR '1'='1']]></trackingNumber>
43+
44+
4. XML实体编码绕过:
45+
<trackingNumber>&#84;&#82;&#75;' OR '1'='1'</trackingNumber>
46+
47+
XML请求示例 (30个参数):
48+
<?xml version="1.0" encoding="UTF-8"?>
49+
<shippingQuery>
50+
<version>1.0</version>
51+
<requestId>req_001</requestId>
52+
<timestamp>1710489600000</timestamp>
53+
<clientId>web_client_001</clientId>
54+
<apiKey>ak_live_xxxxx</apiKey>
55+
<trackingNumber>TRK202403150001</trackingNumber>
56+
<carrierCode>SF</carrierCode>
57+
<queryType>realtime</queryType>
58+
<senderProvince>广东省</senderProvince>
59+
<senderCity>深圳市</senderCity>
60+
<senderDistrict>南山区</senderDistrict>
61+
<receiverProvince>北京市</receiverProvince>
62+
<receiverCity>北京市</receiverCity>
63+
<receiverDistrict>朝阳区</receiverDistrict>
64+
<userId>10001</userId>
65+
<userName>张三</userName>
66+
<userPhone>138****8888</userPhone>
67+
<userEmail>test@example.com</userEmail>
68+
<orderNo>ORD202403150001</orderNo>
69+
<orderId>100001</orderId>
70+
<shopId>SHOP001</shopId>
71+
<deliveryMethod>standard</deliveryMethod>
72+
<priority>normal</priority>
73+
<signature>required</signature>
74+
<insurance>true</insurance>
75+
<sessionId>sess_abc123</sessionId>
76+
<deviceFingerprint>fp_win_chrome_123</deviceFingerprint>
77+
<userAgent>Mozilla/5.0</userAgent>
78+
<clientIp>127.0.0.1</clientIp>
79+
<extraData><![CDATA[{"source":"web"}]]></extraData>
80+
</shippingQuery>
81+
82+
注意:此接口保留SQL注入以供测试,但不支持堆叠查询(避免数据修改)
83+
"""
84+
waf = get_waf()
85+
86+
# 提取所有参数(约30个)
87+
version = data.get('version', '')
88+
request_id = data.get('requestId', '')
89+
timestamp = data.get('timestamp', '')
90+
client_id = data.get('clientId', '')
91+
api_key = data.get('apiKey', '')
92+
93+
# trackingNumber 是注入点
94+
tracking_number = data.get('trackingNumber', '')
95+
96+
carrier_code = data.get('carrierCode', '')
97+
query_type = data.get('queryType', '')
98+
99+
sender_province = data.get('senderProvince', '')
100+
sender_city = data.get('senderCity', '')
101+
sender_district = data.get('senderDistrict', '')
102+
receiver_province = data.get('receiverProvince', '')
103+
receiver_city = data.get('receiverCity', '')
104+
receiver_district = data.get('receiverDistrict', '')
105+
106+
user_id = data.get('userId', '')
107+
user_name = data.get('userName', '')
108+
user_phone = data.get('userPhone', '')
109+
user_email = data.get('userEmail', '')
110+
111+
order_no = data.get('orderNo', '')
112+
order_id = data.get('orderId', '')
113+
shop_id = data.get('shopId', '')
114+
115+
delivery_method = data.get('deliveryMethod', '')
116+
priority = data.get('priority', '')
117+
signature = data.get('signature', '')
118+
insurance = data.get('insurance', '')
119+
120+
session_id = data.get('sessionId', '')
121+
device_fingerprint = data.get('deviceFingerprint', '')
122+
user_agent = data.get('userAgent', '')
123+
client_ip = data.get('clientIp', '')
124+
extra_data = data.get('extraData', '')
125+
126+
if not tracking_number:
127+
self.send_json_response({
128+
'success': False,
129+
'message': 'trackingNumber is required',
130+
'params_received': len(data)
131+
}, 400)
132+
return
133+
134+
# WAF 检查
135+
blocked, reason = waf.check(tracking_number)
136+
if blocked:
137+
self.send_json_response({
138+
'success': False,
139+
'message': f'WAF Blocked: {reason}',
140+
'tracking_number': tracking_number[:20] + '...' if len(tracking_number) > 20 else tracking_number
141+
}, 403)
142+
return
143+
144+
if DEBUG:
145+
logger.debug(
146+
"[ShippingQuery] version=%s, requestId=%s, clientId=%s, "
147+
"trackingNumber=%s, carrierCode=%s, userId=%s, sessionId=%s",
148+
version, request_id, client_id, tracking_number, carrier_code, user_id, session_id
149+
)
150+
151+
conn = get_db_connection()
152+
cursor = conn.cursor()
153+
154+
# 构建存在漏洞的SQL(字符串拼接)- trackingNumber 是注入点
155+
sql = f"SELECT * FROM shipping_logs WHERE tracking_number = '{tracking_number}'"
156+
157+
if DEBUG:
158+
sql_logger.debug("[SQL] %s", sql)
159+
160+
try:
161+
start_time = time.time()
162+
cursor.execute(sql)
163+
results = cursor.fetchall()
164+
elapsed_time = time.time() - start_time
165+
166+
# 构建响应
167+
shipping_info = []
168+
for row in results:
169+
shipping_info.append({
170+
'id': row['id'],
171+
'tracking_number': row['tracking_number'],
172+
'carrier_code': row['carrier_code'],
173+
'status': row['status'],
174+
'location': row['location'],
175+
'weight': row['weight'],
176+
'notes': row['notes'],
177+
'update_time': row['update_time']
178+
})
179+
180+
# 返回响应,包含所有接收到的参数信息(用于演示)
181+
response_data = {
182+
'success': True,
183+
'data': shipping_info[0] if shipping_info else None,
184+
'count': len(shipping_info),
185+
'query_time_ms': round(elapsed_time * 1000, 2),
186+
'request_info': {
187+
'request_id': request_id,
188+
'client_id': client_id,
189+
'timestamp': timestamp,
190+
'params_count': len(data)
191+
}
192+
}
193+
194+
# 如果没有结果,返回提示信息(用于 Boolean-blind 检测)
195+
if not shipping_info:
196+
response_data['message'] = 'No shipping information found for the given tracking number'
197+
198+
self.send_json_response(response_data)
199+
200+
except sqlite3.Error as e:
201+
# Error-based 检测:返回详细的 SQL 错误信息
202+
self.send_error_response(f'Database error: {str(e)}', 500, sql_error=e)
203+
finally:
204+
conn.close()

src/vulnTestServer/server.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
from handlers.cart_handlers import CartHandlerMixin
4646
from handlers.system_handlers import SystemHandlerMixin
4747
from handlers.secrets_handlers import SecretsHandlerMixin
48+
from handlers.shipping_handlers import ShippingHandlerMixin
4849

4950

5051
class VulnShopHandler(
@@ -55,6 +56,7 @@ class VulnShopHandler(
5556
CartHandlerMixin,
5657
SystemHandlerMixin,
5758
SecretsHandlerMixin,
59+
ShippingHandlerMixin,
5860
BaseHTTPRequestHandler
5961
):
6062
"""
@@ -253,7 +255,11 @@ def do_POST(self):
253255
self.handle_secrets_query(data)
254256
elif path == '/api/secrets/search':
255257
self.handle_secrets_search(data)
256-
258+
259+
# 物流查询模块接口(XML SQL注入演示)
260+
elif path == '/api/shipping/query':
261+
self.handle_shipping_query(data)
262+
257263
else:
258264
self.send_error(404, 'Not Found')
259265
except WAFBlockedException as e:
@@ -326,6 +332,7 @@ def run_server():
326332
║ • POST /api/feedback/search - SQL注入 (只读) ║
327333
║ • POST /api/secrets/query - SQL注入 (只读 - 可获取Flag) ║
328334
║ • POST /api/secrets/search - SQL注入 (只读 - 可搜索Flag) ║
335+
║ • POST /api/shipping/query - XML SQL注入 (30参数/1注入点) (只读) ║
329336
║ ║
330337
║ [安全接口 - 参数化查询保护] ║
331338
║ • POST /api/user/register - 安全 (session_id, captcha_token) ║

0 commit comments

Comments
 (0)