Compare commits

..

8 Commits

Author SHA1 Message Date
556f377d20 Add new basic appliance 2025-02-03 16:40:21 +01:00
b65abf1f6a Fix Dockerimage command 2025-02-03 16:29:39 +01:00
46a95ff5a4 Create new challenge Docker image 2025-02-03 16:28:30 +01:00
c128870b93 New SQLi challenge 2025-02-03 16:17:28 +01:00
34275b0287 Fix README 2025-02-03 15:47:50 +01:00
0b3a7114a0 Change default docker port 2025-02-03 15:40:01 +01:00
aff7154458 Update API 2025-02-03 15:37:49 +01:00
72343063cd Start new challenge 2025-02-03 15:15:57 +01:00
29 changed files with 535 additions and 0 deletions

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>

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