文件上传漏洞 笔记

Pikachu靶场

Client check

Image

发现只能上传图片。

方法一

利用抓包软件Burpsuite。

先将要传入的phpinfo文件的后缀改为图片格式。

开启抓包软件

抓包成功后,将文件后缀名改回 .php

Image

上传成功

Image

验证一下

Image

成功

方法二

首先查看网页源代码

发现这段代码限制了文件的上传

Image

Image

找到该函数并删掉

Image

成功选择

MIME type

Image

方法一

同 client check 利用抓包软件,修改文件名后缀

方法二

首先了解一下$_FILES函数 和 MIME 机制

*$_FILES[‘myFile’][‘name’] 客户端文件的原名称。 *
*$_FILES[‘myFile’][‘type’] 文件的 MIME 类型,需要浏览器提供该信息的支持,例如”image/gif”。 *
*$_FILES[‘myFile’][‘size’] 已上传文件的大小,单位为字节。 *
*$_FILES[‘myFile’][‘tmp_name’] 文件被上传后在服务端储存的临时文件名,一般是系统默认。可以在php.ini的upload_tmp_dir 指定,但 用 putenv() 函数设置是不起作用的。 *
*$_FILES[‘myFile’][‘error’] 和该文件上传相关的错误代码。[‘error’] 是在 PHP 4.2.0 版本中增加的。下面是它的说明:(它们在PHP3.0以后成了常量) *

MIME*机制 使允许邮件处理文本,图片等多个不同类型的数据。*

MIME* 来描述标记数据类型**,在MIME扩展中使用一种叫 *多部分对象集合 的方法 来容纳多份不同类型的数据

多部分对象集合的对象有:

multipart/from-data

该对象在Web 表单文件上传时使用.

multipart/byteranges

该对象在 状态码 206响应报文包含了多个范围时使用。

PS:

在HTTP报文中使用多部分对象集合时,需要在首部字段里加上Content-type

使用 boundary 字符串来划分多部分对象集合指名的各类实体。

例:

Image

开始做题

查看源代码

Image

Image

此处用到了一个自定义的 upload_sick 函数 ,转到定义

Image

从此处 我们可以看到 该网页做判断的方法是 通过$_FILES 函数获取表单上传的 文件MIME类型 。

而该函数获取方式 是从报文中获取信息

所以利用抓包软件修改请求报文

Image

上传成功

Image

Getemagesize

getimagesize函数

getimagesize():它是php提供的,通过对目标文件的16进制进行读取,通过该文件的前面几个字符串,来判断文件类型。
getmagesize()返回结果中有文件大小和文件类型。

了解 文件头 和 文件包含漏洞 的一些相关知识

对于 不同格式的 图片文件,以二进制格式打开,其首部四个字节是用来标识文件格式

以 png 格式为例(引用了一下 胡宇轩 的笔记)

我们将一个png格式的图片文件用 010 editor打开后在它的文件头之后会有一个png文件的特有的数据块,每一个部分都有着它特殊的含义

而IHDR所有内容的表示按照顺序是这样表示的:

4字节宽度,4字节高度,1字节位深度,1字节颜色类型,1字节压缩方法,1字节滤波方法,1字节隔行扫描方法

Image

我们首先看前面 89 50 4E 47 丨 0D 0A 1A 0A 这八个字节所表示的就是PNG文件特有的二进制下的文件头,有他就表示有PNG文件。

文件包含漏洞,在 PHP中,当使用include() 函数包含文件时,只有代码执行到 include() 函数时才将文件包含进来,发生错误时只给出一个警告,继续向下执行。

开始做题

Image

这题 我们首先试试用抓包软件修改文件后缀名看看能不能过

Image

发现行不通

看看源代码,一步步找

Image

Image

Image

这时我们 可以** 伪造文件头**

通过系统自带的 copy指令

Image

生成的图片文件会在末尾接上代码

Image

上传成功

Image

想要使代码运行,需要使用到 文件包含漏洞

Image

Image

在最下面发现代码成功运行。

DVWA

LOW

没什么好说的,可以直接上传.php文件

Image

打开看一看,成功运行

Image

MEDIUM

利用burpsuite 抓包改文件后缀名

Image

成功上传

检查一下,没问题。

Image

然后 又改了一下 content-type ,发现还是可上传,猜想是根据MIME来验证

See see 源代码

Image

利用了文件的MIME类型进行判断。

High

直接抓包改后缀名显然不成功

Image

看看源代码

Image

利用和pikachhu的getemagesize的方法

先伪造木马头,上传后 利用 low 的文件包含漏洞打开运行代码

Image

Image

up-loadlabs

pass-01

Image

直接在浏览器中将 onsubmit属性给删了

Image

上传成功

Image

上传文件保存路径通过响应头得到是在 upload-labs\upload

测试一下

Image

成功

或者

利用抓包软件改文件后缀名也行

pass-02

用burpsuite抓下包,修改 首部content-type。

Image

上传成功

pass-03

先提一嘴 黑名单验证

后缀名检测:判断文件后缀名的检测方式。

