Compare commits

...

13 Commits

47 changed files with 1516 additions and 52 deletions

21
LICENCE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Christos Choutouridis <cchoutou@ece.auth.gr>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

75
Readme.md Normal file
View File

@ -0,0 +1,75 @@
# Password Manager Security Assignment
## About
This repository contains an improved and secured version of a simplified web-based password manager.
The project was developed in the context of a university assignment on Aristotle's University of Thessaloniki(AUTh) Information Systems Security class.
The original application intentionally contained multiple security vulnerabilities.
The purpose of this work was to identify, analyze, and mitigate these vulnerabilities using well-established security practices.
The application is implemented in PHP and uses a MySQL database for data storage.
The deployment is fully containerized using Docker and Docker Compose, ensuring reproducibility and ease of execution across different operating systems.
## Architecture Overview
The application is deployed as a multi-container system.
Each component has a clearly defined role and responsibility.
All services are isolated and communicate only through Docker-managed networks.
Components:
- Web Application (PHP)
- Database (MySQL)
- Reverse Proxy and HTTPS (Caddy)
## Deployment Instructions
The deployment process is identical for Linux and Windows.
The only requirement is a working Docker installation.
### Prerequisites
- Docker
- Docker Compose (included in modern Docker installations)
No additional software such as Apache, PHP, or MySQL is required on the host system.
### Deployment on Linux
1. Open a terminal.
2. Navigate to the project directory containing `docker-compose.yml`.
3. Run the following command:
```bash
docker compose up -d --build
```
4. Wait until all containers are built and started.
5. Access the application through your browser using: https://localhost
### Deployment on Windows
1. Install Docker Desktop for Windows.
2. Ensure that WSL2 is enabled (Docker Desktop will guide you automatically).
3. Open PowerShell or Command Prompt.
4. Navigate to the project directory containing docker-compose.yml.
5. Run the following command:
```bash
docker compose up -d --build
```
6. Once the containers are running, open a browser and navigate to: https://localhost
### Notes on Reproducibility
The use of Docker ensures that:
- The application behaves identically on all supported operating systems
- No manual configuration of web servers or databases is required
- Environment-specific issues are minimized
This approach allows evaluators to focus on the security aspects of the application rather than deployment complexity.
## Disclaimer
This project was developed solely for educational purposes.
It is provided "as is", without any express or implied warranties.
The author assumes no responsibility for any misuse, data loss, security incidents, or damages resulting from the use of this software.
This implementation should not be used in production environments.
All work, modifications, and security improvements are the sole responsibility of the author.

19
passman-dev/Caddyfile Normal file
View File

@ -0,0 +1,19 @@
# HTTP site: redirect everything to HTTPS
http://localhost {
redir https://{host}{uri} permanent
}
# HTTPS site
https://localhost {
reverse_proxy web:80
tls internal
# Optional: security headers (defense-in-depth)
header {
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "no-referrer"
}
}

93
passman-dev/Readme.md Normal file
View File

@ -0,0 +1,93 @@
# Password Manager Security Application
## Architecture Overview
The application is deployed as a multi-container system.
Each component has a clearly defined role and responsibility.
All services are isolated and communicate only through Docker-managed networks.
## Components
### Web Application (PHP)
The web service hosts the PHP-based password manager application.
It is responsible for:
- User authentication and session handling
- Secure storage and retrieval of credentials
- Input validation and output sanitization
- Interaction with the database through restricted credentials
The PHP application runs inside its own container and does not expose any ports directly to the host system.
### Database (MySQL)
The database service provides persistent storage for:
- User accounts
- Stored credentials
- Application data
Security improvements include:
- Use of a dedicated database user with limited privileges
- Separation of database credentials via environment variables
- Isolation of the database service from direct external access
### Reverse Proxy and HTTPS (Caddy)
Caddy is used as a reverse proxy in front of the web application.
It provides:
- Automatic HTTP to HTTPS redirection
- Internal TLS certificate generation
- Secure termination of HTTPS connections
- Optional security-related HTTP headers
All external access to the application is handled exclusively by Caddy.
## Deployment Instructions
The deployment process is identical for Linux and Windows.
The only requirement is a working Docker installation.
### Prerequisites
- Docker
- Docker Compose (included in modern Docker installations)
No additional software such as Apache, PHP, or MySQL is required on the host system.
### Deployment on Linux
1. Open a terminal.
2. Navigate to the project directory containing `docker-compose.yml`.
3. Run the following command:
```bash
docker compose up -d --build
```
4. Wait until all containers are built and started.
5. Access the application through your browser using: https://localhost
### Deployment on Windows
1. Install Docker Desktop for Windows.
2. Ensure that WSL2 is enabled (Docker Desktop will guide you automatically).
3. Open PowerShell or Command Prompt.
4. Navigate to the project directory containing docker-compose.yml.
5. Run the following command:
```bash
docker compose up -d --build
```
6. Once the containers are running, open a browser and navigate to: https://localhost
### Notes on Reproducibility
The use of Docker ensures that:
- The application behaves identically on all supported operating systems
- No manual configuration of web servers or databases is required
- Environment-specific issues are minimized
This approach allows evaluators to focus on the security aspects of the application rather than deployment complexity.

