欢迎关注公众号"漫漫安全路"每周更新代码审计、攻防渗透系列文章。
# 引子 这周本来没想好更新什么内容,写文件上传的示例代码时`AI`弹出一个提示,当时的代码提示如下。 ![](https://i-blog.csdnimg.cn/img_convert/3f486c7274ed68a694d710c7bb4bb250.png) 它这里想给我写一个文件上传的后缀白名单,此时我直接按下`tab`因为我想写黑名单于是把`jpg\jpeg`改为了`jsp\jspx`然后我意识到这样写是存在漏洞的,感觉有点意思于是写下这篇文章,总结一下做审计的过程中文件上传容易忽略的几种错误写法,以及黑盒测试中应该如何发现这类问题。 # 案例一 使用`AI`提示的判断改为黑名单代码如下 ``` <%@ page language="java" contentType="text/plain; charset=UTF-8" pageEncoding="UTF-8" trimDirectiveWhitespaces="true"%> <%@ page import="java.io.*" %> <%@ page import="java.util.*" %> <%@ page import="org.apache.commons.fileupload.*" %> <%@ page import="org.apache.commons.fileupload.disk.*" %> <%@ page import="org.apache.commons.fileupload.servlet.*" %>

<%
try {
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
String uploadPath = application.getRealPath(“/upload”);
File uploadDir = new File(uploadPath);
if (!uploadDir.exists()) {
uploadDir.mkdirs();
}

    List<FileItem> items = upload.parseRequest(request);
    for (FileItem item : items) {
        if (!item.isFormField() && item.getSize() > 0) {
            String originalName = item.getName();
            String extension = originalName.substring(originalName.lastIndexOf("."));
            if (extension.equals("jsp") || extension.equals("jspx")) {
                out.print("ERROR: 文件格式非法");
                return;
            }
            File targetFile = new File(uploadDir, originalName);
            item.write(targetFile);
            out.print("SUCCESS: " + originalName);
        }
    }

} catch (Exception e) {
    out.print("ERROR: " + e.getMessage());
}

%>

