沉铝汤的破站

IS LIFE ALWAYS THIS HARD, OR IS IT JUST WHEN YOU'RE A KID

Nexus RCE[CVE-2018-16621&&CVE-2020-10204]

0x00 前言


这篇文章依然是关于Nexus Repository Manager3的漏洞,依然是RCE😋,因为太菜找不到RCE只能来分析历史漏洞了。本篇包含以下元素:
  • CVE-2018-16621(是一个EL的RCE,最后触发处和CVE-2020-10199相同)
  • CVE-2020-10204(其实是对CVE-2018-16621修复后的绕过)

0x01 CVE-2018-16621


漏洞简介

在Nexus的3.x-3.13的版本中,在User的信息处,如果填入的roles不存在,则会进行一个EL表达式的渲染,大概是用来返回错误信息,但是又因为没有过滤,导致了RCE。(其实这和CVE-2020-10199类似,那里是因为不存在名字匹配的Repository,而去拼接一个报错信息,最后也会进行EL的渲染)需要注意的是,这个漏洞需要你有管理员账号,因为貌似只有管理员才能更新用户信息。

环境的搭建

依然是先从Github上clone下来,然后再checkout切换分支:

git clone https://github.com/sonatype/nexus-public.git
git checkout -f -b release-3.13.0-01 remotes/origin/release-3.13.0-01

然后使用我们的祖传docker命令:

docker run -d -p 8081:8081 -p 8000:8000 --name nexus -e INSTALL4J_ADD_VM_PARAMS="-Xms2g -Xmx2g -XX:MaxDirectMemorySize=3g -Djava.util.prefs.userRoot=${NEXUS_DATA}/javaprefs -Dstorage.diskCache.diskFreeSpaceLimit=1024 -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000" sonatype/nexus3:3.13.0

漏洞复现

首先用管理员账号登录,然后找到设置中的User处,如下图:

image-20211121223712194

随便改改LastName,这里从User改为了User1,然后抓包如下:

image-20211121224337872

把roles的内容改为EL表达式,重放之后,可以看到被渲染了:

image-20211121224452420

漏洞定位

看到上面的“Missing roles”,我们可以利用这个来定位一下:

image-20211123213954344

可以看到总共有两处,仔细观察之后还会发现,第二处就是就是第一处中@Constraint所指定的类,所以我们下面就直接跟进RolesExistValidator类处。

(org/sonatype/nexus/security/role/RolesExistValidator.java)

漏洞分析

不过找到了上面的切入点也没啥用…我还是不能一步步分析中间过程,只能用CVE-2020-10199(点我看详情)中我们最后调试的结果,反正这就是Nexus中EL渲染的最终处:

(org/hibernate/validator/internal/engine/messageinterpolation/ElTermResolver.java)

private String interpolateExpressionLanguageTerm(MessageInterpolator.Context context) {
    String resolvedExpression = expression;
    SimpleELContext elContext = new SimpleELContext();
    try {
        ValueExpression valueExpression = bindContextValues( expression, context, elContext );
        resolvedExpression = (String) valueExpression.getValue( elContext );
    }
    catch ( PropertyNotFoundException pnfe ) {
        log.unknownPropertyInExpressionLanguage( expression, pnfe );
    }
    catch ( ELException e ) {
        log.errorInExpressionLanguage( expression, e );
    }
    catch ( Exception e ) {
        log.evaluatingExpressionLanguageExpressionCausedException( expression, e );
    }

    return resolvedExpression;
}

在这里EL表达式会被渲染,中间过程太多了,不知道大佬们是怎样一步步追踪到这里的,或者他们也没追踪….

漏洞修复

漏洞修复在3.14.0版本对我们漏洞定位处先进行了过滤,再传入buildConstraintViolationWithTemplate进行渲染,如下:

image-20211123225406491

其中stripJavaEl代码如下(org/sonatype/nexus/common/template/EscapeHelper.java):

public String stripJavaEl(final String value) {
    if (value != null) {
        return value.replaceAll("\\$+\\{", "{");
    }
    return null;
}

只进行了简单的过滤,这导致了后面CVE-2020-10204的绕过。

0x02 CVE-2020-10204


漏洞简介

如上文所说,这个漏洞是因为CVE-2018-16621的修复不严格,而导致的绕过。存在于Nexus <= 3.21.1版本中

绕过方法

虽然替换了“${”,但是使用“$\x”的格式即可绕过,并且仍然可以成功执行EL表达式,其中x可以是任意字符,如大家常用的:”$\\A{6*6}”。

漏洞复现

docker重新部署3.14.0版本的Nexus,这时候发现使用”${“会不成功

image-20211130162009350

但是使用”$\\x{“则依然可以成功:

image-20211130162138155

漏洞修复

漏洞在3.21.2中被修复,和CVE-2020-10199修复时间相同,网上流传的修复如下(其实可能这只是部分修复):

public String stripJavaEl(final String value) {
    if (value != null) {
        return value.replaceAll("\\$+\\{", "{").replaceAll("\\$+\\\\A\\{", "{");
    }
    return null;
}

看着只新增过滤了”$\\A{“,那岂不是还是可以绕过?

拉取3.21.2版本,重新测试:

image-20211130163911224

发现并不能成功执行,应该还在其他地方进行了修复,可以调试看看,但是某名奇妙文件变成只可读了…下次再来调试

0x03 参考


Nexus Repository UserComponent远程代码执行漏洞浅析(CVE-2018-16621&CVE-2020-10204) - 先知社区 (aliyun.com)