由00截断造成的文件读取(CVE-2023-47473分析)
For82 发表于 中国 漏洞分析 1684浏览 · 2024-01-08 09:00

鉴权分析

通过web.xml配置文件查看过滤器,所以路由都会经过SessionControl_UserLogin过滤器,

进入SessionControl_UserLogin过滤器,查看doFilter方法

其中有这么一段代码,这里的逻辑是创建一个迭代器,如果当前请求URI不在其中,会从会话中获取用户认证信息进行校验。如果当前请求URI在其中,则跳过校验。

在前面有定义默认的列表

也就是后缀为以上的url,将不会需要校验session。

漏洞点分析

那么我们可以把目标放在后缀为以上的代码中,我们可以发现getuploadimage.jsp代码其中包含image.jsp可以绕过SessionControl_UserLogin过滤器的校验。

查看其中代码,发现这是通过传入的图片URL,从文件中读取图片数据,并通过响应输出流返回给客户端的代码。

String imageURL = request.getParameter("imageURL");
    System.out.println(imageURL);
    if (!ValidateUtil.isNull(imageURL)) {
        try {
            String fileName = StringUtil.getFileName(imageURL);
            String fileType = StringUtil.getFileType(fileName, "unkown");
            if ("gif".equals(fileType) || "png".equals(fileType) || "bmp".equals(fileType) || "jpg".equals(fileType) || "jpeg".equals(fileType)) {

            } else {
                return;
            }
            response.setCharacterEncoding("UTF-8");
            response.resetBuffer();
            response.setContentType("image/jpeg");
            File uploadedFile = new File(imageURL);
            DataInputStream is = new DataInputStream(new FileInputStream(uploadedFile));
            DataOutputStream os = new DataOutputStream(response.getOutputStream());
            byte[] readBytes = new byte[128];
            int buffflag = -1;
            while ((buffflag = is.read(readBytes)) > -1) {
                os.write(readBytes, 0, buffflag);
            }
            os.close();
            is.close();
            os = null;
            response.flushBuffer();
            out.clear();
            out = pageContext.pushBody();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
        }
    }

通过分析代码,我们可以发现,String imageURL = request.getParameter("imageURL");imageURL是用户的请求,也就是我们可以控制。然后通过String fileName = StringUtil.getFileName(imageURL);

方法成为文件名。其中getFileName从\后获取文件名,然后将文件名丢进getFileType方法,进行文件类型的获取与校验。

public static String getFileName(String fileName) {
        int pos = fileName.lastIndexOf("\\");
        return pos > 0 ? fileName.substring(pos + 1) : fileName;
    }

    public static String getFileType(String fileName, String defaultType) {
        String fileType = "";
        if (fileName != null && fileName.length() > 0) {
            int i = fileName.lastIndexOf(46);
            if (i > -1 && i < fileName.length() - 1) {
                fileType = fileName.substring(i + 1).toLowerCase();
            }
        }

        if (!"pdf".equals(fileType) && !"doc".equals(fileType) && !"bmp".equals(fileType) && !"xls".equals(fileType) && !"exe".equals(fileType) && !"ppt".equals(fileType) && !"gif".equals(fileType) && !"html".equals(fileType) && !"xls".equals(fileType) && !"jpg".equals(fileType) && !"png".equals(fileType) && !"jpeg".equals(fileType) && !"xml".equals(fileType) && !"wav".equals(fileType) && !"wma".equals(fileType) && !"mp3".equals(fileType) && !"rar".equals(fileType) && !"txt".equals(fileType) && !"htm".equals(fileType) && !"zip".equals(fileType) && !"rm".equals(fileType) && !"swf".equals(fileType) && !"flv".equals(fileType) && !"docx".equals(fileType) && !"pptx".equals(fileType) && !"xlsx".equals(fileType)) {
            fileType = defaultType;
        }

        return fileType;
    }

这里我们可以发现对文件类型的判断十分严格,代码中会获取最后一个.的位置,然后进行转小写(防止大写绕过),然后进行判断,只要文件类型不在规定类型中就会被设置为defaultType也就是unkown类型。在前面的getuploadimage.jsp代码中存在判断语句。

if ("gif".equals(fileType) || "png".equals(fileType) || "bmp".equals(fileType) || "jpg".equals(fileType) || "jpeg".equals(fileType)) {

            } else {
                return;
            }

如果得到fileType不为其中的类型将无法执行后面的File uploadedFile = new File(imageURL)代码

,进行读文件的操作。那么这里是否存在方法使我们可以绕过对文件后缀名的判断,还不会影响到我们后续读文件的操作呢。在当前安装包中的jdk版本为1.7.0(最新版中已经变为jdk8并且没有Windows版本)。

而在JDK1.7.0_40之前的版本中是没有进行对\00进行检查,所以会造成00截断绕过。(也就是%00最终被解析cha(0),而在ASCII码0对应的为空字符,当在字符串中有空字符时会导致后面的字符被丢弃。)JDK1.7.0_40后新增检查

final boolean isInvalid(){
    if(status == null){
        status=(this.path.indexOf('\u0000')<0)?PathStatus.CHECKED:PathStatus.INVALID;
    }
    return status == PathStatus.INVALID;
}

从而达到getFileType文件后缀为图片,File(imageURL)读文件时图片后缀被丢弃。

我们便可以构造poc,只需要在想要读取的文件的后面加上%00图片文件名,就可以

修复建议

更换JDK版本为JDK1.7.0_40之后版本。

0 条评论
某人
表情
可输入 255