后缀名检测的两种方式:黑名单与白名单。

  • 黑名单:定义上传的文件格式,如”php、jsp、zip、rar、tar等格式”,如果上传文件触发该规则,一律拦截不允许上传。

  • 白名单: 定义上传的文件格式,如”jpg、jpeg、png、gif、ico等格式”,如果上传文件不符合该规则,同样一律拦截不允许上传。

look look源码

Image

限制了后缀名,但是限制不严格

可以用 .phtml .phps .php5 .pht 来进行绕过

上传一个 .phps 文件

Image

成功上传。

另外,想要解析.phps等这类文件。需要在 apache 的 httpd.conf 中加一行 AddType application/x-httpd-php .php .phtml .phps .php5 .pht,否则显示空白页

pass-04

先了解 htaccess 文件

htaccess 文件是Apache服务器中的一个配置文件,他负责相关目录下的网页配置。通过htaccess文件,可以帮助我们实现:网页301重定向,自定义404错误页面,改变文件扩展名,允许或组织特定的用户或者,目录的访问,禁止目录列表,配置默认文档等功能。

.htaccess文件只能用于apahce,不能用于iisnginx等中间件

找到的一个参考网页apache .htaccess文件详解和配置技巧总结

开始做题

看看源代码

Image

列了一大堆 黑名单。改后缀名 是行不通了。

面对这种情况,我们可以 上传一个 .htaccess配置文件,

新建一个记事本,写入内容

Image

该段代码的意思是 当遇上文件名为 “1.jpg”的文件时,将其解析为.php文件

保存为.htaccess文件,上传该文件

Image

上传成功

在上转保存为 .jpg 文件的php文件,打开即可

由于 版本问题,我的无法显示

pass-05

前置知识

类似于.htaccess可以覆盖apache的配置文件,而.user.ini则可以覆盖php.ini的配置.

Ps:

  • .user.ini只能用于Server API为FastCGI模式下,而正常情况下apache不是运行在此模块下的

  • .htaccess和.user.ini都只能用于访问本目录下的文件时进行覆盖。

然鹅 .user.ini 并不能覆盖所有php.ini 属性,php.ini 属性分为四类:

  • PHP_INI_USER 可在用户脚本(例如 ini_set())或 Windows 注册表(自 PHP 5.3 起)以及 .user.ini 中设定

  • PHP_INI_PERDIR 可在 php.ini,.htaccess 或 httpd.conf 中设定

  • PHP_INI_SYSTEM 可在 php.ini 或 httpd.conf 中设定

  • PHP_INI_ALL 可在任何地方设定

但是实际上,只要不是**PHP_INI_SYSTEM模式下的属性,均可以在.user.ini**中设置

PHP 官网参考

Image

第一个为后置,第二个为前置

开始做题

查看源代码

Image

发现相较于pass4,把.htaccess屏蔽掉了。

但是我们可以转入 .user.ini 文件,在文件中写入 auto_prepend_file=1.gif

传入后,再转入木马文件,将文件名修改为 1.gif

注意: 在访问php文件时,才会自动包含1.gif

upload文件夹中自带了一个 readme.php 文件,打开该文件,代码成功运行

Image

pass-06

大小写过滤不严格

Image

利用burpsuite 抓包改后缀名

Image

成功传入。

用php 7.3.4打不开,有大小写敏感,换到5.3.29就能打开了

Image

pass-07

看看源代码,发现妹有 首尾去空。

Image

缺少

Image

于是利用burpsuite抓包,后缀名加空格

Image

上传成功

测试一下

Image

这个操作也只有PHP5才行的通

pass-08

看看源码

Image

没有删除点的操作,缺少

Image

于是利用burpsuite抓包,后缀名加点

Image

上传成功

测试一下

Image

成功

该操作也是只有在PHP5下行得通

pass-09(*)

了解一下:

如果文件名+“::$DATA”会把::$DATA之后的数据当成文件流处理,不会检测后缀名,且保持::$DATA之前的文件名,目的就是不检查后缀名

例如”webshell.php::$DATA”Windows会自动去掉末尾的::$DATA变成”webshell.php”

看看源码

Image

发现没有去除字符串::$DATA

Image

还是抓包改后缀名

Image

上传成功

测试一下

Image

成功,这个 PHP5 和PHP7 都行得通

pass-10

看看源码

Image

该过滤的全都有

但是,都是单次过滤

于是抓包改文件名加 “. .“过滤后剩一个点

Image

上传成功

测试一下

Image

