文件上传漏洞-upload靶场3-4关通关笔记(全网最详细解读)
upload 第三关(特殊后缀)
思路
按照第一关和第二关的思路,先随便上传一个文件用burpsuite工具抓包,看它到底是前段验证还是后端验证。
上传一个webshell,发现burpsuite拦截到一个请求包,确定了它是服务器后端验证,然后我们安装第二关的操作,修改MIME(content-Type)的值,实施能否上传成功。
修改MIME(Content-Type)的值后,发现任然无法上传成功,这种后端验证应该就不是验证MIME的值,可能是验证级别更高的方法,我们因为是学习upload上传漏洞,所以我们先分析后端源码,在找找办法。
源码分析
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {if (file_exists(UPLOAD_PATH)) {$deny_ext = array('.asp','.aspx','.php','.jsp');$file_name = trim($_FILES['upload_file']['name']);$file_name = deldot($file_name);//删除文件名末尾的点$file_ext = strrchr($file_name, '.');$file_ext = strtolower($file_ext); //转换为小写$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA$file_ext = trim($file_ext); //收尾去空if(!in_array($file_ext, $deny_ext)) {$temp_file = $_FILES['upload_file']['tmp_name'];$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext; if (move_uploaded_file($temp_file,$img_path)) {$is_upload = true;} else {$msg = '上传出错!';}} else {$msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';}} else {$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';}
}
由上面后端源码分析,可以判断它是一个黑名单验证,而且使用了trim()、strrchr()、strtolower()、str_ireplace()等函数加强了验证的可靠性。
trim()
函数用于删除文件名末尾的空格,确保文件名没有额外的空格导致验证错误。
strrchr()
函数用于从文件名中获取扩展名,这样可以检查文件的扩展名是否在黑名单数组中。
strtolower()
函数用于将文件扩展名转换为小写,以确保不受大小写的影响,从而更准确地与黑名单进行比较。
str_ireplace()
:用来去除文件扩展名中的 “::$DATA” 字符串。
以上后端源码的工作流程如下:
- 如果用户通过表单的 “submit” 提交按钮发送了POST请求,代码会执行文件上传逻辑。
- 首先,检查上传目录是否存在。如果存在,则继续执行,否则返回错误信息。
- 定义了一个拒绝上传的文件扩展名数组
$deny_ext
,其中包含了一些常见的危险文件扩展名(.asp, .aspx, .php, .jsp)。 - 从表单中获取上传文件的名称,并对其进行了一些处理,包括删除文件名末尾的点。
- 使用
strrchr
函数获取文件名中的扩展名,并将其转换为小写。 - 使用
str_ireplace
函数去除文件名中的字符串 “::$DATA”。 - 使用
trim
函数去除文件扩展名首尾的空格。 - 检查处理后的文件扩展名是否在拒绝上传的文件扩展名数组中。如果不存在于数组中,则继续执行下一步。
- 获取上传文件的临时路径,并根据时间戳和随机数生成一个新的文件名。
- 使用
move_uploaded_file
函数将临时文件移动到指定的上传目录,并将$is_upload
标志设置为 true。 - 如果文件移动失败,则返回错误信息。
- 最后,如果文件扩展名在拒绝上传的文件扩展名数组中,则返回相应的错误信息。
源码函数作用
- isset():检查变量是否已设置并且不是null。
- file_exists():检查文件或目录是否存在。
- trim():去除字符串两端的空格。
- $_FILES:一个包含上传文件信息的全局变量。
- strrchr():返回字符串中最后一次出现的指定字符(或子字符串)及其后面的所有字符。
- strtolower():将字符串转换为小写。
- str_ireplace():忽略大小写替换字符串中的子字符串。
- in_array():检查给定的值是否在数组中存在。
- move_uploaded_file():将上传的文件移动到新位置。
黑名单验证
我们从源码中分析出,他是一个后端黑名单验证,那么什么是黑名单呢?
所谓的黑名单就是差集,什么意思呢,用生活中的一个小例子说明一下:
假设您是一家公司的管理员,您有一份员工黑名单。这个黑名单列出了那些被认为不守规矩、有违公司政策或不受欢迎的员工。当这些员工试图访问某些公司资源或参加特定的公司活动时,他们将被禁止或拒绝。
也就是说,只要这个名单中有的名字,都无法正常上传,但是黑名单是一个不严谨的验证,只要我的文件或文件名不在这个黑名单当中,不就可以正常上传了,此外,黑名单验证还可能存在误判的风险。管理者可能会因配置不完善或缺乏经验而遗漏某些不受欢迎的输入,或者不小心将某些合法的数据列入黑名单中,导致合法用户被错误地拒绝访问或执行操作。
白名单验证
有黑名单,自然也有白名单,白名单也就是黑名单相反面,黑名单是在名单内的拒绝访问,那么白名单,它就是只有在名单内的才能访问,如果说我的心上人白名单只有一个人,那么除了她,任何人都不能进入我的心。
白名单是一种限制和过滤机制,只允许特定的事物通过,其他所有事物都被拒绝。它指定了可接受的选项或内容,并排除了其他所有选项。使用白名单意味着只有已明确定义的实体、操作或数据才能通过验证或访问特定的资源或系统。
相比之下,黑名单是一种列出禁止的事物列表,即排除某些特定的选项或内容。它是从已知的不可接受选项中移除特定的实体、操作或数据。然而,黑名单的缺点是可能会漏掉未知或新出现的不可接受选项,从而给安全性带来风险。
使用白名单机制有助于防止潜在的安全漏洞和攻击。通过只允许已知、可信任和明确定义的实体或操作来通过验证和授权,白名单可以提供更高的安全性和控制级别。它可以防止未知或意外的输入导致的安全问题,并减少攻击者滥用系统的可能性。
攻击思路
既然知道了黑名单的原理,我们就要来分析该如何进行攻击,在apache中间件中,能解析php的后缀不止.php。.php后缀只是在apache默认情况下使用,还有非常多的后缀也能去解析php文件,例如:
-
.php3
:在早期版本的PHP中,.php3
用作PHP脚本的后缀。尽管现在不太常见,但某些服务器仍然支持这个后缀。(从php5.3.0版本开始,默认禁用.php3
后缀解析) -
.php4
:与.php3
类似,.php4
也被一些服务器用作早期版本的PHP脚本的后缀。尽管现在已经较少使用,但某些服务器仍然支持它。(和.php3
一样,也是在php5.3.0版本之后默认禁用) -
.php5
:.php5
是一种用于指示PHP 5版本的后缀。某些服务器使用这个后缀来解析PHP 5代码。(目前也还是可以使用,不过也要看配置文件中是否禁用) -
.phtml
:.phtml
文件基本上是一个包含了PHP代码和HTML标记的混合文件。这种文件扩展名可以让开发者在同一个文件中编写和执行PHP代码,并将结果直接嵌入到HTML页面中。 -
还有非常多的后缀,但是总结起来它们都要经过apache的配置才能正常解析php文件
apache扩展知识:
在apache的配置文件(httpd.conf)中有一个AddType application/x-httpd-php 字段
只要在这个字段后添加的后缀,它都能正常去解析php文件,例如我在这里加入了一个
.abcd
的后缀,重启apache服务后,它就能正常解析php文件了。
在了解了关于apache解析php文件扩展名的知识后,我们可以使用burpsuite的Intruder模块,进行后缀名的爆破遍历。
上传一个后缀为php的文件,在用burpsuite进行抓包
把它发送到Intruder模块中进行爆破。
在Intruder模块中我们使用狙击手(sniper)模式,把php这个后缀添加一个payload变量进行暴力枚举。
这是我收集的较为常用的php解析名,用它作为payload进行枚举。
字节长度为4007的12个包均为上传失败的,他的的名字无论那个字母更换大写都无法通过验证,这是因为strtolower()
函数的影响,上传到服务器中的所有文件名都会,自动转换成小写,除了这12个文件上传失败,其他文件都上传成功,但是否能成功解析为php文件,还得看 Addtype application/x-httpd-php 是否把这个后缀名添加在内,由于我们已经知道了apache的配置,其中phtml就在能被解析的名单里,现在我们去尝试是否能成功解析。
从响应文件中找到它的路径为upload/202308291518502062.phtml。
解析成功,在这一关我们了解的php文件解析后缀名的原理,在后门的测试中,就不会在这么详细的去说了,我们上传文件的大概思路就是这样,后面的测试也是根据这些作为基础,去进一步的去扩展思路。
upload 第四关(.htaccess文件解析)
思路
第四关它是第三关的进一步的扩展,当用户对AddType application/x-httpd-php 做了比较严格的限制,例如我就随便写一个自定义的后缀能解析php文件,其他文件一概不能解析,那么我们就可以利用.htaccess文件解析,来绕过用户的限制。
分析源码
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {if (file_exists(UPLOAD_PATH)) {$deny_ext = array(".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");$file_name = trim($_FILES['upload_file']['name']);$file_name = deldot($file_name);//删除文件名末尾的点$file_ext = strrchr($file_name, '.');$file_ext = strtolower($file_ext); //转换为小写$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA$file_ext = trim($file_ext); //收尾去空if (!in_array($file_ext, $deny_ext)) {$temp_file = $_FILES['upload_file']['tmp_name'];$img_path = UPLOAD_PATH.'/'.$file_name;if (move_uploaded_file($temp_file, $img_path)) {$is_upload = true;} else {$msg = '上传出错!';}} else {$msg = '此文件不允许上传!';}} else {$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';}
}
这一串源码和第三关的源码差不多,也是一个黑名单验证,不过它对文件名的限制更多了,几乎包括所有常用的后缀名。但是在这里它没有限制.htaccess文件的上传,我们就可以通过.htaccess文件来进行绕过,
.htaccess文件说明
-
.htaccess
文件是一种用于在Apache服务器上配置网站的分布式配置文件。它允许在特定目录中设置特定的配置规则,而无需修改服务器的主配置文件。 -
.htaccess
文件通常用于实现URL重写、重定向、访问控制、自定义错误页面和其他相关的配置规则。它可以通过添加特定的指令来重写或补充默认的服务器配置,以实现特定网站的需求。 -
.htaccess
文件可以放置在网站根目录以及子目录中的任何位置。它的作用范围取决于其所在的目录及其子目录。-
当某个目录中存在
.htaccess
文件时,Apache会自动读取并应用该文件中的配置规则。这意味着您可以在网站根目录下以及其他子目录中创建不同的.htaccess
文件,针对不同的目录进行特定的配置。 -
.htaccess
文件的作用范围是所在目录及其所有子目录。如果在更高级别的目录中存在.htaccess
文件,它将逐级覆盖更低级别目录中的.htaccess
配置。 -
如果根目录下的
.htaccess
文件没有特定的配置规则,而网站文件目录下的.htaccess
文件有配置规则,则会执行网站文件目录下的.htaccess
文件中的配置。
-
开启、关闭.htaccess配置流程
确认Apache已启用
.htaccess
覆盖:在 Apache 主配置文件(如httpd.conf
)中,找到<Directory>
部分,确保AllowOverride
指令设置为All
(或相应的覆盖级别),以允许.htaccess
文件的配置规则生效。创建
.htaccess
文件:在您希望应用配置规则的目录中,创建一个新的文本文件,并将其命名为.htaccess
(注意文件名以.
开头,所以文件名前面是没有文件名前缀的)。编辑
.htaccess
文件:使用文本编辑器打开.htaccess
文件,并添加您希望应用的配置规则。可以使用各种可用的指令和选项来控制和定制网站的行为。保存
.htaccess
文件:保存您所做的更改,并将.htaccess
文件上传到您的网站目录中,以使其生效。将
AllowOverride
指令设置为None
,以禁止在该目录及其子目录中使用.htaccess
文件。
.htaccess 可配置的基本参数
.htaccess
文件可以用于配置多种参数和规则,以定制和控制 Apache 服务器的行为。以下是一些常见的配置参数示例:
URL 重写规则:使用
RewriteRule
指令可以定义自定义的 URL 重写规则,将复杂的 URL 路径转换为更友好和可读的格式。
简单举例:
- 简单的路径重写:
RewriteEngine On RewriteRule ^about$ about-us.html [L]
上述规则将将
/about
重定向到about-us.html
页面,使访问者可以更方便地访问关于页面。
- 带参数的重写:
RewriteEngine On RewriteRule ^products/([0-9]+)$ product.php?id=$1 [L]
上述规则将将类似
/products/123
的 URL 重写为product.php?id=123
,以便后台能够处理特定产品的请求,并且 URL 更加友好。
- 重定向到其他域名或页面:
RewriteEngine On RewriteRule ^old-page$ http://www.example.com/new-page [R=301,L]
上述规则将把来自
/old-page
的请求重定向到http://www.example.com/new-page
,并返回一个永久重定向的状态码301。这可以用于更新网站时保持旧链接的可用性。访问控制:使用
Require
或Order
指令可以限制对特定目录、文件或 IP 地址的访问。可以实现基于 IP 地址、用户认证等的访问权限控制。
简单举例:
- 基于 IP 地址的访问控制:
Order deny,allow Deny from 192.168.0.1 Allow from 10.0.0.0/24
上述规则指定了对特定 IP 地址的访问控制。对于IP地址
192.168.0.1
,访问将被拒绝;对于IP地址段10.0.0.0/24
,访问将被允许。您可以根据需要添加/修改允许或拒绝的 IP 地址或范围。
- 基于用户认证的访问控制:
AuthType Basic AuthName "Restricted Area" AuthUserFile /path/to/.htpasswd Require valid-user
上述规则实现了基本的用户认证。它要求用户提供有效的凭据才能访问受限区域。用户凭据通常存储在
.htpasswd
文件中。您可以使用htpasswd
工具来创建和管理这个文件。
- 按文件类型进行访问控制:
<Files "sensitive-file.php">Order allow,denyDeny from all </Files>
自定义错误页面:可以通过
ErrorDocument
指令定义自定义错误页面,以在特定错误发生时显示自定义的错误消息。
简单举例
- 定义404错误页面:
ErrorDocument 404 /errors/not-found.html
上述规则将指定在出现404错误(文件未找到)时显示
/errors/not-found.html
页面。
- 定义500错误页面:
ErrorDocument 500 /errors/server-error.html
上述规则将指定在发生500错误(服务器内部错误)时显示
/errors/server-error.html
页面。压缩和缓存控制:可以使用
mod_deflate
和mod_expires
模块的指令来启用和配置 HTTP 压缩和缓存控制,以提高网站性能。
简单举例
- 启用文本文件的压缩:
<IfModule mod_deflate.c># Enable compressionAddOutputFilterByType DEFLATE text/html text/plain text/xml# Set compression level (optional)DeflateCompressionLevel 6 </IfModule>
上述规则启用了对文本文件(如 HTML、纯文本和 XML)的压缩。使用
AddOutputFilterByType
指令将指定的 MIME 类型的文件进行压缩。您可以根据需要添加其他 MIME 类型。
- 启用缓存控制:
<IfModule mod_expires.c># Enable expiration headersExpiresActive On# Cache control for different file typesExpiresByType text/html "access plus 1 week"ExpiresByType image/png "access plus 1 month" </IfModule>
MIME 类型设置:使用
AddType
和AddHandler
指令可以关联特定的 MIME 类型和文件扩展名。
简单举例
- 设置文本文件的 MIME 类型:
AddType text/plain .txt AddType text/html .html .htm
上述规则将文件扩展名
.txt
关联到 MIME 类型text/plain
,将文件扩展名.html
和.htm
关联到 MIME 类型text/html
。这将告诉服务器如何正确地处理这些文件类型。
- 设置图像文件的 MIME 类型:
AddType application/x-httpd-php .php
上述规则将文件扩展名
.php
关联到 MIME 类型application/x-httpd-php
。这告诉服务器使用 PHP 解析器来处理带有.php
扩展的文件。
- 设置脚本文件的处理器:
AddHandler php-script .php
上述规则将文件扩展名
.php
关联到 PHP 处理器。这告诉服务器对于带有.php
扩展的文件,使用 PHP 解析器来处理和执行的脚本。强制 HTTPS:使用
RewriteCond
和RewriteRule
指令可以实现对网站或特定页面的强制 HTTPS 重定向。
简单举例:
- 强制整个网站使用 HTTPS:
RewriteEngine On RewriteCond %{HTTPS} off RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
上述规则将检查是否为HTTP连接(即非HTTPS),如果是,则重定向到相同的URL前面加上
https://
并使用301(永久重定向)。
- 强制特定页面使用 HTTPS:
RewriteEngine On RewriteCond %{HTTPS} off RewriteRule ^(secure-page\.html)$ https://%{HTTP_HOST}/$1 [L,R=301]
上述规则将只对 URL 中包含
secure-page.html
的页面进行重定向。如果连接非HTTPS,则重定向到同一页面的 HTTPS 版本。目录索引:使用
Options
指令可以控制网站目录中是否显示列表索引。
简单举例:
- 禁用目录索引:
Options -Indexes
上述规则将禁用目录索引,使访问一个目录而没有指定具体文件时,服务器不会显示该目录下的文件列表。
- 启用目录索引:
Options +Indexes
上述规则将启用目录索引,默认情况下,当访问一个目录而没有指定具体文件时,服务器会显示该目录下的文件列表。
这只是一些常见的用例示例,.htaccess
文件具有更广泛的功能,几乎可以对 Apache 服务器的各个方面进行定制和控制,.htaccess
文件提供了强大的配置能力,使我们能够对 Apache 服务器做出各种定制。通过适当的使用和配置.htaccess
文件,几乎可以控制 Apache 做出几乎任何事情。
攻击思路
由上所诉,.htaccess文件是一个非常强大的配置文件,用在文件上传上,简直就是杀鸡用牛刀,以下是一些潜在的安全风险。
- 重定向攻击:黑客可以修改重定向规则,将合法用户重定向到恶意站点,用于钓鱼攻击或分发恶意软件。
- 目录遍历攻击:黑客可以利用
.htaccess
文件来绕过服务器配置,实施目录遍历攻击,获取未授权的文件和目录访问权限。 - 认证漏洞:黑客可以修改身份验证规则,绕过用户认证或弱化访问控制,获取对受限资源的未授权访问。
- 恶意重写规则:黑客可以添加恶意的URL重写规则,将请求重定向到恶意代码,用于执行蠕虫、注入攻击或其他恶意活动。
- php解析:黑客可以修改解析后缀,来执行恶意webshell木马文件
了解到.htaccess
的强大,我们来继续尝试,如何通过第四关,第四关没有限制.htaccess
的上传,我们可以新建一个.htaccess
文件
它的意思为 后缀为.aaaa
的文件可以作为php文件在浏览器中被解析。
在上传一个后缀为.aaaa
后缀的webshell木马
全部都上传成功了,我们在看看后缀为.aaaa
的文件能否被正常解析
ok已经被正常解析了。能运行phpinfo()函数,也就说明它也能去执行其他php的代码。