这么写如果开发者不经过测试会直接导致任意文件上传,因为当`originalName="1.jsp"`时`originalName.substring(originalName.lastIndexOf("."))`获取到的是带`.`的后缀`.jsp`而下面的判断是不带`.`会导致判断形同虚设。
![](https://i-blog.csdnimg.cn/img_convert/f0d4e570744d082d793a09842a445d01.png)
如果按照AI的代码写白名单那什么类型的文件都会上传失败。这类错误在实际审计过程中遇到过多次,最近一次遇到是在一个`.NET`项目里代码如下
![](https://i-blog.csdnimg.cn/img_convert/3cd4bb09dce3f4cd8d13c0bbc3d28d1e.png)
写法差不多`AI`可能真的是学多了垃圾代码导致自己也瞎写。
# 案例二
另外一种错误的黑名单写法

<%@ page language=“java” contentType=“text/plain; charset=UTF-8” pageEncoding=“UTF-8”%>
<%@ page import=“java.io." %>
<%@ page import="java.util.
” %>
<%@ page import=“org.apache.commons.fileupload." %>
<%@ page import="org.apache.commons.fileupload.disk.
” %>
<%@ page import=“org.apache.commons.fileupload.servlet.*” %>
<%@ page import=“java.util.UUID” %>

<%
try {
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
String uploadPath = application.getRealPath(“/upload”);
File uploadDir = new File(uploadPath);
if (!uploadDir.exists()) {
uploadDir.mkdirs();
}

    List<FileItem> items = upload.parseRequest(request);
    for (FileItem item : items) {
        if (!item.isFormField() && item.getSize() > 0) {
            String originalName = item.getName();
            if (originalName.indexOf(".jsp") > 0){
                out.print("ERROR: 文件格式非法");
                return;
            }
            String extension = originalName.substring(originalName.lastIndexOf("."));
            String randomName = UUID.randomUUID().toString() + extension;
            File targetFile = new File(uploadDir, randomName);
            item.write(targetFile);
            out.println("SUCCESS: " + originalName + " -> " + randomName);
        }
    }

} catch (Exception e) {
    out.print("ERROR: " + e.getMessage());
}

%>

这里直接使用`originalName.indexOf(".jsp") > 0`判断文件名中是否包含`.jsp`我估计有一部分审计人员可能认为是安全的,实际上是不安全的当`originalName=".jsp"`时`originalName.indexOf(".jsp")==0`依然可以上传`jsp`文件。
![](https://i-blog.csdnimg.cn/img_convert/994844543a2e1e9c1a36c8674d94a30c.png)

![](https://i-blog.csdnimg.cn/img_convert/5f9d5887df3a6ff4b8bcf965d26e4c46.png)
有朋友这几天正好遇到一个黑盒案例估计代码写的差不多
![](https://i-blog.csdnimg.cn/img_convert/46e55d30afe6a1d28cb1f0c1886fc2ea.png)
![](https://i-blog.csdnimg.cn/img_convert/32b3c8a19f4ab5c8a6b7dde87559bc6f.png)
所以以后不光审计需要注意,黑盒测试的时候遇到黑名单也可以使用`.jsp`试试
# 案例三
一种错误的白名单写法

<%@ page language=“java” contentType=“text/plain; charset=UTF-8” pageEncoding=“UTF-8” trimDirectiveWhitespaces=“true”%>
<%@ page import=“java.io." %>
<%@ page import="java.util.
” %>
<%@ page import=“org.apache.commons.fileupload." %>
<%@ page import="org.apache.commons.fileupload.disk.
” %>
<%@ page import=“org.apache.commons.fileupload.servlet.*” %>
<%@ page import=“java.util.UUID” %>

<%
try {
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
String uploadPath = application.getRealPath(“/upload”);
File uploadDir = new File(uploadPath);
if (!uploadDir.exists()) {
uploadDir.mkdirs();
}

    List<FileItem> items = upload.parseRequest(request);
    for (FileItem item : items) {
        if (!item.isFormField() && item.getSize() > 0) {
            String originalName = item.getName();
            if (originalName.indexOf(".zip") > 0){
                String extension = originalName.substring(originalName.lastIndexOf("."));
                String randomName = UUID.randomUUID().toString() + extension;
                File targetFile = new File(uploadDir, randomName);
                item.write(targetFile);
                out.print("SUCCESS: " + originalName + " -> " + randomName);
            }
            else {
				out.print("ERROR: 文件格式非法");
			}
        }
    }

} catch (Exception e) {
    out.print("ERROR: " + e.getMessage());
}

%>

这种写法在审计过程中也不少见,基本做审计的都可以看出来是任意文件上传。`originalName="1.zip.jsp"`即可
![](https://i-blog.csdnimg.cn/img_convert/e68ad810afc6e8f9e1b164d3a9bd1cb0.png)

![](https://i-blog.csdnimg.cn/img_convert/c2140eb259c25213a4da2afbe215159c.png)
这种在黑盒里挺常见的遇到过很多次,因为我黑盒测试任意文件上传的流程是先上传白名单后缀文件,比如`1.zip`如果可以上传我会直接测试`1.zipa`而不是`1.jsp`,测试`1.zipa`不行的话基本上就不行了,如果行的话大多数情况的可以shell。比如这个案例里`1.zipa`是行的然后我可能会直接测试`1.zip.jsp`即可成功`shell`
# 总结
白盒审计的时候需要注意黑名单/白名单逻辑是否严密,黑盒测试的话可以尝试`1.jpg.jsp\.jsp`这种文件名可能可以绕过某些错误的黑白名单判断。
`AI`写的代码也可能会出现漏洞,如果一种错误写法在网上很多的话`AI`可能被污染导致某类漏洞大规模出现。有的时候会想`AI`会不会让代码审计人员失业,从这个例子来说好像不会😄?



Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