成功,但只有在PHP5过的去,PHP7 move_uploaded_file($temp_file, $img_path 函数过不去

pass-11

注意:str_ireplace() 函数 是从前往后找

看看源码

Image

意思是 将 $deny_ext 中的敏感词全部过滤掉一遍

所以 将后缀名 改为 “.pphphp”,写两遍

Image

上传成功

测试一下

Image

pass-12

先了解 %00截断

在url中%00表示ascll码中的0 ,而ascii中0作为特殊字符保留,表示字符串结束,所以当url中出现%00时就会认为读取已结束

再补充两个函数

strrpos() 函数:查找字符串在另一字符串中最后一次出现的位置。

例:查找 “php” 在字符串中最后一次出现的位置:

Text
1
2
3
<?php
echo strrpos("You love php, I love php too!","php");
?>

注意:strrpos() 函数对大小写敏感

substr() 函数:返回字符串的一部分。

从字符串中返回 “world”:

Text
1
2
3
<?php
echo substr("Hello world",6);
?>

注意:如果 start 参数是负数且 length 小于或等于 start,则 length 为 0。

开始做题

先得把PHP版本调到5.3下,然后把magic_quotes_gpc关闭

看看源代码

Image

看到是用get方法得到初始路径

利用burpsuite抓包

这样改

Image

然后就上传成功了

基本思路是这样,我由于版本高了实现不了,不做展示

pass-13

看看源代码

Image

思路与pass12思路一样

但由于是采用的是post方法,所以要将**%00进行url编码后**加到末尾

pass-14

利用文件头伪造知识

文件头总结

跟pikachu靶场的第三题差不多

开始做题,看看源代码,发现读取文件前两个字节来做类型判断。

Image

于是利用系统自带的copy指令 合成一个木马图片。

Image

转入木马图片

Image

成功上传。

网站自带一个文件包含漏洞

Image

于是在地址栏输入 include.php?file=upload/服务器中文件名

Image

成功

pass-15

方法与 pass-14 相同,只是判断方式 变成了 用 getimagesize()函数,前面讲过,不再赘述。

Image

pass-16

了解 exif_imagetype 函数

exif_imagetype

(PHP 4 >= 4.3.0, PHP 5, PHP 7, PHP 8)

exif_imagetype — 判断一个图像的类型

说明** **

exif_imagetype(string $filename): int|false

exif_imagetype() 读取一个图像的第一个字节并检查其签名。

本函数可用来避免调用其它 exif 函数用到了不支持的文件类型上或和 $_SERVER[‘HTTP_ACCEPT’] 结合使用来检查浏览器是否可以显示某个指定的图像。

源码:

Image

用这个函数需要先把php配置改一下

pass-17

首先了解** 二次渲染**

二次渲染原理

在我们上传文件后,网站会对图片进行二次处理(格式、尺寸要求等),服务器会把里面的内容进行替换更新,处理完成后,根据我们原有的图片生成一个新的图片并放到网站对应的标签进行显示。

由Gif文件或 URL 创建一个新图象。成功则返回一图像标识符/图像资源,失败则返回false,导致图片马的数据丢失,上传图片马失败

开始做题

看看源码

Image

发现后端采用了二次渲染手段

我们尝试一下上一题的手段

Image

哒咩!行不通。

于是把原图和服务器修改过的图片进行比较,看看哪个部分没有被修改(利用脚本)。将php代码放到没有被更改的部分,配合包含漏洞

对于GIF 的上传,只需要判断没有修改的位置,然后将php代码添加即可

对于PNG的上传,需要修改PLTE数据块或者修改IDAT数据块,

该文章介绍了几种不同格式图片的绕过方式:【文件上传绕过】——二次渲染漏洞

将增强 后的图片再进行上传,结合文件上传漏洞,即可成功

Image

pass-18

先了解 条件竞争(爆破)

条件竞争是指一个系统的运行结果依赖于不受控制的事件的先后顺序。当这些不受控制的事件并没有按照开发者想要的方式运行时,就可能会出现bug。尤其在当前我们的系统中大量对资源进行共享,如果处理不当的话,就会产生条件竞争漏洞

就是如果并发处理不当或相关操作逻辑顺序设计的不合理,导致出现了漏洞

开始做题,看看源码

Image

这里的move_uploaded_file()函数在外面,意思是先上传后判断,于是我们可以利用这个上传的间隙去执行php文件

然后进行爆破

我是根据这篇文章里的步骤来的【文件上传绕过】——条件竞争漏洞

然后爆了好久出不来。。。

Image

不过方法是会了

pass-19

和pass-18一样

但是做了文件头的检测,上传改为图片格式上传即可

pass-20

先看看源码

Image

多了一个保存名字

方法一(版本低于5.3)

据源码,$img_path 是由$file_name组成,$flie_name又由 ‘savename’ 控制。

因此可以抓包使用 00截断

方法二

move_uploaded_file()有一个 忽略掉文件末尾的 /. 的特性。

抓包改 savename

Image

成功上传

测试一下

Image

成功

pass-21

先了解几个函数

explode() 函数

定义和用法

explode(separator,string,limit)

explode() 函数使用一个字符串分割另一个字符串,并返回由字符串组成的数组。

注释:“separator” 参数不能是一个空字符串。

注释:该函数是二进制安全的。

end() 函数:输出数组中最后一个元素的值

count() 函数****:返回数组中元素的数目

看看源码

Image

利用了白名单验证方法,

检测了MIME类型 -》修改 content-type

然后是对svename 进行分割,使其成为数组来验证,又因为是把最后一个元素拿出检测(end($flie))

所以预先抓包将 savename 作为数组上传

Image

上传成功

测试一下

Image

成功