View File

@ -22,6 +22,12 @@ CREATE TABLE IF NOT EXISTS `dummy` (
`id` int(11) DEFAULT NULL `id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Create a dedicated DB user for the web application (least privilege).
-- Grant only the required privileges on the application database.
CREATE USER IF NOT EXISTS 'passman_app'@'%' IDENTIFIED BY 'passman_app_pw';
GRANT SELECT, INSERT, UPDATE, DELETE ON pwd_mgr.* TO 'passman_app'@'%';
FLUSH PRIVILEGES;
CREATE TABLE IF NOT EXISTS `login_users` ( CREATE TABLE IF NOT EXISTS `login_users` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(20) NOT NULL, `username` varchar(20) NOT NULL,
@ -31,7 +37,7 @@ CREATE TABLE IF NOT EXISTS `login_users` (
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `login_users` (`id`, `username`, `password`) VALUES INSERT INTO `login_users` (`id`, `username`, `password`) VALUES
(1, 'u1', 'p1'); (1, 'u1', '$2y$10$L18u5/PyVkDgsce/DsUOQu0sKhTzh854Euhog3cVb1W4YAfgRzY8W'); -- php -r 'echo password_hash("p1", PASSWORD_DEFAULT), PHP_EOL;'
CREATE TABLE IF NOT EXISTS `notes` ( CREATE TABLE IF NOT EXISTS `notes` (
`notesid` int(11) NOT NULL AUTO_INCREMENT, `notesid` int(11) NOT NULL AUTO_INCREMENT,

View File

@ -2,18 +2,30 @@
services: services:
web: web:
build: . build: .
ports: # ports:
- "80:80" # - "80:80"
volumes: volumes:
- ./php:/var/www/html - ./php:/var/www/html
environment: environment:
DB_HOST: db DB_HOST: db
DB_USER: root
DB_PASS: rootpass
DB_NAME: pwd_mgr DB_NAME: pwd_mgr
DB_USER: passman_app
DB_PASS: passman_app_pw
depends_on: depends_on:
- db - db
proxy:
image: caddy:2
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
depends_on:
- web
db: db:
image: mariadb:11 image: mariadb:11
container_name: passman_db container_name: passman_db
@ -30,4 +42,6 @@ services:
volumes: volumes:
dbdata: dbdata:
caddy_data:
caddy_config:

View File

@ -3,8 +3,8 @@
// NOTE: In Docker, the DB host is the service name (e.g., "db"), not "localhost". // NOTE: In Docker, the DB host is the service name (e.g., "db"), not "localhost".
$DB_HOST = getenv('DB_HOST') ?: 'db'; $DB_HOST = getenv('DB_HOST') ?: 'db';
$DB_USER = getenv('DB_USER') ?: 'root'; $DB_USER = getenv('DB_USER') ?: 'passman_app';
$DB_PASS = getenv('DB_PASS') ?: 'rootpass'; $DB_PASS = getenv('DB_PASS') ?: 'passman_app_pw';
$DB_NAME = getenv('DB_NAME') ?: 'pwd_mgr'; $DB_NAME = getenv('DB_NAME') ?: 'pwd_mgr';
// Create a DB connection. // Create a DB connection.

View File

@ -99,16 +99,23 @@ $stmt->close();
//echo htmlspecialchars($username); //echo htmlspecialchars($username);
echo "<h3>Entries of " . $username . "</h3>"; $safe_username = htmlspecialchars($username, ENT_QUOTES | ENT_SUBSTITUTE, "UTF-8");
echo "<h3>Entries of " . $safe_username . "</h3>";
if (!empty($result) && $result->num_rows >= 1) { if (!empty($result) && $result->num_rows >= 1) {
while ($row = $result -> fetch_assoc()) { while ($row = $result -> fetch_assoc()) {
// Escape output to prevent stored XSS (DB content must be treated as untrusted).
$safe_url = htmlspecialchars($row["web_url"], ENT_QUOTES | ENT_SUBSTITUTE, "UTF-8");
$safe_user = htmlspecialchars($row["web_username"], ENT_QUOTES | ENT_SUBSTITUTE, "UTF-8");
$safe_pass = htmlspecialchars($row["web_password"], ENT_QUOTES | ENT_SUBSTITUTE, "UTF-8");
$webid_safe = (int)$row["webid"];
echo "<table border=0>"; echo "<table border=0>";
echo "<tr style='background-color: #f4f4f4;'><td colspan=2>" . $row["web_url"] . "</td></tr>" . echo "<tr style='background-color: #f4f4f4;'><td colspan=2>" . $safe_url . "</td></tr>" .
"<tr><td>Username: " . $row["web_username"] . "</td><td>Password: " . $row["web_password"] . "</td></tr>"; "<tr><td>Username: " . $safe_user . "</td><td>Password: " . $safe_pass . "</td></tr>";
echo "<tr><td><form method='POST' style='height: 3px'>" . echo "<tr><td><form method='POST' style='height: 3px'>" .
"<input type='hidden' name='websiteid' value='" . $row["webid"] . "'>" . "<input type='hidden' name='websiteid' value='" . $webid_safe . "'>" .
"<button type='submit' name='delete_website'>Delete</button></form></td></tr>"; "<button type='submit' name='delete_website'>Delete</button></form></td></tr>";
echo "<tr><td colspan=2 style=height: 20px;></td></tr>"; echo "<tr><td colspan=2 style=height: 20px;></td></tr>";

View File

@ -15,23 +15,23 @@
<br /> <br />
<ul> <ul>
<li> <li>
<a href="http://localhost/passman/register.php">Registration Form</a> <a href="/passman/register.php">Registration Form</a>
</li> </li>
<br /> <br />
<li> <li>
<a href="http://localhost/passman/login.php">Login Page</a> <a href="/passman/login.php">Login Page</a>
</li> </li>
<br /> <br />
<li> <li>
<a href="http://localhost/passman/logout.php">Logout Page</a> <a href="/passman/logout.php">Logout Page</a>
</li> </li>
<br /> <br />
<li> <li>
<a href="http://localhost/passman/dashboard.php">Dashboard</a> (display passwords for websites) <a href="/passman/dashboard.php">Dashboard</a> (display passwords for websites)
</li> </li>
<br /> <br />
<li> <li>
<a href="http://localhost/passman/notes.php">Notes</a> (notes/comments/announcements) <a href="/passman/notes.php">Notes</a> (notes/comments/announcements)
</li> </li>
<br /> <br />
</ul> </ul>
@ -41,18 +41,18 @@
<br /> <br />
<ul> <ul>
<li> <li>
Test <a href="http://localhost/passman/test_hash.php">hashing</a> functions in PHP (server side) Test <a href="/passman/test_hash.php">hashing</a> functions in PHP (server side)
</li> </li>
<br /> <br />
<li> <li>
Test <a href="http://localhost/passman/test_encrypt.php">encrypting/decrypting</a> functions in PHP (server side) Test <a href="/passman/test_encrypt.php">encrypting/decrypting</a> functions in PHP (server side)
</li> </li>
<br /> <br />
</ul> </ul>
<br /> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Hacker's side (for using stealing cookies using XSS): &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Hacker's side (for using stealing cookies using XSS):
<a href="http://localhost/passman/xss">http://localhost/passman/xss</a> <a href="/passman/xss">passman/xss</a>
<br /> <br />
</body> </body>

View File

@ -26,22 +26,30 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
// } // }
require_once __DIR__ . "/config.php"; require_once __DIR__ . "/config.php";
// Authentication with hashed passwords:
// 1) Fetch the stored hash by username
// SQL injection mitigation: use a prepared statement with bound parameters. // SQL injection mitigation: use a prepared statement with bound parameters.
// User input is treated strictly as data, not as part of the SQL syntax. // User input is treated strictly as data, not as part of the SQL syntax.
$stmt = $conn->prepare("SELECT id FROM login_users WHERE username = ? AND password = ?"); // 2) Verify the submitted password with password_verify()
$stmt = $conn->prepare("SELECT id, password FROM login_users WHERE username = ?");
if ($stmt === false) { if ($stmt === false) {
// Fail closed (do not leak details in production). // Fail closed (do not leak details in production).
die("Prepare failed."); die("Prepare failed.");
} }
$stmt->bind_param("ss", $username, $password); $stmt->bind_param("s", $username);
$stmt->execute(); $stmt->execute();
$stmt->store_result(); // Needed to use $stmt->num_rows
$result = $stmt->get_result(); // Requires mysqlnd (usually enabled)
unset($_POST['username']); unset($_POST['username']);
unset($_POST['password']); unset($_POST['password']);
if ($stmt->num_rows >= 1) { if ($result && $result->num_rows === 1) {
$row = $result->fetch_assoc();
$stored_hash = $row["password"];
// Verify password against the stored hash.
if (password_verify($password, $stored_hash)) {
// Regenerate session ID to prevent session fixation! // Regenerate session ID to prevent session fixation!
//session_regenerate_id(true); //session_regenerate_id(true);
@ -49,21 +57,18 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
$_SESSION['username'] = $username; $_SESSION['username'] = $username;
$_SESSION['loggedin'] = true; $_SESSION['loggedin'] = true;
//while ($row = $result -> fetch_assoc()) {
// print_r($row);
// $_SESSION['user_id'] = $row['id'];
//}
// Close
$stmt->close(); $stmt->close();
$conn->close(); $conn->close();
// Redirect to a dashboard page
header("Location: dashboard.php"); header("Location: dashboard.php");
exit; exit;
} else { } else {
$login_message = "Invalid username or password"; $login_message = "Invalid username or password";
} }
} else {
$login_message = "Invalid username or password";
}
$stmt->close(); $stmt->close();
$conn->close(); $conn->close();
} }

View File

@ -84,12 +84,17 @@ echo "<h3>List of notes/comments</h3>";
if (!empty($result) && $result->num_rows >= 1) { if (!empty($result) && $result->num_rows >= 1) {
while ($row = $result -> fetch_assoc()) { while ($row = $result -> fetch_assoc()) {
// Escape output to prevent stored XSS (DB content must be treated as untrusted).
$safe_note = htmlspecialchars($row["note"], ENT_QUOTES | ENT_SUBSTITUTE, "UTF-8");
$safe_user = htmlspecialchars($row["username"], ENT_QUOTES | ENT_SUBSTITUTE, "UTF-8");
echo "<div class='note'>"; echo "<div class='note'>";
echo "<div class='note-content'>" . $row["note"] . "</div>"; echo "<div class='note-content'>" . $safe_note . "</div>";
echo "<div class='note-signature'> by " . $row["username"] . "</div>"; echo "<div class='note-signature'> by " . $safe_user . "</div>";
echo "</div>"; echo "</div>";
} }
// Free result set // Free result set
$result -> free_result(); $result -> free_result();
} else { } else {

View File

@ -37,8 +37,17 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
$login_message = "Database error (prepare failed)."; $login_message = "Database error (prepare failed).";
$result = false; $result = false;
} else { } else {
$stmt->bind_param("ss", $new_username, $new_password); // Hash the password before storing it.
// Never store login passwords in plaintext.
$password_hash = password_hash($new_password, PASSWORD_DEFAULT);
if ($password_hash === false) {
$login_message = "Password hashing failed.";
$result = false;
} else {
// Store the hash (not the plaintext password).
$stmt->bind_param("ss", $new_username, $password_hash);
$result = $stmt->execute(); $result = $stmt->execute();
}
$stmt->close(); $stmt->close();
} }

View File

@ -0,0 +1,84 @@
<?php
// Simple example of encrypting/decrypting data using a password
function getPasswordHash_Bin($username, $password) {
$salt = hash('sha256', $username, true); // Compute salt as the hash of the username (parameter 'true' computes hash in bin format, default is hex)
$saltedPwd = $salt . $password; // Get a salted password by combining salt and password
$hashedPwd = hash('sha256', $saltedPwd, true); // Hash the salted password using SHA-256
// Return the password hash and the salt
return [
'hash' => $hashedPwd,
'salt' => $salt
];
}
function deriveEncryptionKey($username, $password) {
// Compute binary hash of salted-password (and salt) from username and password
$pwdHash = getPasswordHash_Bin($username, $password);
// Derive a secure key using PBKDF2
$iterations = 100000; // Number of iterations for PBKDF2
$keyLength = 32; // Key length = 32 bytes for AES-256
$key = hash_pbkdf2('sha256', $pwdHash['hash'], $pwdHash['salt'], $iterations, $keyLength, true); // Parameter 'true' computes hash_pbkdf2 in bin
return $key;
}
// Encrypt data using AES-256-GCM
function encryptData($data, $key) {
$nonce = random_bytes(12); // 12 bytes for AES-GCM nonce
$cipher = "aes-256-gcm";
// Encrypt the data
$ciphertext = openssl_encrypt($data, $cipher, $key, OPENSSL_RAW_DATA, $nonce, $tag);
//echo "nonce: " . bin2hex($nonce) . "<br>";;
//echo "tag: " . bin2hex($tag) . "<br>";;
// Concatenate nonce, tag, and ciphertext for storage
$result = $nonce . $tag . $ciphertext;
return base64_encode($result); // Encode to make it suitable for storage or transmission
}
// Decrypt data using AES-256-GCM, extracting nonce, tag, and ciphertext from the concatenated string
function decryptData($encryptedData, $key) {
$cipher = "aes-256-gcm";
// Decode the base64-encoded data
$encryptedData = base64_decode($encryptedData);
// Extract nonce (12 bytes), tag (16 bytes), and ciphertext
$nonce = substr($encryptedData, 0, 12);
$tag = substr($encryptedData, 12, 16);
$ciphertext = substr($encryptedData, 28);
// Decrypt the data
$decryptedData = openssl_decrypt($ciphertext, $cipher, $key, OPENSSL_RAW_DATA, $nonce, $tag);
return $decryptedData;
}
// Example Usage
$username = "user123";
$password = "securepassword";
$dataToEncrypt = "Sensitive Data";
// Derive a symmetric encryption/dec key by hashing the password (and username as the salt) using PBKDF2 algorithm
$encryptionKey = deriveEncryptionKey($username, $password);
// Encrypt the data
$encrypted = encryptData($dataToEncrypt, $encryptionKey);
// Decrypt the data
$decrypted = decryptData($encrypted, $encryptionKey);
// Display results
echo "Original Data: $dataToEncrypt<br>";
//echo "Encryption Key (in bin): " . $encryptionKey . "<br>";
//echo "Encryption Key (in hex): " . bin2hex($encryptionKey) . "<br>";
echo "Encrypted Data (in base64): " . $encrypted . "<br>";
//echo "Encrypted Data (in bin): " . base64_decode($encrypted) . "<br>";
//echo "Encrypted Data (in hex): " . bin2hex(base64_decode($encrypted)) . "<br>";
echo "Decrypted Data: $decrypted<br>";
?>

View File

@ -0,0 +1,46 @@
<?php
// Simple example of hashing password
$username = "user123";
$password = "securepassword";
// Compute salt as the hash of the username
$salt = hash('sha256', $username);
// Get a salted password by combining salt and password
$saltedPwd = $salt . $password;
// Hash the salted password using SHA-256
$hashedPwd = hash('sha256', $saltedPwd);
// Display variables
echo "Username: $username<br>";
echo "Password: $password<br>";
echo "Salt (computed as the username's hash): $salt<br>";
echo "Salted password: $saltedPwd<br>";
echo "Hash of salted password: $hashedPwd<br>";
echo "<p>";
// Same as above but using a function
function getPasswordHash_Hex($username, $password) {
// Compute hash of salted-password (and salt) from username and password (in hex format)
$salt = hash('sha256', $username); // Compute salt as the hash of the username
$saltedPwd = $salt . $password; // Get a salted password by combining salt and password
$hashedPwd = hash('sha256', $saltedPwd); // Hash the salted password using SHA-256
// Return the password hash and the salt
return [
'hash' => $hashedPwd,
'salt' => $salt
];
}
// Example usage of function getPasswordHash
$getHasedPwd = getPasswordHash_Hex($username, $password);
// Display results
echo "Salt (in hex) computed using function getPasswordHash_Hex: " . $getHasedPwd['salt'] . "<br>";
echo "Hash (in hex) computed using function getPasswordHash_Hex: " . $getHasedPwd['hash'] . "<br>";
?>

View File

@ -0,0 +1,3 @@
PHPSESSID=2c215dd41fe1090a5da5d0f3adc6ba64
PHPSESSID=2c215dd41fe1090a5da5d0f3adc6ba64

View File

@ -1,2 +0,0 @@
PHPSESSID=knjfug3u4gavdas9o4eupe38l1; seclab_user=u1
seclab_user=u1; PHPSESSID=o1mg400lipd2mck69kpfnl6p5s

BIN
report/img/https-Sample.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
report/img/sqli-DBquery.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
report/img/sqli-DBusers.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
report/report.pdf Normal file

Binary file not shown.

1079
report/report.tex Executable file

File diff suppressed because it is too large Load Diff