Initial commit - Forum CTF

This commit is contained in:
2026-01-08 20:38:22 +00:00
parent 923a6d4e20
commit 1953ad539a
5 changed files with 295 additions and 0 deletions

262
index.php Normal file
View File

@@ -0,0 +1,262 @@
<?php
require_once '/var/www/config/.env.php';
session_start();
include 'config.php';
$adminUsername = getenv('ADMIN_USERNAME');
$adminPassword = getenv('ADMIN_PASSWORD');
$flag = getenv('FLAG');
$minFileSize = 2 * 1024 * 1024;
$maxFileSize = 5 * 1024 * 1024;
$allowedExtensions = ['png', 'jpeg', 'jpg'];
$isConnected = isset($_SESSION['user']) && $_SESSION['user'] === $adminUsername;
$error = '';
$success = '';
$page = $_GET['page'] ?? 'forum';
function getClientIp() {
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
return $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
return explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0];
} else {
return $_SERVER['REMOTE_ADDR'];
}
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
if ($action === 'login') {
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
if ($username === $adminUsername && $password === $adminPassword) {
$_SESSION['user'] = $adminUsername;
$isConnected = true;
$success = 'Connexion réussie !';
$page = 'flag';
} else {
$error = 'Identifiants incorrects';
}
}
if ($action === 'logout') {
session_destroy();
header('Location: index.php');
exit;
}
if ($action === 'post_comment') {
$clientIp = getClientIp();
$result = $mysqli->query("SELECT last_post_time FROM rate_limit WHERE ip = '" . $mysqli->real_escape_string($clientIp) . "'");
if ($result && $result->num_rows > 0) {
$row = $result->fetch_assoc();
if (time() - $row['last_post_time'] < 60) {
$error = 'Attendre ' . (60 - (time() - $row['last_post_time'])) . 's avant de poster.';
}
}
if (empty($error)) {
$comment = trim($_POST['comment'] ?? '');
$imagePath = null;
if (isset($_FILES['image']) && $_FILES['image']['error'] === UPLOAD_ERR_OK) {
$fileSize = $_FILES['image']['size'];
$fileName = $_FILES['image']['name'];
$fileExt = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
if ($fileSize < $minFileSize) {
$error = 'Min 2 Mo.';
} elseif ($fileSize > $maxFileSize) {
$error = 'Max 5 Mo.';
} elseif (!in_array($fileExt, $allowedExtensions)) {
$error = 'PNG/JPEG seulement.';
} else {
$uploadDir = __DIR__ . '/uploads/';
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
$newFileName = uniqid() . '.' . $fileExt;
$uploadPath = $uploadDir . $newFileName;
if (move_uploaded_file($_FILES['image']['tmp_name'], $uploadPath)) {
$imagePath = 'uploads/' . $newFileName;
} else {
$error = 'Erreur upload.';
}
}
}
if (empty($error) && !empty($comment)) {
$comment = htmlspecialchars($comment, ENT_QUOTES, 'UTF-8');
$stmt = $mysqli->prepare('INSERT INTO posts (comment, image_path, poster_ip) VALUES (?, ?, ?)');
$stmt->bind_param('sss', $comment, $imagePath, $clientIp);
if ($stmt->execute()) {
$mysqli->query("INSERT INTO rate_limit (ip, last_post_time) VALUES ('" . $mysqli->real_escape_string($clientIp) . "', " . time() . ") ON DUPLICATE KEY UPDATE last_post_time = " . time());
$success = 'Posté !';
}
$stmt->close();
} elseif (empty($error)) {
$error = 'Commentaire vide.';
}
}
}
}
$posts = [];
$result = $mysqli->query('SELECT id, comment, image_path, poster_ip, created_at FROM posts ORDER BY created_at DESC');
if ($result) {
while ($row = $result->fetch_assoc()) {
$posts[] = $row;
}
}
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Forum CTF</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: Arial, sans-serif; background: #f5f5f5; padding: 20px; }
.container { max-width: 1000px; margin: 0 auto; }
nav { background: white; padding: 15px; margin-bottom: 20px; border-radius: 5px; display: flex; justify-content: space-between; align-items: center; box-shadow: 0 2px 5px rgba(0,0,0,0.1); }
nav a { color: #667eea; text-decoration: none; margin: 0 15px; font-weight: bold; }
nav a:hover { text-decoration: underline; }
.logout-btn { background: #667eea; color: white; border: none; padding: 10px 15px; border-radius: 3px; cursor: pointer; font-weight: bold; }
.logout-btn:hover { background: #764ba2; }
.content { background: white; padding: 25px; border-radius: 5px; box-shadow: 0 2px 5px rgba(0,0,0,0.1); }
h1 { color: #333; margin-bottom: 20px; }
.alert { padding: 12px; margin-bottom: 15px; border-radius: 3px; font-weight: bold; }
.alert-success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
.alert-error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
.form-group { margin-bottom: 15px; }
label { display: block; margin-bottom: 5px; font-weight: bold; color: #333; }
input, textarea { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 3px; font-family: Arial, sans-serif; }
input:focus, textarea:focus { outline: none; border-color: #667eea; box-shadow: 0 0 5px rgba(102,126,234,0.3); }
textarea { resize: vertical; min-height: 100px; }
.btn { background: #667eea; color: white; padding: 10px 20px; border: none; border-radius: 3px; cursor: pointer; font-weight: bold; }
.btn:hover { background: #764ba2; }
.posts { margin-top: 30px; }
.post { background: #f9f9f9; padding: 15px; margin-bottom: 15px; border-left: 4px solid #667eea; border-radius: 3px; }
.post-header { font-size: 12px; color: #666; margin-bottom: 10px; display: flex; justify-content: space-between; }
.post-ip { background: #e8eef7; padding: 3px 8px; border-radius: 2px; font-weight: bold; color: #667eea; }
.post-comment { margin-bottom: 10px; color: #333; line-height: 1.5; }
.post-image { margin-top: 10px; }
.post-image img { max-width: 100%; max-height: 300px; border-radius: 3px; }
.login-form { max-width: 400px; margin: 0 auto; }
.flag-box { background: #fff3cd; border: 2px solid #ffc107; padding: 25px; border-radius: 5px; text-align: center; }
.flag-text { background: #000; color: #0f0; padding: 15px; border-radius: 3px; font-family: monospace; font-size: 16px; font-weight: bold; margin-top: 15px; letter-spacing: 1px; }
.no-posts { color: #999; text-align: center; padding: 20px; }
</style>
</head>
<body>
<div class="container">
<nav>
<div>
<a href="?page=forum">Forum</a>
<a href="?page=login">Connexion</a>
<?php if ($isConnected): ?>
<a href="?page=flag">Flag</a>
<?php endif; ?>
</div>
<?php if ($isConnected): ?>
<form method="POST" style="margin: 0;">
<input type="hidden" name="action" value="logout">
<button type="submit" class="logout-btn">Déconnexion</button>
</form>
<?php endif; ?>
</nav>
<div class="content">
<?php if ($error): ?>
<div class="alert alert-error"><?php echo htmlspecialchars($error); ?></div>
<?php endif; ?>
<?php if ($success): ?>
<div class="alert alert-success"><?php echo htmlspecialchars($success); ?></div>
<?php endif; ?>
<?php if ($page === 'forum'): ?>
<h1>Forum - Partagez vos commentaires</h1>
<form method="POST" enctype="multipart/form-data">
<input type="hidden" name="action" value="post_comment">
<div class="form-group">
<label for="comment">Commentaire :</label>
<textarea name="comment" id="comment" placeholder="Écrivez votre message..." required></textarea>
</div>
<div class="form-group">
<label for="image">Image (PNG/JPEG, 2-5 Mo) :</label>
<input type="file" name="image" id="image" accept=".png,.jpeg,.jpg">
</div>
<button type="submit" class="btn">Poster</button>
</form>
<div class="posts">
<h2>Commentaires récents</h2>
<?php if (empty($posts)): ?>
<p class="no-posts">Aucun commentaire pour le moment.</p>
<?php else: ?>
<?php foreach ($posts as $post): ?>
<div class="post">
<div class="post-header">
<span class="post-ip">IP: <?php echo htmlspecialchars($post['poster_ip']); ?></span>
<span><?php echo htmlspecialchars($post['created_at']); ?></span>
</div>
<div class="post-comment"><?php echo nl2br(htmlspecialchars($post['comment'])); ?></div>
<?php if ($post['image_path']): ?>
<div class="post-image">
<img src="<?php echo htmlspecialchars($post['image_path']); ?>" alt="Image">
</div>
<?php endif; ?>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
<?php elseif ($page === 'login'): ?>
<h1>Connexion</h1>
<div class="login-form">
<form method="POST">
<input type="hidden" name="action" value="login">
<div class="form-group">
<label for="username">Utilisateur :</label>
<input type="text" name="username" id="username" required autofocus>
</div>
<div class="form-group">
<label for="password">Mot de passe :</label>
<input type="password" name="password" id="password" required>
</div>
<button type="submit" class="btn">Se connecter</button>
</form>
</div>
<?php elseif ($page === 'flag'): ?>
<?php if ($isConnected): ?>
<h1>Flag</h1>
<div class="flag-box">
<h2>🚩 Vous êtes connecté !</h2>
<div class="flag-text"><?php echo htmlspecialchars($flag); ?></div>
</div>
<?php else: ?>
<h1>Accès refusé</h1>
<p>Veuillez vous <a href="?page=login">connecter</a>.</p>
<?php endif; ?>
<?php endif; ?>
</div>
</div>
</body>
</html>