不安全的文件上传

client check

客户端检测

他说这里只允许上传图片,我们就看看这里的 HTML 语句,发现有一个 JS 代码限制了文件的类型。我们可以常识一下禁止 JS 代码或者修改 JS 代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

function checkFileExt(filename)
{
var flag = false; //状态
var arr = ["jpg","png","gif"];
//取出上传文件的扩展名
var index = filename.lastIndexOf(".");
var ext = filename.substr(index+1);
//比较
for(var i=0;i<arr.length;i++)
{
if(ext == arr[i])
{
flag = true; //一旦找到合适的,立即退出循环
break;
}
}
//条件判断
if(!flag)
{
alert("上传的文件不符合要求,请重新选择!");
location.reload(true);
}
}

我们采用了禁止 JS 代码运行,我直接上传了一句话木马,网页直接给我了相对位置了。

1
uploads/hack.php

然后用蚁剑去利用。

MIME type

MIME 是描述消息内容类型的标准。

https://www.runoob.com/http/mime-types.html

**MIME **类型通用结构

1
type/subtype

这里我们查看浏览器,为 POST 请求,还有一个multipart/form-data 是指定传输数据为二进制类型。

我们尝试一下抓包,内容如下

1
2
Content-Disposition: form-data; name="uploadfile"; filename="hack.png"
Content-Type: application/octet-stream

看到类型为 applicaiton/octet-stream 我们可以改成image/png 或者其他图片类型看看。

可以上传成功,我们用蚁剑去验证。

getimagesize

getimagesize 获取图片大小(用于看到底是不是图片的一个函数)

我们看 DOS 命令中的 copy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
COPY [/D] [/V] [/N] [/Y | /-Y] [/Z] [/L] [/A | /B ] source [/A | /B]
[+ source [/A | /B] [+ ...]] [destination [/A | /B]]

source 指定要复制的文件。
/A 表示一个 ASCII 文本文件。
/B 表示一个二进位文件。
/D 允许解密要创建的目标文件
destination 为新文件指定目录和/或文件名。
/V 验证新文件写入是否正确。
/N 复制带有非 8dot3 名称的文件时,
尽可能使用短文件名。
/Y 不使用确认是否要覆盖现有目标文件
的提示。
/-Y 使用确认是否要覆盖现有目标文件
的提示。
/Z 用可重新启动模式复制已联网的文件。
/L 如果源是符号链接,请将链接复制
到目标而不是源链接指向的实际文件。

命令行开关 /Y 可以在 COPYCMD 环境变量中预先设定。
这可能会被命令行上的 /-Y 替代。除非 COPY
命令是在一个批处理脚本中执行的,默认值应为
在覆盖时进行提示。

要附加文件,请为目标指定一个文件,为源指定
数个文件(用通配符或 file1+file2+file3 格式)。

copy 中的加号是用于将多个文件合并成一个文件的意思。

1
copy /b hack.php+2.jpg hack.jpg

发现图片大了

解决方法

  1. 修改 php.ini 文件
  2. 上传小图片

我这里尝试一下修改 php.ini 文件

查看 php.ini 位置,我们到 RCE 那章的 exec “eval”那节输入 phpinfo();

1
/etc/php/7.3/apacha2/php.ini

我们进入 pikachu Docker 容器

1
docker exec -it [容器ID] /bin/bash

我们通过 cd 找到文件,然后输入 vim php.ini,按下 i 编辑,去编辑,随便修改一下大小,最后按下 esc,再输入:wq,OK!

哈哈,终于可以上传图片了,不过还是失败了,这是咋回事?

我们用 010Editor 或者 winexe 查看文件的二进制和 16 禁止还有 ASCII 码看看。发现我们的 php 代码在前面,明显我们的 DOS 命令的顺序错误了,我们修改一下

![](../../img/docs/pikachu/Unsafe Fileupload/1738552548273-48cd6434-d9c6-48eb-9ed9-25962a10b3b1.png)

1
copy /b 2.jpg+ack.php hack.jpg

我们再次上传,我们发现应该是后端 getimagesize 设定是 512kb 的图片,又双叒叕踩坑了。

我可以放到蚁剑去检验,发现没用,因为它被后端框架被识别是图片,只会展示出来,我们需要用上之前节的文件包含,才会被识别为 php 代码。因为 Include 即使有报错也会往下运行,所以非常欧克。

1
http://192.168.17.129:8000/vul/fileinclude/fi_local.php?filename=file2.php&submit=%E6%8F%90%E4%BA%A4%E6%9F%A5%E8%AF%A2
1
unsafeupload/uploads/2025/02/03/72956067a035f759000198096914.png

=

1
http://192.168.17.129:8000/vul/fileinclude/fi_local.php?filename=../../unsafeupload/uploads/2025/02/03/72956067a035f759000198096914.png&submit=%E6%8F%90%E4%BA%A4%E6%9F%A5%E8%AF%A2

完美!