惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

雷峰网
雷峰网
月光博客
月光博客
S
Security Affairs
宝玉的分享
宝玉的分享
D
DataBreaches.Net
MongoDB | Blog
MongoDB | Blog
Cloudbric
Cloudbric
PCI Perspectives
PCI Perspectives
B
Blog RSS Feed
腾讯CDC
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Attack and Defense Labs
Attack and Defense Labs
N
News and Events Feed by Topic
T
The Blog of Author Tim Ferriss
H
Help Net Security
Vercel News
Vercel News
W
WeLiveSecurity
U
Unit 42
S
SegmentFault 最新的问题
Microsoft Azure Blog
Microsoft Azure Blog
Google Online Security Blog
Google Online Security Blog
云风的 BLOG
云风的 BLOG
Google DeepMind News
Google DeepMind News
S
Schneier on Security
The Register - Security
The Register - Security
酷 壳 – CoolShell
酷 壳 – CoolShell
Recent Announcements
Recent Announcements
博客园 - Franky
H
Hacker News: Front Page
WordPress大学
WordPress大学
I
Intezer
M
MIT News - Artificial intelligence
博客园 - 叶小钗
The Last Watchdog
The Last Watchdog
T
Troy Hunt's Blog
Stack Overflow Blog
Stack Overflow Blog
Microsoft Security Blog
Microsoft Security Blog
L
Lohrmann on Cybersecurity
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
I
InfoQ
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Schneier on Security
Schneier on Security
P
Proofpoint News Feed
V
V2EX
Help Net Security
Help Net Security
小众软件
小众软件
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
大猫的无限游戏
大猫的无限游戏
The GitHub Blog
The GitHub Blog
F
Fortinet All Blogs

SumSec's Blog

