diff --git a/owasp-top10-2021-apps/a5/insecure-file-upload/.gitignore b/owasp-top10-2021-apps/a5/insecure-file-upload/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/owasp-top10-2021-apps/a5/insecure-file-upload/Makefile b/owasp-top10-2021-apps/a5/insecure-file-upload/Makefile new file mode 100644 index 000000000..f69501466 --- /dev/null +++ b/owasp-top10-2021-apps/a5/insecure-file-upload/Makefile @@ -0,0 +1,37 @@ +.SILENT: +.DEFAULT_GOAL := help + +COLOR_RESET = \033[0m +COLOR_COMMAND = \033[36m +COLOR_YELLOW = \033[33m +COLOR_GREEN = \033[32m +COLOR_RED = \033[31m + +PROJECT := INSECURE FILE UPLOAD +PORT := 8080 + +## Installs a development environment +install: compose + +## Composes project using docker-compose +compose: compose-down + docker-compose -f deployments/docker-compose.yml up -d --build --force-recreate + +## Down project using docker-compose +compose-down: + docker-compose -f deployments/docker-compose.yml down + + +## Prints help message +help: + printf "\n${COLOR_YELLOW}${PROJECT}\n------\n${COLOR_RESET}" + awk '/^[a-zA-Z\-\_0-9\.%]+:/ { \ + helpMessage = match(lastLine, /^## (.*)/); \ + if (helpMessage) { \ + helpCommand = substr($$1, 0, index($$1, ":")); \ + helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \ + printf "${COLOR_COMMAND}$$ make %s${COLOR_RESET} %s\n", helpCommand, helpMessage; \ + } \ + } \ + { lastLine = $$0 }' $(MAKEFILE_LIST) | sort + printf "\n" \ No newline at end of file diff --git a/owasp-top10-2021-apps/a5/insecure-file-upload/README.md b/owasp-top10-2021-apps/a5/insecure-file-upload/README.md new file mode 100644 index 000000000..8d4248fe7 --- /dev/null +++ b/owasp-top10-2021-apps/a5/insecure-file-upload/README.md @@ -0,0 +1,124 @@ + + +# INSECURE FILE UPLOAD + +

+ +

+ +Insecure File Upload is a web laboratory written in PHP, with weak file upload validations. +A simple app that uploads files to the server’s public folder and displays a list of saved +files that can be viewed. + +This laboratory aims to demonstrate code execution on the server, a security flaw that +falls under A5 — Security Misconfiguration and A3 — Injection in the OWASP classification. + +## Index + +- [Definition](#definition) +- [Setup](#setup) +- [Attack narrative](#attack-narrative) +- [Objectives](#secure-this-app) +- [Solutions](#pr-solutions) +- [Contributing](#contributing) + +## What is Unrestricted File Upload? + +Unrestricted File Upload is a class of vulnerability that occurs when a web application accepts +and stores files from users without performing adequate validation, sanitization, or safe handling. +When file uploads are not properly checked (for type, content, name, storage location, and execution +permissions), an attacker can upload a crafted file that the server later interprets or executes — +for example, a PHP file disguised as an image. This can lead to remote code execution (RCE), local +file inclusion, information disclosure, or other severe compromises. + +## Setup + +To start this intentionally **insecure application**, you will need [Docker][docker install] and [Docker Compose][docker compose install]. After forking [secDevLabs](https://github.com/globocom/secDevLabs), you must type the following commands to start: + +```sh +cd secDevLabs/owasp-top10-2021-apps/a5/insecure-file-upload +``` + +```sh +make install +``` + +Then simply visit [http://localhost:8080][app] + +## Get to know the app :camera_flash: + +To properly understand how this application works, you can follow these simple steps: + +- Access the URL in your browser +- Click the Select Image button +- Choose a PNG image +- Click the Upload button +- Then the file list will update, and you can view the image by clicking the link icon + +## Attack narrative + +Now that you know the purpose of this app, what could possibly go wrong? The following section +describes how an attacker could identify and eventually find sensitive information about the app +or it's users. We encourage you to follow these steps and try to reproduce them on your own to +better understand the attack vector! 😜 + +### 👀 + +Upon accessing the page the attacker will see the following interface. They will then try to find a way to break the application. +A common flaw in applications is the lack of proper validation of user-submitted data. This allows an attacker to take advantage of it. + +

+ +

+ +### 🔥 + +The attacker then decides to see how the application works and, meanwhile, will try to think of a security +vulnerability during the process. When they select an image and click **Upload**, the file list will refresh +with the new file, as shown in the image below. + +

+ +

+ +Ok! Everything went well. In the file listing, when inspecting the page source code, the attacker notices that the image keeps its original name and was saved in the `/uploads` folder on the server. + +

+ +

+ +Ok! At this point the attacker gets an idea: "what if I upload a file named `hello.png.php`?" + +```sh +# hello.png.php + + +

+ +## Secure this app + +How would you migitate this vulnerability? After your changes, an attacker should not be able to: + +- Upload a file with an extension other than an image +- You will not be able to execute the code by accessing `/uploads/` + +## PR solutions + +- Issue still unresolved + + + +## Contributing + +We encourage you to contribute to SecDevLabs! Please check out the [Contributing to SecDevLabs](../../../docs/CONTRIBUTING.md) +section for guidelines on how to proceed! 🎉 + +[secDevLabs]: https://github.com/globocom/secDevLabs +[ExploitDB]: https://www.exploit-db.com/ diff --git a/owasp-top10-2021-apps/a5/insecure-file-upload/app/hello.png.php b/owasp-top10-2021-apps/a5/insecure-file-upload/app/hello.png.php new file mode 100644 index 000000000..33da5b24f --- /dev/null +++ b/owasp-top10-2021-apps/a5/insecure-file-upload/app/hello.png.php @@ -0,0 +1,2 @@ + + RewriteEngine On + RewriteBase / + + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + + diff --git a/owasp-top10-2021-apps/a5/insecure-file-upload/app/public/css/main.css b/owasp-top10-2021-apps/a5/insecure-file-upload/app/public/css/main.css new file mode 100644 index 000000000..2c61c7e0e --- /dev/null +++ b/owasp-top10-2021-apps/a5/insecure-file-upload/app/public/css/main.css @@ -0,0 +1,211 @@ +@import url('https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100..900;1,100..900&display=swap'); + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + + +html, :root { + + --background-color: #F3F4FF; + --white-color: #fff; + + --purple-400: #4D44B5; + + --red-400: #d82424; + --red-900: #830606; + + --green-400: #57d824; + --green-900: #108306; + + --gray-300: #dadada; + --gray-400: #313131; + + --blue-900: #303972; + +} + + +.app { + width: 100vw; + min-height: 100vh; + + display: flex; + align-items: center; + justify-content: center; + + padding: 30px; + + background-color: var(--background-color); +} + +.alert { + width: 100%; + + display: flex; + align-items: center; + gap: 10px; + + padding: 10px; + margin-bottom: 15px; + + font-family: Roboto, Arial; + font-weight: 600; + + border-radius: 10px; + border: 3px solid ; +} + +.alert.error { + background-color: var(--red-400); + border-color: var(--red-900); +} + +.alert.success { + background-color: var(--green-400); + border-color: var(--green-900); +} + +.container-uploads { + width: 100%; + max-width: 600px; + + padding: 20px; + border-radius: 20px; + + box-shadow: 0 0 10px var(--gray-300); + + background-color: var(--white-color); +} + +.upload-section { + flex: 1; +} + +.sections-container { + display: flex; + flex-direction: column; + gap: 50px; +} + +@media screen and (min-width: 1024px) { + .sections-container { + flex-direction: row; + } +} + +.hidden { + display: none; +} + +.title-form { + margin-bottom: 50px; + + color: var(--blue-900); + font-size: 18px; + font-family: Roboto, Arial; +} + +.files-uploaded { + list-style-type: none; + + display: flex; + flex-direction: column; + gap: 15px; +} + +.file-item { + display: flex; + align-items: center; + gap: 20px; + + font-family: Roboto, Arial; +} + +.file-item svg { + width: 40px; + height: 40px; +} + +.file-item div { + flex: 1; +} + +.file-item .file-title { + font-weight: bold; +} + +.file-item .file-size { + font-weight: normal; + font-size: 12px; + + color: var(--gray-400); +} + +.upload-area { + width: 100%; + min-height: 150px; + + border-radius: 16px; + padding: 20px; + border: 2px dashed var(--purple-400); + + display: flex; + flex-direction: column; + align-items: center; + + gap: 20px; + + font-family: Roboto, Arial; + text-align: center; +} + +.upload-area svg { + width: 50px; + height: 50px; +} + +.file-header { + width: 100%; + + display: flex; + align-items: center; + justify-content: space-between; +} + +.view-image svg { + width: 20px; + height: 20px; +} + +.button-container { + margin-top: 20px; +} + +.button-submit { + display: block; + margin: auto; + + width: 150px; + height: 40px; + + border: none; + border-radius: 10px; + + font-family: Roboto, Arial; + font-weight: bold; + + color: var(--white-color); + background-color: var(--purple-400); +} + +.empty-uploads { + display: flex; + align-items: center; + gap: 10px; + + font-family: Roboto, Arial; + color: var(--gray-400); +} diff --git a/owasp-top10-2021-apps/a5/insecure-file-upload/app/public/index.php b/owasp-top10-2021-apps/a5/insecure-file-upload/app/public/index.php new file mode 100644 index 000000000..3efa6dbf4 --- /dev/null +++ b/owasp-top10-2021-apps/a5/insecure-file-upload/app/public/index.php @@ -0,0 +1,143 @@ + number_format($fileSize, 2) . ' KB', + 'name' => $file, + 'link' => '/uploads/' . $file, + ]; + +} + +?> + + + + + + + + Sec Dev Labs - 2025 + + + + + + +
+
+ + +
+ + + + + + + +
+ + +
+
+
+ + + + +
+ +
+
+
+ +
+

Arquivos Processados:

+ +
    + +
  • + + + + + + +

    Nanhum arquivo encontrado

    +
  • + + + $file): ?> +
  • + + + + + + + +
    +
    +

    + + + + + + + +
    + +

    +
    +
  • + + + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/owasp-top10-2021-apps/a5/insecure-file-upload/app/public/upload.php b/owasp-top10-2021-apps/a5/insecure-file-upload/app/public/upload.php new file mode 100644 index 000000000..313432dd2 --- /dev/null +++ b/owasp-top10-2021-apps/a5/insecure-file-upload/app/public/upload.php @@ -0,0 +1,56 @@ + 'error', + 'content' => 'O arquivo não contem a extensão .png', + ]; + + header('Location: index.php'); + die(); +} + +$uploadFolder = __DIR__ . '/uploads/'; + +if (!is_dir($uploadFolder)) { + $_SESSION['message'] = [ + 'type' => 'error', + 'content' => 'Não foi possivel salvar o arquivo no disco', + ]; + + header('Location: index.php'); + die(); +} + +$uploadFileDestination = $uploadFolder . $fileUploadName; + + +if (!copy($fileUploadPath, $uploadFileDestination)) { + $_SESSION['message'] = [ + 'type' => 'error', + 'content' => 'Não foi possivel salvar o arquivo no disco', + ]; + + header('Location: index.php'); + die(); +} + +$_SESSION['message'] = [ + 'type' => 'success', + 'content' => 'Upload da imagem feito com sucesso!', +]; + +header('Location: index.php'); +die(); diff --git a/owasp-top10-2021-apps/a5/insecure-file-upload/deployments/Dockerfile b/owasp-top10-2021-apps/a5/insecure-file-upload/deployments/Dockerfile new file mode 100644 index 000000000..2b3b1b42f --- /dev/null +++ b/owasp-top10-2021-apps/a5/insecure-file-upload/deployments/Dockerfile @@ -0,0 +1,12 @@ +FROM php:8.2-apache + +RUN a2enmod rewrite + +COPY app/public /var/www/html/public +COPY deployments/apache.conf /etc/apache2/sites-available/000-default.conf + + +RUN mkdir -p /var/www/html/public/uploads +RUN chmod 775 /var/www/html/public/uploads + +RUN chown -R www-data:www-data /var/www/html diff --git a/owasp-top10-2021-apps/a5/insecure-file-upload/deployments/apache.conf b/owasp-top10-2021-apps/a5/insecure-file-upload/deployments/apache.conf new file mode 100644 index 000000000..dadf1e383 --- /dev/null +++ b/owasp-top10-2021-apps/a5/insecure-file-upload/deployments/apache.conf @@ -0,0 +1,11 @@ + + DocumentRoot /var/www/html/public + + + AllowOverride All + Require all granted + + + ErrorLog ${APACHE_LOG_DIR}/error.log + CustomLog ${APACHE_LOG_DIR}/access.log combined + \ No newline at end of file diff --git a/owasp-top10-2021-apps/a5/insecure-file-upload/deployments/docker-compose.yml b/owasp-top10-2021-apps/a5/insecure-file-upload/deployments/docker-compose.yml new file mode 100644 index 000000000..b18943de3 --- /dev/null +++ b/owasp-top10-2021-apps/a5/insecure-file-upload/deployments/docker-compose.yml @@ -0,0 +1,11 @@ +services: + php-insecure-file-upload: + build: + context: .. + dockerfile: ./deployments/Dockerfile + + ports: + - "8080:80" + + # volumes: + # - ../app/public:/var/www/html/public diff --git a/owasp-top10-2021-apps/a5/insecure-file-upload/images/img1.png b/owasp-top10-2021-apps/a5/insecure-file-upload/images/img1.png new file mode 100644 index 000000000..19fde96d9 Binary files /dev/null and b/owasp-top10-2021-apps/a5/insecure-file-upload/images/img1.png differ diff --git a/owasp-top10-2021-apps/a5/insecure-file-upload/images/img2.png b/owasp-top10-2021-apps/a5/insecure-file-upload/images/img2.png new file mode 100644 index 000000000..6ac4c70a8 Binary files /dev/null and b/owasp-top10-2021-apps/a5/insecure-file-upload/images/img2.png differ diff --git a/owasp-top10-2021-apps/a5/insecure-file-upload/images/img3.png b/owasp-top10-2021-apps/a5/insecure-file-upload/images/img3.png new file mode 100644 index 000000000..40e98a462 Binary files /dev/null and b/owasp-top10-2021-apps/a5/insecure-file-upload/images/img3.png differ diff --git a/owasp-top10-2021-apps/a5/insecure-file-upload/images/img4.png b/owasp-top10-2021-apps/a5/insecure-file-upload/images/img4.png new file mode 100644 index 000000000..6d4d819fa Binary files /dev/null and b/owasp-top10-2021-apps/a5/insecure-file-upload/images/img4.png differ