本文只说一些我遇到过的上传文件的漏洞。毕竟漏洞太多,我又不可能全部发现。
(安全方面的小菜鸟)
可能你们的系统比较完善,针对这些漏洞,已有相应的防御手段。我们针对的是那种比较简单的系统(就是各位上大学时自己开发的小系统,哈哈哈)。
利用漏洞的具体效果,就不演示了。本文只是提供一些思路和方向。
工具:我装了kali,使用 burpsuite;Linux环境下的VirtualBox
要配一下,burpsuite的 proxy-->options
自己去哔哩哔哩找一下资料了解一下burpsuite的使用。
漏洞一:直接上传jsp、php、jspx、exe等这种在黑名单的文件。上传成功后,可以使用冰蝎等webshell工具去getshell
如果系统没有对上传文件进行检测的话,直接上传这种带恶意代码的文件,再利用webshell的工具,就可以进入系统后台了。然后就可以做一些危险的事情:删除文件。
漏洞二:系统有个功能,编辑文件内容。写入新的内容后,点击提交,能修改文件内容。
我们可以写入恶意代码,然后用burpsuite 抓包,修改文件名。
点击放行。
漏洞三:系统中上传压缩包。上传成功后,系统会自动解压压缩包。这时,我们可以搞很多层深度的文件夹的压缩包(文件夹里有10000000层深度的文件夹);压缩包里有10000000000个文件;在压缩包中放非法文件(jsp/jspx/php等);上传的文件特别大(10G)
漏洞四:通过更改文件名后缀来绕过前端检测
.jspx改为 .html或者 .jpg
然后上传,用burpsuite抓包,再修改文件名后缀。
漏洞五:在图片中加入恶意代码,用文本编辑器打开,写东西
漏洞六:删除文件时,用burpsuite抓包,然后加一些特殊字符来删除其他目录下的文件
将"path":"/def.xml" 的文件修改为 "path":"../../../../../../XXXXX"
后面系统中会拼接出这样的路径(在生成File对象时用到的),
如果在/home/zcm目录下,恰好有 def.xml。
那么,就可以删除/home/zcm目录下的 def.xml。
"/home/zcm/workspace/git/DKEYAM/target/var/portal/realm/848e34b1-4829-4cdf-ac26-3afc7108cf81/login/mobile/../../../../../../../../../../def.xml"
如果将realm 改为 portal/文件夹中 一个不存在的文件夹名字,比如 no(随便起的),就找不到了。
即"/home/zcm/workspace/git/DKEYAM/target/var/portal/realm/848e34b1-4829-4cdf-ac26-3afc7108cf81/login/mobile/../../../../../../../../../../def.xml" 这个路径中的每一部分都要存在。
防御手段:(只说一下大体的思路)
因为是公司的代码,就不方便贴出来。就提示一些jar包吧。你们去查一下对应jar包的对应的类,有哪些方法,基本应该能搞定的。
先使用枚举类,记录文件格式的文件幻数与文件格式的映射。这个文件幻数是用来防止:
一个.jspx的文件,手动重命名为 .png 这种情况的。
可以通过文件幻数来,看出真实的文件名后缀(真实的后缀名不一定是表面上的文件名后缀)。
比如HTML的十六进制流
docx的
/**
* @Author: zcm
* @DateTime: 2021/10/22 下午5:20
* @Description:
* 各种格式的文件,经过一套特定的计算后,可以得到一个十六进制流。
* 这个十六进制流的开头的一小段,就是所谓的文件幻数。
* 不同格式的文件,它们十六进制流的开头的那一小段十六进制流是独特的,可以把这部分十六进制流当做ID,来识别对应的格式。
*/
public enum TrustFileType {
/* image */
JPEG("FFD8FFE0", ".jpg.jpeg"), // jpg
JPEG2("FFD8FFE1", ".jpg.jpeg"), // jpg
PNG("89504E47", ".png"), // png
GIF("47494638", ".gif"), // gif
/* 压缩包 */
RAR("52617221", ".rar"), // ARAR Archive
GZ("1F8B08", ".gz"), // gz
/* 办公文档类 */
XLS_DOCX("504B0304", "docx.pptx.xlsx.zip.jar"), // pptx、docx、xlsx; zip压缩文件的文件幻数也一样
RTF("7B5C727466", ".rtf"),
PDF("255044462D312E", ".pdf"),
/* 视频或音频类 */
MP4("49443303000000002176", ".mp4"), // mp4
/* 程序文件 */
XML("3C3F786D6C", ".xml"), // XML
HTML("3C21444", ".html"), // HTML
CSS("48544D4C207B0D0A0942", ".css"), // css
JS("696B2E71623D696B2E71", ".js"), // js
CLASS("CAFEBABE0000002E00", ".class"); // class
// JAVA("7061636B", ".java"), // java (任何时候禁止上传.java文件)
// JSP("3C254020", ".jsp"), // jsp (任何时候禁止上传.jsp文件)
// exe("4D5A9000", ".exe"), // exe (任何时候禁止上传.exe文件)
private String fileSuffix = "";
private String fileMagicNumber = "";
TrustFileType(String fileSuffix) {
this.fileSuffix = fileSuffix;
}
@Override
public String toString() {
return "TrustFileType{" +
"fileSuffix='" + fileSuffix + '\'' +
", fileMagicNumber='" + fileMagicNumber + '\'' +
'}';
}
TrustFileType(String fileSuffix, String fileMagicNumber) {
this(fileSuffix);
this.fileMagicNumber = fileMagicNumber;
}
public String getFileMagicNumber() {
return fileMagicNumber;
}
public String getfileSuffix() {
return fileSuffix;
}
}
//文件幻数的计算
InputStream is = File对象.getInputStream();
byte[] src = new byte[28];
is.read(src, 0, 28);
StringBuilder stringBuilder = new StringBuilder("");
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v).toUpperCase();
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
stringBuilder.toString()这个StringBuilder的开头一小段十六进制流,就是文件幻数。这一小段是多长,自己看着截取就好。反正能标识出对应的文件格式就好。
1、对于压缩包,要检测文件夹的深度、里面的文件数量、压缩包大小。
解压前先 遍历一波文件,就直接过滤一波表面上的文件名后缀。
解压后,
checkCompressedFileMaxDepthAndMaxCount
检测一下文件的深度,文件的数量。
然后,在逐个遍历检查每个File 对象的文件幻数。
最后,要删除解压出来的临时文件。
对于非法文件的处理,如果发现有非法文件或者其他异常,就统一抛出异常,在这个调用链的上层(就是URL直接访问到的那个方法体内)去捕获异常。
throw new RuntimeException("含有非法文件!操作失败。");
异常往上抛出,抛到URL访问的方法体中,在这个方法体中去 catch
import com.google.common.io.Files;
import org.apache.commons.io.FileUtils;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.lang3.StringUtils;
Files.createTempDir();
File.createTempFile
可以去这些包里面看看它们的方法,找找灵感。
2、对于图片中含有恶意代码
就搞个压缩函数,把这里面的代码打乱就好了。
3、对于含有特殊字符的文件路径(删除文件的方法)
/**
* @Author: zcm
* @DateTime: 2021/10/22 下午2:47
* @Params: [java.lang.String, java.lang.String]
* @Return boolean
* @Description: 检测文件名是否合法。比如“/../../../../../../../../../../def.xml”
* 这种就是不合法的。
* 先检测 . 的个数
* 再 将 dir目录下的文件名和filename 做比较。如果dir目录中没有这个filename,就返回 false
*/
public static boolean isLegalFileName(String dir, String fileName){
boolean isLegal = false;
//检测 . 字符是否超过1个
if (fileName.split("\\.").length > 1 ){
return isLegal;
}
File dirFile = new File(dir);
File[] files = dirFile.listFiles();
String name = fileName.substring(fileName.indexOf("/") + 1);
for (File i :files){
if (i.getName().equals(name)){
isLegal = true;
break;
}
}
return isLegal;
}
if (!SecureFileUtils.isLegalFileName(root.getAbsolutePath(), path)){
throw new RuntimeException("删除失败!存在非法路径!");
}