前言:
虽然之前就已经搭建过一次简单的登录注册网站了,但是随着一年web的学习对于php、html和js的理解才懂得之前的那些代码的含义。借为24级新生出题需要搭建一个登录网站的机会,此时再次搭建一个网站巩固对于语言的学习。
目录结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| web - admin | |--------files |--------flag.sh |--------run.sh |--------TGlu.sql |--------src |--------404.html |--------admin.php |--------db.php |--------index.php |--------login.php |--------register.php |--------user.php |--------docker-compose.yml |--------Dockerfile
|
一、登录界面和注册界面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
| //login.php <?php // 开始会话 session_start(); // 清除所有会话数据 session_unset();
// 连接数据库 include 'db.php';
// 处理用户登录 if ($_SERVER["REQUEST_METHOD"] == "POST") { $username = $_POST['username']; $password = $_POST['password']; // 使用预准备语句和参数化查询 $stmt = $conn->prepare("SELECT * FROM User WHERE username=? AND password=?"); $stmt->bind_param("ss", $username, $password); $stmt->execute(); $result = $stmt->get_result();
// 查询用户信息 // $sql = "SELECT * FROM User WHERE username='$username' AND password='$password'"; // $result = $conn->query($sql);
if ($result->num_rows == 1) { $user = $result->fetch_assoc(); // 假设验证成功,将用户名存储在 session 中 $_SESSION['username'] = $username; if ($user['username'] == 'admin') { // 如果是admin用户,重定向到 admin.php header("Location: admin.php"); exit(); } else { // 如果不是admin用户,重定向到 user.php header("Location: user.php"); exit(); } } else { $loginMessage = '用户名或密码错误!'; } }
// 关闭数据库连接 $conn->close(); ?> <style> * { font-family: "Poppins", sans-serif; margin: 0; padding: 0; box-sizing: border-box; }
body { min-height: 100vh; display: flex; align-items: center; justify-content: center; background: #282a37; background-size: cover; background-position: center; }
.wrapper { position: relative; width: 400px; height: 450px; background: #3e404d; border: 2px solid rgba(255, 255, 255, 0.5); border-radius: 20px; display: flex; align-items: center; justify-content: center; backdrop-filter: blur(15px); } .wrapper:hover { box-shadow: 0 0 40px rgba(255,255,255,0.5); background: #46474e; }
.wrapper h1 { font-size: 2em; color: #fff; text-align: center; }
.wrapper .input-box { position: relative; width: 310px; margin: 30px 0; border-bottom: 2px solid #fff; }
.wrapper .input-box input { width: 100%; height: 50px; background: transparent; outline: none; border: none; font-size: 1em; color: #fff; padding: 0 40px 0 5px; }
.wrapper .input-box label { position: absolute; top: 50%; left: 5px; transform: translateY(-50%); font-size: 1em; color: #fff; pointer-events: none; transition: 0.5s; }
.wrapper .input-box input:focus ~ label, .wrapper .input-box input:valid ~ label { top: -5px; }
.wrapper .input-box .icon { position: absolute; right: 8px; color: #fff; font-size: 1.2em; line-height: 57px; }
.wrapper .row { margin: -15px 0 15px; font-size: 0.9em; color: #fff; display: flex; justify-content: space-between; }
.wrapper .row label { display: flex; align-items: center; gap: 5px; }
.wrapper .row a { color: #fff; text-decoration: none; }
.wrapper .options a:hover { text-decoration: underline; }
.wrapper .btn { width: 100%; height: 40px; background: #fff; outline: none; border: none; border-radius: 40px; cursor: pointer; font-size: 1em; font-weight: 500; color: #000; margin-top: 10px; } .btn:hover { background: #ffffea; }
.wrapper .signup-link { font-size: 0.9em; color: #fff; text-align: center; margin: 25px 0 10px; }
.wrapper .signup-link a { color: #fff; text-decoration: none; font-weight: 600; }
.wrapper .signup-link a:hover { text-decoration: underline; }
@media (max-width: 360px) { .wrapper { width: 100%; height: 100vh; border: none; border-radius: 0px; }
.wrapper .input-box { width: 290px; } #img { z-index: -90; } } </style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
<!--css file--> <link rel="stylesheet" href="styles.css" /> <head> <title>登录</title> </head> <body>
<div class="wrapper"> <form action="login.php" method="POST"> <h1>Login</h1> <div class="input-box"> <input type="text" name="username" id="usernameInput" required /> <label>Username</label> </div> <div class="input-box"> <input type="password" name="password" id="passwordInput" required /> <label>Password</label> </div> <button type="submit" class="btn">Login</button> <div class="signup-link"> <p>Don't have an account? <a href="register.php">Create one</a></p> </div> </form> </div> <script> document.addEventListener('DOMContentLoaded', function() { var loginMessage = "<?php echo isset($loginMessage) ? $loginMessage : ''; ?>"; if (loginMessage !== '') { alert(loginMessage); } }); </script> </body> </html>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
| //register.php <?php
include 'db.php';
// 处理用户注册 if ($_SERVER["REQUEST_METHOD"] == "POST") { $username = $_POST['username']; $password = $_POST['password'];
// 检查数据库中是否已经存在相同用户名的用户 $check_sql = "SELECT * FROM User WHERE username=?"; $stmt = $conn->prepare($check_sql); $stmt->bind_param("s", $username); $stmt->execute(); $check_result = $stmt->get_result();
if ($check_result->num_rows > 0) { $registerMessage = '用户名已存在,请选择其他用户名!'; } else { // 插入用户信息到数据库 // 使用准备语句插入用户信息到数据库 $sql = "INSERT INTO User (username, password) VALUES (?, ?)"; $stmt = $conn->prepare($sql); $stmt->bind_param("ss", $username, $password);
if ($stmt->execute()) { header("Location: login.php"); exit(); } else { $registerMessage = '注册失败!'; } } }
// 关闭数据库连接 $conn->close(); ?> <style> * { font-family: "Poppins", sans-serif; margin: 0; padding: 0; box-sizing: border-box; }
body { min-height: 100vh; display: flex; align-items: center; justify-content: center; background: #282a37; background-size: cover; background-position: center; }
.wrapper { position: relative; width: 400px; height: 450px; background: #3e404d; border: 2px solid rgba(255, 255, 255, 0.5); border-radius: 20px; display: flex; align-items: center; justify-content: center; backdrop-filter: blur(15px); } .wrapper:hover { box-shadow: 0 0 40px rgba(255,255,255,0.5); background: #46474e; }
.wrapper h1 { font-size: 2em; color: #fff; text-align: center; }
.wrapper .input-box { position: relative; width: 310px; margin: 30px 0; border-bottom: 2px solid #fff; }
.wrapper .input-box input { width: 100%; height: 50px; background: transparent; outline: none; border: none; font-size: 1em; color: #fff; padding: 0 40px 0 5px; }
.wrapper .input-box label { position: absolute; top: 50%; left: 5px; transform: translateY(-50%); font-size: 1em; color: #fff; pointer-events: none; transition: 0.5s; }
.wrapper .input-box input:focus ~ label, .wrapper .input-box input:valid ~ label { top: -5px; }
.wrapper .input-box .icon { position: absolute; right: 8px; color: #fff; font-size: 1.2em; line-height: 57px; }
.wrapper .row { margin: -15px 0 15px; font-size: 0.9em; color: #fff; display: flex; justify-content: space-between; }
.wrapper .row label { display: flex; align-items: center; gap: 5px; }
.wrapper .row a { color: #fff; text-decoration: none; }
.wrapper .options a:hover { text-decoration: underline; }
.wrapper .btn { width: 100%; height: 40px; background: #fff; outline: none; border: none; border-radius: 40px; cursor: pointer; font-size: 1em; font-weight: 500; color: #000; margin-top: 10px; } .btn:hover { background: #ffffea; }
.wrapper .signup-link { font-size: 0.9em; color: #fff; text-align: center; margin: 25px 0 10px; }
.wrapper .signup-link a { color: #fff; text-decoration: none; font-weight: 600; }
.wrapper .signup-link a:hover { text-decoration: underline; }
@media (max-width: 360px) { .wrapper { width: 100%; height: 100vh; border: none; border-radius: 0px; }
.wrapper .input-box { width: 290px; } #img { z-index: -90; } } </style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
<!--css file--> <link rel="stylesheet" href="styles.css" /> <head> <title>注册</title> <script> // JavaScript代码,根据注册消息显示弹窗 window.onload = function() { var registerMessage = "<?php echo $registerMessage; ?>"; if (registerMessage !== '') { alert(registerMessage); } }; </script> </head> <body> <div class="wrapper"> <form action="#" method="POST"> <h1>Register</h1> <div class="input-box"> <!--<i class="fas fa-envelope icon"></i>--> <input type="text" name="username" id="usernameInput" required /> <label>Username</label> </div> <div class="input-box"> <!--<i class="fas fa-lock icon"></i>--> <input type="password" name="password" id="passwordInput" required /> <label>Password</label> </div>
<button type="submit" class="btn">Register</button>
</form> </div> </body> </html>
|
二、数据库
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| //db.php <?php $servername = "localhost"; $username = "root"; $password = "root"; $dbname = "TGlu";
$conn = new mysqli($servername, $username, $password, $dbname);
// 检查数据库连接 if ($conn->connect_error) { die("数据库连接失败: " . $conn->connect_error); } ?>
|
1 2 3 4 5 6 7
| //run.sh #!/bin/sh
mysqld_safe --skip-grant-tables& sleep 20
mysql -uroot -proot < /TGlu.sql
|
sql文件直接从phpmyadmin导出,然后需要添加以下代码
1 2 3 4 5 6 7
| -- -- 数据库: `TGlu` --
drop database if exists `TGlu`; create database `TGlu` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; use TGlu;
|
三、设置后台界面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| //user.php <?php session_start();
// 检查用户是否登录,如果未登录则重定向到登录页面 if (!isset($_SESSION['username'])) { header("Location: login.php"); // 重定向到登录页面 exit(); }
$username = $_SESSION['username'];
// 连接数据库 include 'db.php';
if (isset($_GET['id'])) { $id = $_GET['id']; // 直接使用用户输入,允许 SQL 注入
// 构建 SQL 查询,允许联合注入 $sql = "SELECT flag FROM flag WHERE id = '$id' LIMIT 0,1"; $result = $conn->query($sql); $error = $conn->error;
// 获取查询结果 if ($result->num_rows > 0) { $data = $result->fetch_assoc(); echo $data['flag']; } else { echo "$error"; }
// 关闭数据库连接 $conn->close(); exit(); // 确保在返回 flag 值后停止脚本执行 } ?>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>主页</title> <style> .center-block { display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100vh; } .center-block h1 { margin-bottom: 20px; } </style> </head> <body> <div class="center-block"> <h1>Welcome, <?php echo htmlspecialchars($username); ?>!</h1> <button id="idButton">点击得到flag</button> <script> document.getElementById('idButton').addEventListener('click', function() { // 构建请求 URL const url = 'user.php?id=1';
// 发送 GET 请求 fetch(url) .then(response => response.text()) .then(data => { // 处理响应数据并显示弹窗 alert(data); // 改变地址栏 URL history.pushState(null, '', 'user.php?id=1'); }) .catch(error => { console.error('Error:', error); }); }); </script> </div> </body> </html>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| //admin.php <?php session_start();
// 检查用户是否登录,如果未登录则重定向到登录页面 if(!isset($_SESSION['username'])) { header("Location: login.php"); // 重定向到登录页面 exit(); }
$username = $_SESSION['username'];
// 检查用户是否是 admin if ($username !== 'admin') { header("Location: 404.html"); // 重定向到访问被拒绝页面 exit(); }
$flag = "Yunxi{123}";
?>
<!DOCTYPE html> <html lang="en"> <head> <title>主页</title> <style> .center-block { display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100vh; } .center-block h1 { margin-bottom: 20px; } </style> </head> <body> <div class="center-block"> <h1>Welcome, <?php echo $username; ?>!</h1> <p>This is the real flag <?php echo $flag; ?></p> </div> </body> </html>
|
四、设置主页和重定向
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| //index.php <!DOCTYPE html> <html> <head> <title>Redirect Example</title> <script> window.onload = function() { if (window.location.pathname === '/' || window.location.pathname === '/index.php') { window.location.href = '/login.php'; } }; </script> </head> <body>
</body> </html>
|
五、Dockerfile和docker-compose
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| //Dockerfile FROM ctftraining/base_image_nginx_mysql_php_73
COPY files /tmp/files/
COPY src /var/www/html/
COPY /files/flag.sh /flag.sh RUN chmod +x /flag.sh
RUN chown -R root:root /var/www/html/ && \ chmod -R 755 /var/www/html && \ mv /tmp/files/run.sh /run.sh && \ mv /tmp/files/TGlu.sql /TGlu.sql && \ chmod +x /run.sh && \ rm -rf /tmp/files/
RUN /run.sh
EXPOSE 80
|
1 2 3 4 5 6 7 8 9 10 11 12
| //docker-compose.yml version: "2"
services:
web: build: . restart: always ports: - "0.0.0.0:8087:80" environment: - FLAG=Yunxi{TGlu}
|
六、制作动态flag
1 2 3 4 5 6 7 8 9 10 11
| //flag.sh #!/bin/sh
sed -i "s/Yunxi{123}/$FLAG/g" /var/www/html/admin.php
# 覆盖掉环境变量,防止非预期 export FLAG=nonono FLAG=nonono
# 删除自身 rm -f /flag.sh
|
注:
如果使用的是Windows 编辑器,请确保保存文件时使用 Unix 风格的换行符(LF),而不是 Windows 风格的换行符(CRLF)。
