Compare commits

...

17 Commits

62 changed files with 1441 additions and 1 deletions

View File

@@ -2,4 +2,4 @@
Appliances used to build GNS3 labs.
This images are freely inspired from [Chewie's](https://github.com/Chewie/gns3-docker-appliances) ones
These images are freely inspired from [Chewie's](https://github.com/Chewie/gns3-docker-appliances) ones

View File

@@ -0,0 +1,7 @@
FROM php:8-apache-bullseye
COPY src /var/www/html
RUN mkdir /hidden_server
COPY hidden_server /hidden_server
COPY docker/start.sh /start.sh
EXPOSE 80
ENTRYPOINT ["/start.sh"]

View File

@@ -0,0 +1,8 @@
# Unsafe gallery challenge
You need to set the `FLAG` environment variable for this challenge to work!
## Run the image
```bash
docker run --rm --name beautiful_rfi --env FLAG='FLAG{UNSAFE_RFI}' -p 3578:80 -it pierre42100/gns3-appliance-beautiful-vuln-rfi
```

View File

@@ -0,0 +1 @@
sudo docker build -t pierre42100/gns3-appliance-beautiful-vuln-rfi .

View File

@@ -0,0 +1,10 @@
#!/bin/sh
echo Start hidden server
cd /hidden_server/
php -S 127.0.0.1:4567 &
cd
echo Run main server
docker-php-entrypoint apache2-foreground

View File

@@ -0,0 +1,2 @@
<?php
echo getenv("FLAG");

View File

@@ -0,0 +1 @@
I am an old and accustomed developer who wrote too much source code in his life...

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,3 @@
Welcome to this strong and almost secure website!
Please use the menu below to access the different parts of the application...

View File

@@ -0,0 +1,58 @@
<?php
/**
* My home page
*/
$page = "home.txt";
if (isset($_GET["page"]))
$page = $_GET["page"];
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= $page ?> - Beautiful RFI</title>
<link rel="stylesheet" href="/bootstrap.min.css">
</head>
<body>
<nav class="navbar navbar-expand-lg bg-dark" data-bs-theme="dark">
<div class="container-fluid">
<a class="navbar-brand" href="/">Beautiful VULN RFI</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarColor02"
aria-controls="navbarColor02" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarColor02">
<ul class="navbar-nav me-auto">
<li class="nav-item">
<a class="nav-link <?= $page === "home.txt" ? "active" : "" ?>" href="/?page=home.txt">Home</a>
</li>
<li class="nav-item">
<a class="nav-link <?= $page === "about.txt" ? "active" : "" ?>" href="/?page=about.txt">About</a>
</li>
<li class="nav-item">
<a class="nav-link <?= $page === "privacy.txt" ? "active" : "" ?>" href="/?page=privacy.txt">Privacy</a>
</li>
</ul>
</div>
</div>
</nav>
<h1 class="display-4 fw-normal text-body-emphasis" style="color: white !important; text-align: center;">
<?= str_replace(".txt", "", $page) ?>
</h1>
<pre style="max-width: 700px; margin: auto;">
<?php echo file_get_contents($page); ?>
</pre>
<script src="/bootstrap.bundle.min.js"></script>
</body>
</html>

View File

@@ -0,0 +1 @@
Privacy policy: TODO

11
countries_list/Dockerfile Normal file
View File

@@ -0,0 +1,11 @@
FROM php:8.3-apache
COPY src/ /var/www/html/
ENV FLAG=CHANGEME
COPY docker/start.sh /start.sh
COPY docker/add_flag.php /add_flag.php
EXPOSE 80
ENTRYPOINT ["/start.sh"]

8
countries_list/README.md Normal file
View File

@@ -0,0 +1,8 @@
# Unsafe login challenge
You need to set the `FLAG` environment variable for this challenge to work!
## Run the image
```bash
docker run --rm --name countries_list --env FLAG='FLAG{SQLIMYFRIENDAGAIN}' -p 3767:80 -it pierre42100/countries-list
```

1
countries_list/build.sh Normal file
View File

@@ -0,0 +1 @@
sudo docker build -t pierre42100/countries-list .

View File

@@ -0,0 +1,12 @@
<?php
// First, connect to database
try {
$db = new PDO('sqlite:/var/www/html/database.db');
} catch (PDOException $e) {
echo 'Connection to database failed: ' . $e->getMessage();
}
$stmt = $db->prepare("INSERT INTO secret (flag) VALUES (?)");
$stmt->execute(array(getenv("FLAG")));

View File

@@ -0,0 +1,7 @@
#!/bin/sh
echo Add flag to database
php /add_flag.php
echo Run main server
docker-php-entrypoint apache2-foreground

View File

@@ -0,0 +1,3 @@
<Files ~ "(.db)">
Require all denied
</Files>

6
countries_list/src/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -0,0 +1,68 @@
<?php
// First, connect to database
try {
$db = new PDO('sqlite:' . __DIR__ . '/database.db');
} catch (PDOException $e) {
echo 'Connection to database failed: ' . $e->getMessage();
}
$filter = isset($_GET["filter"]) ? $_GET["filter"] : "";
// Get the list of countries
$query = "SELECT * FROM countries_list WHERE full_name LIKE '%$filter%'";
$stmt = $db->prepare($query);
$stmt->execute(array());
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
?><!doctype html>
<html lang="en" data-bs-theme="auto">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Countries list</title>
<link href="/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<link href="/style.css" rel="stylesheet">
</head>
<body class="d-flex align-items-center py-4 bg-body-tertiary">
<main class="form-signin w-100 m-auto">
<h1>Countries list</h1>
<form action="/" method="get" style="margin: 30px 0px">
<div class="input-group flex-nowrap">
<span class="input-group-text" id="addon-wrapping">Filter by full name</span>
<input type="text" class="form-control" placeholder="Filter list by full name" aria-label="Filter by full name"
aria-describedby="addon-wrapping" value="<?=$filter?>" name="filter" />
<button class="btn btn-outline-secondary" type="submit" id="button-addon2">Filter</button>
</div>
</form>
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Full name</th>
</tr>
</thead>
<tbody>
<?php
foreach ($results as $row) {
?>
<tr>
<th scope="row"><?= $row["code"] ?></th>
<td colspan="2"><?= $row["full_name"] ?></td>
</tr><?php
}
?>
</tbody>
</table>
</main>
</body>
</html>

View File

@@ -0,0 +1,102 @@
html,
body {
height: 100%;
}
.form-signin {
max-width: 800px;
padding: 1rem;
}
.form-signin .form-floating:focus-within {
z-index: 2;
}
.form-signin input[type="email"] {
margin-bottom: -1px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
.form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
@media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
.b-example-divider {
width: 100%;
height: 3rem;
background-color: rgba(0, 0, 0, .1);
border: solid rgba(0, 0, 0, .15);
border-width: 1px 0;
box-shadow: inset 0 .5em 1.5em rgba(0, 0, 0, .1), inset 0 .125em .5em rgba(0, 0, 0, .15);
}
.b-example-vr {
flex-shrink: 0;
width: 1.5rem;
height: 100vh;
}
.bi {
vertical-align: -.125em;
fill: currentColor;
}
.nav-scroller {
position: relative;
z-index: 2;
height: 2.75rem;
overflow-y: hidden;
}
.nav-scroller .nav {
display: flex;
flex-wrap: nowrap;
padding-bottom: 1rem;
margin-top: -1px;
overflow-x: auto;
text-align: center;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
}
.btn-bd-primary {
--bd-violet-bg: #712cf9;
--bd-violet-rgb: 112.520718, 44.062154, 249.437846;
--bs-btn-font-weight: 600;
--bs-btn-color: var(--bs-white);
--bs-btn-bg: var(--bd-violet-bg);
--bs-btn-border-color: var(--bd-violet-bg);
--bs-btn-hover-color: var(--bs-white);
--bs-btn-hover-bg: #6528e0;
--bs-btn-hover-border-color: #6528e0;
--bs-btn-focus-shadow-rgb: var(--bd-violet-rgb);
--bs-btn-active-color: var(--bs-btn-hover-color);
--bs-btn-active-bg: #5a23c8;
--bs-btn-active-border-color: #5a23c8;
}
.bd-mode-toggle {
z-index: 1500;
}
.bd-mode-toggle .dropdown-menu .active .bi {
display: block !important;
}

4
hidden_header/Dockerfile Normal file
View File

@@ -0,0 +1,4 @@
FROM php:8.3-apache
COPY src/ /var/www/html/
ENV FLAG=CHANGEME

8
hidden_header/README.md Normal file
View File

@@ -0,0 +1,8 @@
# Unsafe login challenge
You need to set the `FLAG` environment variable for this challenge to work!
## Run the image
```bash
docker run --rm --name hidden_header --env FLAG='FLAG{HIDDEN_HEADER}' -p 3865:80 -it pierre42100/gns3-appliance-hidden-header
```

1
hidden_header/build.sh Normal file
View File

@@ -0,0 +1 @@
sudo docker build -t pierre42100/gns3-appliance-hidden-header .

View File

@@ -0,0 +1,13 @@
<?php
header("Flag: ".getenv("FLAG"));
?><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p>Hello world!</p>
</body>
</html>

8
js_login/Dockerfile Normal file
View File

@@ -0,0 +1,8 @@
FROM python:3.12
COPY src/ /web
COPY docker/start.sh /start.sh
RUN chmod +x start.sh
ENTRYPOINT ["/start.sh"]

8
js_login/README.md Normal file
View File

@@ -0,0 +1,8 @@
# JsLogin
Taken from: https://github.com/mazipan/login-page-css/tree/master/src/18-instagram
## Run the image
```bash
docker run --rm --name js_login --env FLAG='FLAG{JSLOGIN}' -p 3570:8080 -it pierre42100/unsafe-js-login
```

1
js_login/build.sh Normal file
View File

@@ -0,0 +1 @@
sudo docker build -t pierre42100/unsafe-js-login .

13
js_login/docker/start.sh Normal file
View File

@@ -0,0 +1,13 @@
#!/bin/sh
if [[ -z "${FLAG}" ]]; then
echo "Please set the FLAG environment variable!"
exit 1
fi
echo $FLAG > /web/flag.txt
echo "Starting HTTP server..."
cd /web
python3 -m http.server 8080

52
js_login/src/index.html Normal file
View File

@@ -0,0 +1,52 @@
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./styles.css" />
<title>Instagram clone</title>
<link rel="stylesheet" href="../shared/normalize.css">
<link rel="stylesheet" href="../shared/additional.css">
</head>
<body>
<main class="flex align-items-center justify-content-center">
<section id="auth" class="flex direction-column">
<div class="panel login flex direction-column">
<h1 title="Instagram" class="flex justify-content-center">
JsLogin
</h1>
<form id="loginForm">
<label for="email" class="sr-only">Phone number, username or email address</label>
<input id="email" name="email" placeholder="Phone number, username or email address" required />
<label for="password" class="sr-only">Password</label>
<input id="password" name="password" type="password" placeholder="Password" required />
<button type="submit" style="cursor:pointer;">Log In</button>
</form>
</div>
<div class="panel register flex justify-content-center">
<p>Don't have an account?</p>
<a href="#">Sign up</a>
</div>
<div class="foot" style="padding-top:50px">
<ul class="flex flex-wrap" style="font-size: .6em">
<li><a href="#">About</a></li>
<li><a href="#">Blog</a></li>
<li><a href="#">Jobs</a></li>
<li><a href="#">Help</li>
<li><a href="#">API</a></li>
<li><a href="#">Privacy</a></li>
<li><a href="#">Terms</a></li>
<li><a href="#">Top accounts</a></li>
<li><a href="#">Hashtags</a></li>
<li><a href="#">Locations</a></li>
</ul>
</div>
</section>
<script src="/script.js"></script>
</body>
</html>

12
js_login/src/script.js Normal file
View File

@@ -0,0 +1,12 @@
const form = document.getElementById("loginForm");
form.addEventListener("submit", (e) => {
e.preventDefault();
const email = document.getElementById("email").value;
const password = document.getElementById("password").value;
if (email === "sesame@ouvretoi.com" && password === "topsecret")
location.href = "/flag.txt";
else
alert("Invalid credentials, please try again!");
})

243
js_login/src/styles.css Normal file
View File

@@ -0,0 +1,243 @@
* {
border: none;
box-sizing: border-box;
font-family: Arial, Helvetica, sans-serif;
margin: 0;
padding: 0;
}
body {
background-color: #fafafa;
height: 100vh;
}
main {
height: 100vh;
margin: auto;
max-width: 935px;
}
a {
text-decoration: none;
}
h1 {
margin: 20px 0;
}
ul {
list-style: none;
}
/**
* Flex rules
*/
.flex {
display: flex;
}
.direction-column {
flex-direction: column;
}
.justify-content-center {
justify-content: center;
}
.align-items-center {
align-items: center;
}
.flex-wrap {
flex-wrap: wrap;
}
.panel {
background-color: white;
border: 1px solid #dbdbdb;
margin-bottom: 10px;
padding: 10px;
}
#auth {
max-width: 350px;
}
#mobile img {
height: 618px;
}
/**
* Login section
*/
.login-with-fb,
form {
width: 100%;
}
.register,
form {
padding: 30px 20px;
}
.login-with-fb {
padding: 30px 20px 20px;
}
form .sr-only {
display: none;
}
form input {
background-color: #fafafa;
border: 1px solid #dbdbdb;
border-radius: 3px;
color: #808080;
margin-bottom: 8px;
padding: 10px;
width: 100%;
}
form input::placeholder {
color: #808080;
}
form input:focus {
border: 1px solid #808080;
outline: none;
}
form button {
background-color: #0095f6;
border-radius: 5px;
color: #fff;
font-weight: bold;
height: 35px;
margin-top: 10px;
width: 100%;
}
/**
* Separator login form from login with fb
*/
.separator span {
background-color: #dbdbdb;
height: 1px;
width: calc(100% - 10px);
}
.separator .or {
color: #808080;
font-weight: bold;
}
.separator {
padding: 0 20px;
}
.separator span:first-child {
margin-right: 10px;
}
.separator span:last-child {
margin-left: 10px;
}
/**
* Login with fb section
*/
.login-with-fb a {
color: #385185;
}
.login-with-fb>a {
font-size: 12px;
}
.login-with-fb div a {
font-weight: bold;
}
.login-with-fb div {
margin-bottom: 15px;
}
/**
* Register section
*/
.register * {
font-size: 14px;
}
.register a {
color: #0095f6;
font-weight: bold;
}
.register p {
margin-right: 5px;
}
/**
* App download
*/
.app-download {
padding: 15px;
}
.app-download p {
padding: 10px 0;
}
.app-download img {
height: 40px;
margin: 0 5px;
}
/**
* Footer
*/
.foot {
margin: 0 auto 30px;
max-width: 935px;
}
.foot ul {
margin-bottom: 20px;
}
.foot ul li {
margin: 0 10px 10px;
}
.foot ul li a {
color: #385185;
}
.foot .copyright {
color: #808080;
}
.foot ul li a,
.foot .copyright {
font-weight: bold;
text-align: center;
text-transform: uppercase;
}
/**
* Media queries
*/
@media screen and (width <=767px) {
main {
margin: 30px auto 50px;
}
.foot .copyright,
.foot ul li a {
font-size: 13px;
}
}

4
oh_my_api/Dockerfile Normal file
View File

@@ -0,0 +1,4 @@
FROM php:8.3-apache
COPY src/ /var/www/html/
ENV FLAG=CHANGEME

8
oh_my_api/README.md Normal file
View File

@@ -0,0 +1,8 @@
# Unsafe gallery challenge
You need to set the `FLAG` environment variable for this challenge to work!
## Run the image
```bash
docker run --rm --name oh_my_api --env FLAG='FLAG{BROKEN_ACL}' -p 3569:80 -it pierre42100/gns3-appliance-oh-my-api
```

1
oh_my_api/build.sh Normal file
View File

@@ -0,0 +1 @@
sudo docker build -t pierre42100/gns3-appliance-oh-my-api .

1
oh_my_api/src/.htaccess Normal file
View File

@@ -0,0 +1 @@
Options -Indexes

131
oh_my_api/src/api.php Normal file
View File

@@ -0,0 +1,131 @@
<?php
$path = isset($_SERVER["PATH_INFO"]) ? $_SERVER["PATH_INFO"] : "/";
// First, connect to database
try
{
$db = new PDO('sqlite:'.__DIR__.'/database.db');
}
catch (PDOException $e)
{
echo 'Connection to database failed: ' . $e->getMessage();
}
// Check for supplied authentication
if(isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW']))
{
$user = $_SERVER['PHP_AUTH_USER'];
$pass = $_SERVER['PHP_AUTH_PW'];
$password_hash = hash("sha512", $pass);
$query = "SELECT * FROM users WHERE user = ? AND password = ?";
$stmt = $db->prepare($query);
$stmt->execute(array($user, $password_hash));
$res = $stmt->fetchAll();
if(count($res) === 0)
{
http_response_code(401);
echo "The specified credentials are invalid!";
exit(0);
}
$user = $res[0];
}
// Secure maintenance access
else if (isset($_GET["dev_user"]))
{
$user = ["user" => $_GET["dev_user"], "is_admin" => $_GET["dev_user"] === "fake_admin"];
}
header("content-type: application/json");
// Home page
if ($path === "/") {
echo "{\"msg\": \"Oh my API\"}";
exit(0);
}
// Get user information
else if($path === "/user")
{
?>{"user": "<?=$user["user"]?>", "admin": <?=$user["is_admin"]?"true":"false"?>}<?php
exit(0);
}
// Get the list of articles
else if($path === "/articles")
{
if(!isset($user))
{
http_response_code(401);
?>"Authentication required!"<?php
exit(0);
}
// Extract current user information
$stmt = $db->prepare("SELECT * FROM articles;");
$stmt->execute(array());
echo json_encode($stmt->fetchAll(PDO::FETCH_CLASS));
}
// Insert a new article
else if($path === "/insert_article")
{
if(!isset($user))
{
http_response_code(401);
?>"Authentication required!"<?php
exit(0);
}
if(!$user["is_admin"])
{
http_response_code(401);
?>"Only an admin can do that!"<?php
exit(0);
}
if(!isset($_POST["title"]) || !isset($_POST["content"]))
{
http_response_code(401);
?>"Some fields are missing!"<?php
exit(0);
}
$stmt = $db->prepare("INSERT INTO articles (published, time, title, description) VALUES (0, 0, ?, ?)");
$stmt->execute(array($_POST["title"], $_POST["content"]));
?>"Success!"<?php
}
// Get the secret flag
else if($path === "/flag")
{
if(!isset($user))
{
http_response_code(401);
?>"Authentication required!"<?php
exit(0);
}
if(!$user["is_admin"])
{
http_response_code(401);
?>"Only an admin can do that!"<?php
exit(0);
}
?>{"flag": "<?=getenv("FLAG")?>"}<?php
}
// 404 not found
else {
http_response_code(404);
echo "\"404 Not Found\"";
}

BIN
oh_my_api/src/database.db Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

16
oh_my_api/src/index.css Normal file
View File

@@ -0,0 +1,16 @@
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
margin: 0;
background: #fafafa;
}

21
oh_my_api/src/index.html Normal file
View File

@@ -0,0 +1,21 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer','GTM-PFFSBW3');</script>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" />
<link rel="stylesheet" type="text/css" href="index.css" />
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
</head>
<body>
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-PFFSBW3" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script src="./swagger-initializer.js" charset="UTF-8"> </script>
</body>
</html>

View File

@@ -0,0 +1,28 @@
window.onload = function() {
const defaultDefinitionUrl = "/swagger.yaml";
const ossServices = `petstore3.swagger.io=https://petstore3.swagger.io/api/v3/openapi.json,petstore31.swagger.io=https://petstore31.swagger.io/api/v31/openapi.json,petstore.swagger.io=https://petstore.swagger.io/v2/swagger.json,generator.swagger.io=https://generator.swagger.io/api/swagger.json,generator3.swagger.io=https://generator3.swagger.io/openapi.json,validator.swagger.io=https://validator.swagger.io/validator/openapi.json,oai.swagger.io=https://oai.swagger.io/api/openapi.json,converter.swagger.io=https://converter.swagger.io/api/openapi.json`;
const ossServicesTuples = ossServices.split(',').map(ossService => ossService.split('='))
const ossServiceMatch = ossServicesTuples.find(([host]) => window.location.host.includes(host))
const definitionURL = ossServiceMatch ? ossServiceMatch[1] : defaultDefinitionUrl;
//<editor-fold desc="Changeable Configuration Block">
window.ui = SwaggerUIBundle({
url: definitionURL,
"dom_id": "#swagger-ui",
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout",
queryConfigEnabled: true,
// validatorUrl: "https://validator.swagger.io/validator",
})
//</editor-fold>
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,74 @@
openapi: 3.0.3
info:
title: Oh My API
description: |-
Welcome to my articles services API
version: 1.0.0
servers:
- url: /api.php
paths:
/:
get:
tags:
- default
summary: API root
description: Get welcome message of API
responses:
'200':
description: Successful operation
/user:
get:
tags:
- default
summary: User info
description: Get information about current user
responses:
'200':
description: Successful operation
security:
- basicAuth: []
/articles:
get:
tags:
- articles
summary: Articles list
description: Get the list of articles of the database
responses:
'200':
description: Successful operation
security:
- basicAuth: []
/insert_article:
post:
tags:
- articles
summary: Insert a new article
description: Insert a new article in the database
requestBody:
required: true
content:
application/x-www-form-urlencoded:
schema:
type: object
properties:
title:
type: string
description: Article title
content:
type: string
description: Article content
responses:
'200':
description: Successful operation
security:
- basicAuth: []
components:
securitySchemes:
basicAuth:
type: http
scheme: basic

View File

@@ -0,0 +1,4 @@
FROM php:8.3-apache
COPY src/ /var/www/html/
ENV FLAG=CHANGEME

8
unsafe_gallery/README.md Normal file
View File

@@ -0,0 +1,8 @@
# Unsafe gallery challenge
You need to set the `FLAG` environment variable for this challenge to work!
## Run the image
```bash
docker run --rm --name unsafe_gallery --env FLAG='FLAG{UNSAFEGALLERY}' -p 3568:80 -it pierre42100/gns3-appliance-unsafe-gallery
```

1
unsafe_gallery/build.sh Normal file
View File

@@ -0,0 +1 @@
sudo docker build -t pierre42100/gns3-appliance-unsafe-gallery .

1
unsafe_gallery/src/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
uploads

View File

@@ -0,0 +1 @@
Options -Indexes

6
unsafe_gallery/src/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,96 @@
<?php
session_start();
// Assign unique session ID to the client
if (!isset($_SESSION["id"]))
$_SESSION["id"] = uniqid();
// Specify uploads target directory
define('UPLOAD_DIR', __DIR__ . "/uploads/" . $_SESSION["id"]);
if (isset($_FILES["file"])) {
$dest_file_name = (string) time() . "-" . str_replace("/", "", $_FILES["file"]["name"]);
// Create target directory
if (!is_dir(UPLOAD_DIR) && !mkdir(UPLOAD_DIR, 0770, true)) {
$error = "Failed to create storage directory!";
} else if ($_FILES["file"]["size"] > 500000) {
$error = "File is too large (max 500kb)!";
} else if (move_uploaded_file($_FILES["file"]["tmp_name"], UPLOAD_DIR . "/" . $dest_file_name)) {
$success = "The file was successfully uploaded!";
} else {
$error = "Error while uploading file!";
}
}
?><!doctype html>
<html lang="en" data-bs-theme="auto">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Safe gallery</title>
<link href="/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<link href="/style.css" rel="stylesheet">
</head>
<body class="d-flex align-items-center py-4 bg-body-tertiary">
<main class="form-signin w-100 m-auto">
<h1>Gallery manager</h1>
<div class="alert alert-secondary">
<strong>Note</strong> : Une information se cache dans la variable d'environnement <i>FLAG</i>.
</div>
<?php
if (isset($success)) {
?>
<div class="alert alert-success">
<?= $success ?>
</div><?php
}
if (isset($error)) {
?>
<div class="alert alert-danger">
<?= $error ?>
</div><?php
}
?>
<h2>Upload file</h2>
<form action="/" method="post" enctype="multipart/form-data">
<div>
<label for="formFile" class="form-label mt-4">Select image to upload</label>
<input class="form-control" type="file" id="formFile" name="file" required />
</div>
<div style="margin-top: 10px;">
<button type="submit" class="btn btn-primary">Perform upload</button>
</div>
</form>
<?php
if (is_dir(UPLOAD_DIR)) {
?>
<h2 style="margin-top: 50px;">Your files</h2>
<ul>
<?php
foreach (scandir(UPLOAD_DIR) as $f) {
if ($f === "." or $f === "..")
continue;
echo "<li><a href='uploads/" . $_SESSION['id'] . "/$f' target='_blank'>" . $f . "</a></li>";
}
?>
</ul><?php
}
?>
</main>
</body>
</html>

View File

@@ -0,0 +1,102 @@
html,
body {
height: 100%;
}
.form-signin {
max-width: 800px;
padding: 1rem;
}
.form-signin .form-floating:focus-within {
z-index: 2;
}
.form-signin input[type="email"] {
margin-bottom: -1px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
.form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
@media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
.b-example-divider {
width: 100%;
height: 3rem;
background-color: rgba(0, 0, 0, .1);
border: solid rgba(0, 0, 0, .15);
border-width: 1px 0;
box-shadow: inset 0 .5em 1.5em rgba(0, 0, 0, .1), inset 0 .125em .5em rgba(0, 0, 0, .15);
}
.b-example-vr {
flex-shrink: 0;
width: 1.5rem;
height: 100vh;
}
.bi {
vertical-align: -.125em;
fill: currentColor;
}
.nav-scroller {
position: relative;
z-index: 2;
height: 2.75rem;
overflow-y: hidden;
}
.nav-scroller .nav {
display: flex;
flex-wrap: nowrap;
padding-bottom: 1rem;
margin-top: -1px;
overflow-x: auto;
text-align: center;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
}
.btn-bd-primary {
--bd-violet-bg: #712cf9;
--bd-violet-rgb: 112.520718, 44.062154, 249.437846;
--bs-btn-font-weight: 600;
--bs-btn-color: var(--bs-white);
--bs-btn-bg: var(--bd-violet-bg);
--bs-btn-border-color: var(--bd-violet-bg);
--bs-btn-hover-color: var(--bs-white);
--bs-btn-hover-bg: #6528e0;
--bs-btn-hover-border-color: #6528e0;
--bs-btn-focus-shadow-rgb: var(--bd-violet-rgb);
--bs-btn-active-color: var(--bs-btn-hover-color);
--bs-btn-active-bg: #5a23c8;
--bs-btn-active-border-color: #5a23c8;
}
.bd-mode-toggle {
z-index: 1500;
}
.bd-mode-toggle .dropdown-menu .active .bi {
display: block !important;
}

4
unsafe_login/Dockerfile Normal file
View File

@@ -0,0 +1,4 @@
FROM php:8.3-apache
COPY src/ /var/www/html/
ENV FLAG=CHANGEME

8
unsafe_login/README.md Normal file
View File

@@ -0,0 +1,8 @@
# Unsafe login challenge
You need to set the `FLAG` environment variable for this challenge to work!
## Run the image
```bash
docker run --rm --name unsafe_login --env FLAG='FLAG{EASYINJECTION}' -p 3565:80 -it pierre42100/gns3-appliance-unsafe-login
```

1
unsafe_login/build.sh Normal file
View File

@@ -0,0 +1 @@
sudo docker build -t pierre42100/gns3-appliance-unsafe-login .

6
unsafe_login/src/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

220
unsafe_login/src/index.php Normal file
View File

@@ -0,0 +1,220 @@
<?php
session_start();
$user = NULL;
// First, connect to database
try
{
$db = new PDO('sqlite:'.__DIR__.'/database.db');
}
catch (PDOException $e)
{
echo 'Connection to database failed: ' . $e->getMessage();
}
// Check if user requested to be signed out
if(isset($_GET['sign_out']))
{
unset($_SESSION["user"]);
}
// Check for authentication
if(isset($_POST["user"]) && isset($_POST["password"]))
{
$username = $_POST["user"];
$password_hash = hash("sha512", $_POST["password"]);
$query = "SELECT * FROM users WHERE user = '$username' AND password = '$password_hash'";
$stmt = $db->prepare($query);
$stmt->execute(array());
$res = $stmt->fetchAll();
if(count($res) === 0)
$error = "The specified credentials are invalid!";
else {
$_SESSION["user"] = $res[0]["id"];
}
}
if(isset($_SESSION["user"]))
{
// Extract current user information
$stmt = $db->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute(array($_SESSION["user"]));
$user = $stmt->fetchAll()[0];
}
?><!doctype html>
<html lang="en" data-bs-theme="auto">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Safesys</title>
<link href="/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<style>
html,
body {
height: 100%;
}
.form-signin {
max-width: 330px;
padding: 1rem;
}
.form-signin .form-floating:focus-within {
z-index: 2;
}
.form-signin input[type="email"] {
margin-bottom: -1px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
.form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
@media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
.b-example-divider {
width: 100%;
height: 3rem;
background-color: rgba(0, 0, 0, .1);
border: solid rgba(0, 0, 0, .15);
border-width: 1px 0;
box-shadow: inset 0 .5em 1.5em rgba(0, 0, 0, .1), inset 0 .125em .5em rgba(0, 0, 0, .15);
}
.b-example-vr {
flex-shrink: 0;
width: 1.5rem;
height: 100vh;
}
.bi {
vertical-align: -.125em;
fill: currentColor;
}
.nav-scroller {
position: relative;
z-index: 2;
height: 2.75rem;
overflow-y: hidden;
}
.nav-scroller .nav {
display: flex;
flex-wrap: nowrap;
padding-bottom: 1rem;
margin-top: -1px;
overflow-x: auto;
text-align: center;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
}
.btn-bd-primary {
--bd-violet-bg: #712cf9;
--bd-violet-rgb: 112.520718, 44.062154, 249.437846;
--bs-btn-font-weight: 600;
--bs-btn-color: var(--bs-white);
--bs-btn-bg: var(--bd-violet-bg);
--bs-btn-border-color: var(--bd-violet-bg);
--bs-btn-hover-color: var(--bs-white);
--bs-btn-hover-bg: #6528e0;
--bs-btn-hover-border-color: #6528e0;
--bs-btn-focus-shadow-rgb: var(--bd-violet-rgb);
--bs-btn-active-color: var(--bs-btn-hover-color);
--bs-btn-active-bg: #5a23c8;
--bs-btn-active-border-color: #5a23c8;
}
.bd-mode-toggle {
z-index: 1500;
}
.bd-mode-toggle .dropdown-menu .active .bi {
display: block !important;
}
</style>
</head>
<body class="d-flex align-items-center py-4 bg-body-tertiary">
<main class="form-signin w-100 m-auto">
<?php
if($user === NULL) {
?><form method="POST" action="/">
<?php
if(isset($error))
{
?><div class="alert alert-danger">
<?=$error?>
</div><?php
}
?>
<h1 class="h3 mb-3 fw-normal">Please sign in</h1>
<div class="form-floating">
<input type="user" class="form-control" id="floatingInput" placeholder="user" name="user" required />
<label for="floatingInput">Username</label>
</div>
<div class="form-floating">
<input type="password" class="form-control" id="floatingPassword" placeholder="Password" name="password" required />
<label for="floatingPassword">Password</label>
</div>
<div class="form-check text-start my-3">
<input class="form-check-input" type="checkbox" value="remember-me" id="flexCheckDefault">
<label class="form-check-label" for="flexCheckDefault">
Remember me
</label>
</div>
<button class="btn btn-primary w-100 py-2" type="submit">Sign in</button>
<p class="mt-5 mb-3 text-body-secondary">&copy; 2025 Safesys</p>
</form><?php
}
else {
?><h3>Welcome <?=$user['user']?>! <a href='/?sign_out=1'>Sign out</a></h3><?php
if($user["is_admin"]) {
?><div class="alert alert-success">
Hey admin ! You can access the secret value: <?=getenv("FLAG")?>
</div><?php
}
else {
?><div class="alert alert-light">
You are not an administrator, you cannot access privileged information!
</div><?php
}
}
?></main>
</body>
</html>