## https://sploitus.com/exploit?id=A38CD375-804A-57F8-8ADF-ADBE2565EF2D
# CVE-2020-13671
## RCE via File Upload β Drupal Core
**Software:** Drupal Core 8.7.5 (Affected: 7.x get('allow_insecure_uploads')
&& preg_match(FILE_INSECURE_EXTENSION_REGEX, $file->getFilename())
&& (substr($file->getFilename(), -4) != '.txt')) {
$file->setMimeType('text/plain');
$file->setFilename($file->getFilename() . '.txt');
}
```
If the filename matches the regex β change MIME to `text/plain` and append `.txt` at the end.
With `shell.phtml`:
- `preg_match('/\.(phar|php|pl|py|cgi|asp|js)(\.|$)/i', 'shell.phtml')` returns `0`
- No match β does not enter the if block β file retains its original name
Thus, this section should have blocked dangerous files, but because the regex **does not know** `.phtml` is dangerous, it slips right through.
### Layer 3 β `.htaccess` in the upload directory
Drupal places a `.htaccess` file in `sites/default/files/`:
```apache
SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006
SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003
php_flag engine off
```
The `php_flag engine off` directive turns off the PHP engine for the entire directory, but it only applies to `mod_php5`. Drupal 8.7.5 runs on PHP 7, meaning `mod_php7` is active and **not disabled**.
And `.htaccess` also has 3 other weaknesses:
- **Nginx** does not read `.htaccess` β this file is completely ineffective on Nginx
- Apache configured with **`AllowOverride None`** β `.htaccess` is ignored
- Servers using **PHP-FPM** instead of `mod_php` β the `php_flag` directive has no effect
## **Exploitation**
### **Step 1 β Create webshell**
```bash
echo '' > webshell.phtml
```
### **Step 2 β Upload file**
Log in to Drupal with an account that has upload permissions β Content β Add content β Article β in the Image field, select the file `webshell.phtml` β Upload.
Drupal accepts the file, does not rename it, and saves it with its original name into `sites/default/files/`.

### **Step 3 β Execute webshell**
After that, execute the shell call with `whoami`:

Thus, we have successfully achieved RCE as `www-data`.
Testing further to view credentials:

### **Result**
The attacker can read `settings.php` containing database credentials, dump the entire DB, install a reverse shell, or escalate privileges to root.
## Remediation
**Update regex** β add the 5 missing extensions:
```php
// Before:
'/\.(phar|php|pl|py|cgi|asp|js)(\.|$)/i'
// After:
'/\.(phar|php|pl|py|cgi|asp|js|phtml|php5|pht|phps|shtml)(\.|$)/i'
```
**Update `.htaccess`** β add disable for mod_php7:
```apache
php_flag engine off
```
The patch works but still relies on a blacklist. If new extensions emerge in the future (`.php8`, `.phpt`), the regex will need updating again. Whitelisting β only allowing known safe extensions β would be a more thorough approach.
## Summary
| **Vulnerable File** | `core/modules/file/file.module` line 28 |
| --- | --- |
| **Root Cause** | Regex blacklist is missing `.phtml`, `.php5`, `.pht`, `.phps`, `.shtml` |
| **Impact** | Upload `.phtml` β server executes β RCE |
| **3 Bypassed Defense Layers** | `file_munge_filename()` β `FILE_INSECURE_EXTENSION_REGEX` β `.htaccess` |
| **Patch** | Add 5 extensions to regex + disable mod_php7 in `.htaccess` |