AI Agent 工程的必然演进:CLI、Skills、Harne… 从安全角度谈Java反射机制--前章 · SUMSEC 从安全角度谈Java反射机制--终章 · SUMSEC 逆向学习fastjson反序列化始 · SUMSEC 2020年研究回顾总结 · SUMSEC Abstract syntax tree classes for … Analyzing data flow in Java · SUM… Annotations in Java · SUMSEC Basic query for Java code · SUMSEC BypassSuper使用介绍说明 · SUMSEC CodeQL Create OpenJdk/Jdk8 Databa… CodeQL library for Java · SUMSEC Navigating the call graph · SUMSEC Overflow-prone comparisons in Jav… Types in Java · SUMSEC Working with source locations · S… Aliases · SUMSEC Expression · SUMSEC Formulas · SUMSEC Javadoc · SUMSEC Modules · SUMSEC Predicates · SUMSEC Queries · SUMSEC Type · SUMSEC Variables · SUMSEC 一道shiro反序列化题目引发的思考 · SUMSEC 修改ysoserial使其支持任意代码执行 · SUMSEC 自定义 ClassLoader 隔离运行不同版本jar包的方式 ·… 2020网鼎杯---Java文件上传wp · SUMSEC CNVD-2020-10487(CVE-2020-1938)tom… JDSRC安全课笔记 · SUMSEC Java反序列化链回显解决方案 · SUMSEC Skipped breakpoint because it hap… Windows Terminal 配置文件 · SUMSEC bypass 学习笔记之绕安全狗bypass safedog · … 一次意外的代码审计----JfinalCMS审计 · SUMSEC 一篇文章读懂Java代码审计之XXE · SUMSEC 从安全角度谈Java反射机制--序章 · SUMSEC 小楼昨夜又春风,你知ysoserial-Gadget-URLDNS… 春眠不觉晓,RCE知多少? · SUMSEC 漫谈Commons-Collections反序列化 · SUMSEC 漫谈Java反序列化 · SUMSEC 白头搔更短,SSTI惹人心! · SUMSEC 记一次面试题 · SUMSEC About Me 关于我 · SUMSEC Apache Flink任意Jar包上传导致远程代码执行 · SU… CVE-2019-1388 UAC提权复现 · SUMSEC CVE-2019-16097 || Harbor任意管理员注册漏洞… Python加密shellcode免杀 · SUMSEC Telegram机器人作为渗透测试框架 · SUMSEC VM虚拟机无法安装vmtools解决|本程序需要您将此虚拟机上安装… 谁能想到,电视遥控器竟成了 Vibe Coding 神器 · SU… 从手改 Skill 到自动进化:评测结果和执行轨迹如何让 Agen… 模型人人都能用,什么才是你能带走的?我的答案是一个可进化的SKIL… 模型人人都能用,什么才是你能带走的?我的答案是一个可进化的Skil… AI 时代 ShiroAttack2 5.x:修改了什么 · SU… 在 AGI 降临前,先给 AI 开一条”脑内弹幕”通道 · SUM… 一篇博文,三种时间:网页幻灯与 Remotion 动效的交付逻辑 … 🔍 别让大模型”想太多”:SKILL开发中的语义陷阱与抗幻觉设计 … 2022 年年度总结 · SUMSEC Java Swing To RCE 漏洞分析 · SUMSEC SpringBoot GatewayEL表达式漏洞分析 · SUM… Sensitive keys in codebases · SUM… 论如何优雅注入 Java 内存马 · SUMSEC SUMSEC 知识点 · SUMSEC VMWare Workspace ONE Access Auth … Spring Framework RCE CVE-2022-229… 相似度算法调研 · SUMSEC CVE-2022-33891 Apache Spark shell… Spring Data MongoDB SpEL CVE-2022… CodeQl Usage Tricks · SUMSEC Spring Boot RCE到内存马探索 · SUMSEC Shiro后渗透拓展面 · SUMSEC shiro反序列化漏洞攻击拓展面–修改key · SUMSEC GitHub Java CodeQL CTF · SUMSEC Hack-Tools 转化成Web · SUMSEC CodeQL与Shiro550碰撞 · SUMSEC CodeQL初见Shiro550 · SUMSEC CodeQL与AST之间联系 · SUMSEC Java加载动态链接库 · SUMSEC Log4j2 漏洞分析 · SUMSEC Interprocedural-Analysis 过程间分析 · … Data Analysis Foundation 数据分析基础 ·… Data Flow Analysis · SUMSEC Intermediate Representation 中间代表(… PII泄露–用CodeQL识别日志中的PII数据 · SUMSEC CodeQL workshop for Java: Unsafe … 前言 · SUMSEC 漏洞环境的搭建 · SUMSEC Fastjson回显 · SUMSEC Tomcat通用回显学习笔记 · SUMSEC 从Java反序列化漏洞题看CodeQL数据流 · SUMSEC 概述 · SUMSEC 记一次Log4j失败的Gadget挖掘记录 · SUMSEC Ysoserial改造记录 · SUMSEC JNDI注入 · SUMSEC shiro JRMP gadget · SUMSEC Fastjson MySQL gadget复现 · SUMSEC 2021年度总结 · SUMSEC
正则匹配配置不当 · SUMSEC
2023-01-09 · via SumSec's Blog

正则匹配配置不当

前言

正则匹配如果被使用在权限检验的场景中,需要注意一些是否使用默认配置。如果使用默认配置会可能会导致被Bypass的情况,历史Java框架漏洞 Spring Security CVE-2022-22978Apache Shiro CVE-2022-32532


默认情况下的漏洞

示例代码,大多数开放很少注意到使用Pattern.DOTALL来避免匹配文本中的\r\n\t等字符,就很可能存在被绕过的风险。

Ps: Pattern内置了 CASE_INSENSITIVE、MULTILINE、DOTALL、UNICODE_CASE、CANON_EQ、UNIX_LINES、LITERAL、UNICODE_CHARACTER_CLASS、COMMENTS 等匹配设置

CASE_INSENSITIVE 不区分大小写

DOTALL 在 dotall 模式下,表达式 {@code .} 匹配任何字符,包括行终止符。默认情况下,此表达式不匹配行终止符。

MULTILINE 启用多行模式。在多行模式中,表达式 ^ 和匹配分别在行终止符或输入序列的结尾之后或之前。默认情况下,这些表达式只匹配整个输入序列的开头和结尾。多行模式也可以通过嵌入式标志表达式 (?m) 启用

….

import java.util.regex.Pattern;

public class RegexBypassDemo {

    public static void main(String[] args) {
        String regex = "/permit/.*";
        Pattern pattern = Pattern.compile(regex, Pattern.DOTALL);
        Pattern pattern1 = Pattern.compile(regex);

        String source = "/permit/a\nb";

        if (pattern.matcher(source).matches()){
            System.out.println("pattern: /permit/a\nb is match!");
        }

        if (pattern1.matcher(source).matches()){
            System.out.println("pattern1: /permit/a\nb is match!");
        }

    }
}

Output:

pattern: /permit/a b is match!


漏洞场景

Apache Shiro CVE-2022-32532

漏洞环境 https://github.com/4ra1n/CVE-2022-32532

正常情况下场景:

请求中带了Token是能访问/permit/的目录,如果没有带Token是不允许访问。

GET /permit/any HTTP/1.1
Token: 4ra1n

success

Access is not allowed

GET /permit/a%0any HTTP/1.1

Bypass Success


漏洞源代码org.apache.shiro.util.RegExPatternMatcher 实现

package org.apache.shiro.util;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegExPatternMatcher implements PatternMatcher {
    public RegExPatternMatcher() {
    }

    public boolean matches(String pattern, String source) {
        if (pattern == null) {
            throw new IllegalArgumentException("pattern argument cannot be null.");
        } else {
            Pattern p = Pattern.compile(pattern);
            Matcher m = p.matcher(source);
            return m.matches();
        }
    }
}

修复后的漏洞代码,在Pattern.compile()方法,默认情况下flag=Pattern.DOTALL

package org.apache.shiro.util;

import java.util.regex.Pattern;
import java.util.regex.Matcher;


public class RegExPatternMatcher implements PatternMatcher {

    private static final int DEFAULT = Pattern.DOTALL;

    private static final int CASE_INSENSITIVE = DEFAULT | Pattern.CASE_INSENSITIVE;

    private boolean caseInsensitive = false;

    public boolean matches(String pattern, String source) {
        if (pattern == null) {
            throw new IllegalArgumentException("pattern argument cannot be null.");
        }
        Pattern p = Pattern.compile(pattern, caseInsensitive ? CASE_INSENSITIVE : DEFAULT);
        Matcher m = p.matcher(source);
        return m.matches();
    }


    public boolean isCaseInsensitive() {
        return caseInsensitive;
    }


    public void setCaseInsensitive(boolean caseInsensitive) {
        this.caseInsensitive = caseInsensitive;
    }
}

Spring Security CVE-2022-22978

漏洞代码Version: 5.0.x RegexRequestMatcher

package org.springframework.security.web.util.matcher;

import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.HttpMethod;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.StringUtils;


public final class RegexRequestMatcher implements RequestMatcher {
	private final static Log logger = LogFactory.getLog(RegexRequestMatcher.class);

	private final Pattern pattern;
	private final HttpMethod httpMethod;


	public RegexRequestMatcher(String pattern, String httpMethod) {
		this(pattern, httpMethod, false);
	}


	public RegexRequestMatcher(String pattern, String httpMethod, boolean caseInsensitive) {
		if (caseInsensitive) {
			this.pattern = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
		}
		else {
			this.pattern = Pattern.compile(pattern);
		}
		this.httpMethod = StringUtils.hasText(httpMethod) ? HttpMethod
				.valueOf(httpMethod) : null;
	}


	public boolean matches(HttpServletRequest request) {
		if (httpMethod != null && request.getMethod() != null
				&& httpMethod != valueOf(request.getMethod())) {
			return false;
		}

		String url = request.getServletPath();
		String pathInfo = request.getPathInfo();
		String query = request.getQueryString();

		if (pathInfo != null || query != null) {
			StringBuilder sb = new StringBuilder(url);

			if (pathInfo != null) {
				sb.append(pathInfo);
			}

			if (query != null) {
				sb.append('?').append(query);
			}
			url = sb.toString();
		}

		if (logger.isDebugEnabled()) {
			logger.debug("Checking match of request : '" + url + "'; against '" + pattern
					+ "'");
		}

		return pattern.matcher(url).matches();
	}

	private static HttpMethod valueOf(String method) {
		try {
			return HttpMethod.valueOf(method);
		}
		catch (IllegalArgumentException e) {
		}

		return null;
	}
}

修复后的代码Version: 5.7.x RegexRequestMatcher.java

package org.springframework.security.web.util.matcher;

import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.log.LogMessage;
import org.springframework.http.HttpMethod;
import org.springframework.util.StringUtils;

public final class RegexRequestMatcher implements RequestMatcher {

	private static final int DEFAULT = Pattern.DOTALL;

	private static final int CASE_INSENSITIVE = DEFAULT | Pattern.CASE_INSENSITIVE;

	private static final Log logger = LogFactory.getLog(RegexRequestMatcher.class);

	private final Pattern pattern;

	private final HttpMethod httpMethod;


	public RegexRequestMatcher(String pattern, String httpMethod) {
		this(pattern, httpMethod, false);
	}


	public RegexRequestMatcher(String pattern, String httpMethod, boolean caseInsensitive) {
		this.pattern = Pattern.compile(pattern, caseInsensitive ? CASE_INSENSITIVE : DEFAULT);
		this.httpMethod = StringUtils.hasText(httpMethod) ? HttpMethod.valueOf(httpMethod) : null;
	}


	@Override
	public boolean matches(HttpServletRequest request) {
		if (this.httpMethod != null && request.getMethod() != null
				&& this.httpMethod != HttpMethod.resolve(request.getMethod())) {
			return false;
		}
		String url = request.getServletPath();
		String pathInfo = request.getPathInfo();
		String query = request.getQueryString();
		if (pathInfo != null || query != null) {
			StringBuilder sb = new StringBuilder(url);
			if (pathInfo != null) {
				sb.append(pathInfo);
			}
			if (query != null) {
				sb.append('?').append(query);
			}
			url = sb.toString();
		}
		logger.debug(LogMessage.format("Checking match of request : '%s'; against '%s'", url, this.pattern));
		return this.pattern.matcher(url).matches();
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("Regex [pattern='").append(this.pattern).append("'");
		if (this.httpMethod != null) {
			sb.append(", ").append(this.httpMethod);
		}
		sb.append("]");
		return sb.toString();
	}

}

主要差异

image-20220706165712413

image-20220706165730031


漏洞场景分析

这个bypass和之前历史路径bypass不一样,因为这个具体的uri都改变了,无法将请求转发到具体代码逻辑下或者说转发到需要的uri上。

这里根据4ra1n大佬的代码可能存在某些特殊情况的场景利用,当路径使用{value}取值时就可能存在漏洞。

@RequestMapping(path = "/permit/{value}")
public String permit(@PathVariable String value) {
    System.out.println("success!");
    return "success is " + value;
}

image-20220714152845423

但这种情况在实际开放场景很少会使用{value}取路径。


总结

  1. 使用正则匹配作为权限检验不能直接使用Pattern.compile(regex),应当使用Pattern.compile(regex, Pattern.DOTALL);
  2. 使用正则匹配匹配文本也应当尽量避免使用Pattern.compile(regex);,尽量加上Pattern中的匹配模式。
  3. 尽量避免使用{value}这种模糊方式取路径的值
  4. 关于自动化检测,目前CodeQL是支持了,详情参考 https://github.com/github/securitylab/issues/694 。

参考

  • https://lists.apache.org/thread/y8260dw8vbm99oq7zv6y3mzn5ovk90xh
  • https://tanzu.vmware.com/security/cve-2022-22978
  • https://xz.aliyun.com/t/11501