Compare commits

...

3 Commits

Author SHA1 Message Date
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
15 changed files with 291 additions and 0 deletions

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 unsafe_gallery --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