Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
S
Security in Container Environments
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Martinz, David
Security in Container Environments
Commits
a62fb6a3
Commit
a62fb6a3
authored
1 month ago
by
Martinz, David
Browse files
Options
Downloads
Patches
Plain Diff
added descriptions
parent
6de1a802
No related branches found
Branches containing commit
No related tags found
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
README.md
+55
-0
55 additions, 0 deletions
README.md
messaging-app/app/routes/auth.py
+38
-5
38 additions, 5 deletions
messaging-app/app/routes/auth.py
messaging-app/app/routes/messaging.py
+32
-2
32 additions, 2 deletions
messaging-app/app/routes/messaging.py
with
125 additions
and
7 deletions
README.md
+
55
−
0
View file @
a62fb6a3
...
...
@@ -28,6 +28,61 @@ Each branch contains a specific **hacklet** demonstrating a unique security vuln
---
### 📂 **Directory Structure**
```
bash
.
├── app
# Main application directory
│ ├── __init__.py
# App initialization (Flask app factory)
│ ├── routes
# Contains Flask route handlers (blueprints)
│ │ ├── auth.py
# Authentication routes (login, register)
│ │ ├── messaging.py
# Messaging routes (chats, file uploads)
│ │ └── __pycache__
# Compiled Python files (ignored by git)
│ └── uploads
# Directory to store uploaded files
│ ├── etc
# Directory for uploaded system files (exploit testing)
│ └── malicious.sh
# Example malicious file uploaded by an attacker
├── docker-compose.yml
# Docker Compose configuration for running the app
├── Dockerfile
# Dockerfile to build the container image
├── host_etc
# Host directory bind-mounted to the container (used in hacklet)
├── malicious.sh
# Exploit script for CVE-2024-21626 (container breakout)
├── requirements.txt
# Python dependencies for the app
├── run.py
# Main entry point to run the Flask app
├── templates
# HTML templates for the web app
│ ├── base.html
# Base template (common layout for all pages)
│ ├── chats.html
# Template for the chats page
│ ├── conversation.html# Template
for
conversation/chat window
│ ├── index.html
# Homepage template
│ ├── login.html
# Login page template
│ ├── macros.html
# Reusable UI components (e.g., flash messages)
│ ├── register.html
# Registration page template
│ └── send_file.html
# Template for sending files
└── uploads
# Directory to store user-uploaded files
├── malicious.sh
# Uploaded malicious shell script
└── reverse_shell.sh
# Reverse shell script uploaded by the attacker
```
---
### 🛠️ **How to Run the Web App**
1.
Clone the repository:
```
bash
git clone https://github.com/DFS-group/security-in-container-environments.git
cd
security-in-container-environments/messaging-app
```
2.
Build and run the Docker container:
```
bash
docker-compose up
--build
```
3.
Access the web app at:
```
http://localhost:5000
```
---
## 🛠️ **Tools and Techniques Used**
|
**Tool**
|
**Purpose**
|
...
...
This diff is collapsed.
Click to expand it.
messaging-app/app/routes/auth.py
+
38
−
5
View file @
a62fb6a3
...
...
@@ -2,12 +2,17 @@ from flask import Blueprint, render_template, request, redirect, url_for, flash
from
flask_login
import
login_user
,
logout_user
,
current_user
,
UserMixin
from
app
import
login_manager
# Define the authentication blueprint
# This blueprint handles routes related to user authentication (login, logout, registration)
auth_bp
=
Blueprint
(
'
auth
'
,
__name__
)
# In-memory user data
# In-memory user data storage
# This dictionary stores user information (username, ID, and password)
# Example: {"david": {"id": 1, "password": "1234"}}
users
=
{}
# User class
# Define a custom User class that extends Flask-Login's UserMixin
# This class represents a logged-in user
class
User
(
UserMixin
):
def
__init__
(
self
,
id
,
username
,
password
):
self
.
id
=
id
...
...
@@ -15,48 +20,76 @@ class User(UserMixin):
self
.
password
=
password
# User loader function for Flask-Login
# Flask-Login requires this function to retrieve the user object based on their ID
@login_manager.user_loader
def
load_user
(
user_id
):
"""
This function loads a user from the in-memory users dictionary
based on the user ID provided by Flask-Login.
"""
for
username
,
user
in
users
.
items
():
if
user
[
'
id
'
]
==
int
(
user_id
):
return
User
(
user
[
'
id
'
],
username
,
user
[
'
password
'
])
return
None
# Registration route
# Route to handle user registration
# Users can register by providing a username and password
@auth_bp.route
(
'
/register
'
,
methods
=
[
'
GET
'
,
'
POST
'
])
def
register
():
"""
Handles user registration.
- GET request: Displays the registration form.
- POST request: Processes the registration form and creates a new user.
"""
if
request
.
method
==
'
POST
'
:
username
=
request
.
form
.
get
(
'
username
'
)
password
=
request
.
form
.
get
(
'
password
'
)
if
username
in
users
:
# If the username already exists, show an error message
flash
(
'
Username already exists
'
,
'
register-danger
'
)
else
:
# If the username is new, add the user to the in-memory users dictionary
user_id
=
len
(
users
)
+
1
users
[
username
]
=
{
'
id
'
:
user_id
,
'
password
'
:
password
}
flash
(
'
Registration successful! Please log in.
'
,
'
login-success
'
)
return
redirect
(
url_for
(
'
auth.login
'
))
# Render the registration page
return
render_template
(
'
register.html
'
)
#
Login route
#
Route to handle user login
@auth_bp.route
(
'
/login
'
,
methods
=
[
'
GET
'
,
'
POST
'
])
def
login
():
"""
Handles user login.
- GET request: Displays the login form.
- POST request: Processes the login form and logs in the user if credentials are valid.
"""
if
request
.
method
==
'
POST
'
:
username
=
request
.
form
.
get
(
'
username
'
)
password
=
request
.
form
.
get
(
'
password
'
)
# Check if the provided username and password match an existing user
if
username
in
users
and
users
[
username
][
'
password
'
]
==
password
:
# Create a User object and log the user in
user
=
User
(
users
[
username
][
'
id
'
],
username
,
password
)
login_user
(
user
)
flash
(
'
Login successful!
'
,
'
index-success
'
)
return
redirect
(
url_for
(
'
messaging.index
'
))
else
:
# If login fails, show an error message
flash
(
'
Invalid username or password
'
,
'
login-danger
'
)
# Render the login page
return
render_template
(
'
login.html
'
)
#
Logout r
out
e
#
Route to handle user log
out
@auth_bp.route
(
'
/logout
'
)
def
logout
():
"""
Logs out the current user and redirects them to the login page.
"""
logout_user
()
flash
(
'
You have been logged out.
'
,
'
login-info
'
)
return
redirect
(
url_for
(
'
auth.login
'
))
This diff is collapsed.
Click to expand it.
messaging-app/app/routes/messaging.py
+
32
−
2
View file @
a62fb6a3
...
...
@@ -3,38 +3,53 @@ from flask_login import login_required, current_user
import
os
from
app.routes.auth
import
users
# Define the messaging blueprint for handling chat-related routes
messaging_bp
=
Blueprint
(
'
messaging
'
,
__name__
)
# Mock database for messages
# In-memory dictionary to store chat messages between users
# Format: {("user1", "user2"): [("sender", "message"), ...]}
messages
=
{}
# Directory to store uploaded files
UPLOAD_FOLDER
=
'
./uploads
'
# Ensure the upload folder exists when the app starts
if
not
os
.
path
.
exists
(
UPLOAD_FOLDER
):
os
.
makedirs
(
UPLOAD_FOLDER
)
# Route for the homepage
@messaging_bp.route
(
'
/
'
)
def
index
():
"""
Render the homepage.
"""
return
render_template
(
'
index.html
'
)
# Route to view and manage chats
@messaging_bp.route
(
'
/chats
'
,
methods
=
[
'
GET
'
,
'
POST
'
])
@login_required
def
view_chats
():
user_chats
=
set
()
"""
Displays a list of active conversations for the current user.
Allows starting a new conversation by selecting a user from a dropdown list.
"""
user_chats
=
set
()
# Stores the usernames of users the current user has chatted with
# Loop through all message participants to find active chats for the current user
for
participants
in
messages
.
keys
():
if
current_user
.
username
in
participants
:
other_user
=
participants
[
1
]
if
participants
[
0
]
==
current_user
.
username
else
participants
[
0
]
user_chats
.
add
(
other_user
)
# Handle form submission to start a new chat
if
request
.
method
==
'
POST
'
:
new_chat_user
=
request
.
form
.
get
(
'
username
'
)
if
new_chat_user
:
if
new_chat_user
==
current_user
.
username
:
# Prevent starting a chat with yourself
flash
(
'
You cannot start a conversation with yourself!
'
,
'
chats-danger
'
)
return
redirect
(
url_for
(
'
messaging.view_chats
'
))
if
new_chat_user
in
users
:
# Create a new conversation if it doesn't already exist
participants
=
tuple
(
sorted
((
current_user
.
username
,
new_chat_user
)))
if
participants
not
in
messages
:
messages
[
participants
]
=
[]
...
...
@@ -44,16 +59,25 @@ def view_chats():
flash
(
'
User not found!
'
,
'
chats-danger
'
)
return
redirect
(
url_for
(
'
messaging.view_chats
'
))
# Render the chats template with the list of users and active chats
return
render_template
(
'
chats.html
'
,
users
=
users
.
keys
(),
chats
=
list
(
user_chats
))
# Route to view a specific conversation between the current user and another user
@messaging_bp.route
(
'
/conversation/<username>
'
,
methods
=
[
'
GET
'
,
'
POST
'
])
@login_required
def
view_conversation
(
username
):
"""
Displays the chat history between the current user and the specified user.
Allows the current user to send new messages.
"""
# Sort participants alphabetically to create a unique key for the conversation
participants
=
tuple
(
sorted
((
current_user
.
username
,
username
)))
# Initialize a new conversation if it doesn't exist
if
participants
not
in
messages
:
messages
[
participants
]
=
[]
# Handle new message submission
if
request
.
method
==
'
POST
'
:
new_message
=
request
.
form
.
get
(
'
message
'
)
if
new_message
:
...
...
@@ -61,10 +85,16 @@ def view_conversation(username):
flash
(
'
Message sent!
'
,
'
conversation-success
'
)
return
redirect
(
url_for
(
'
messaging.view_conversation
'
,
username
=
username
))
# Render the conversation template with chat history
chat_history
=
messages
[
participants
]
return
render_template
(
'
conversation.html
'
,
username
=
username
,
chat_history
=
chat_history
)
# Route to download a file from the uploads folder
@messaging_bp.route
(
'
/uploads/<filename>
'
)
@login_required
def
download_file
(
filename
):
"""
Serves a file from the uploads directory.
Ensures that only authenticated users can download files.
"""
return
send_from_directory
(
UPLOAD_FOLDER
,
filename
)
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment