您好,登錄后才能下訂單哦!
小編給大家分享一下Nexus Repository Manager 3幾次表達式解析漏洞的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
Nexus Repository Manager 3最近曝出兩個el表達式解析漏洞,編號為CVE-2020-10199,CVE-2020-10204,都是由Github Secutiry Lab團隊的@pwntester發現。由于之前Nexus3的漏洞沒有去跟蹤,所以當時diff得很頭疼,并且Nexus3 bug與安全修復都是混在一起,更不容易猜到哪個可能是漏洞位置了。后面與@r00t4dm師傅一起復現出了CVE-2020-10204,CVE-2020-10204是CVE-2018-16621的繞過,之后又有師傅弄出了CVE-2020-10199,這三個漏洞的根源是一樣的,其實并不止這三處,官方可能已經修復了好幾處這樣的漏洞,由于歷史不太好追溯回去,所以加了可能,通過后面的分析,就能看到了。還有之前的CVE-2019-7238,這是一個jexl表達式解析,一并在這里分析下,以及對它的修復問題,之前看到有的分析文章說這個漏洞是加了個權限來修復,可能那時是真的只加了個權限吧,不過我測試用的較新的版本,加了權限貌似也沒用,在Nexus3高版本已經使用了jexl白名單的沙箱。
文中會用到三個Nexus3環境:
nexus-3.14.0-04
nexus-3.21.1-01
nexus-3.21.2-03
nexus-3.14.0-04用于測試jexl表達式解析,nexus-3.21.1-01用于測試jexl表達式解析與el表達式解析以及diff,nexus-3.21.2-03用于測試el表達式解析以及diff
CVE-2020-10199、CVE-2020-10204漏洞的修復界限是3.21.1與3.21.2,但是github開源的代碼分支好像不對應,所以只得去下載壓縮包來對比了。在官方下載了nexus-3.21.1-01與nexus-3.21.2-03,但是beyond對比需要目錄名一樣,文件名一樣,而不同版本的代碼有的文件與文件名都不一樣。我是先分別反編譯了對應目錄下的所有jar包,然后用腳本將nexus-3.21.1-01中所有的文件與文件名中含有3.21.1-01的替換為了3.21.2-03,同時刪除了META文件夾,這個文件夾對漏洞diff沒什么用并且影響diff分析,所以都刪除了,下面是處理后的效果:
如果沒有調試和熟悉之前的Nexus3漏洞,直接去看diff可能會看得很頭疼,沒有目標的diff。
抓下nexus3發的包,隨意的點點點,可以看到大多數請求都是POST類型的,URI都是/service/extdirect:
post內容如下:
{"action":"coreui_Repository","method":"getBrowseableFormats","data":null,"type":"rpc","tid":7}
可以看下其他請求,json中都有action與method這兩個key,在代碼中搜索下coreui_Repository這個關鍵字:
可以看到這樣的地方,展開看下代碼:
通過注解方式注入了action,上面post的method->getBrowseableFormats也在中,通過注解注入了對應的method:
所以之后這樣的請求,我們就很好定位路由與對應的處理類了
Nexus3的API也出現了漏洞,來看下怎么定位API的路由,在后臺能看到Nexus3提供的所有API。
點幾個看下包,有GET、POST、DELETE、PUT等類型的請求:
沒有了之前的action與method,這里用URI來定位,直接搜索/service/rest/beta/security/content-selectors定位不到,所以縮短關鍵字,用/beta/security/content-selectors來定位:
通過@Path注解來注入URI,對應的處理方式也使用了對應的@GET、@POST來注解
可能還有其他類型的路由,不過也可以使用上面類似的方式進行搜索來定位。還有Nexus的權限問題,可以看到上面有的請求通過@RequiresPermissions來設置了權限,不過還是以實際的測試權限為準,有的在到達之前也進行了權限校驗,有的操作雖然在web頁面的admin頁面,不過本不需要admin權限,可能無權限或者只需要普通權限。
在跟蹤調試了CVE-2018-16621與CVE-2020-10204之后,感覺buildConstraintViolationWithTemplate這個keyword可以作為這個漏洞的根源,因為從調用棧可以看出這個函數的調用處于Nexus包與hibernate-validator包的分界,并且計算器的彈出也是在它之后進入hibernate-validator的處理流程,即buildConstraintViolationWithTemplate(xxx).addConstraintViolation(),最終在hibernate-validator包中的ElTermResolver中通過valueExpression.getValue(context)完成了表達式的執行,與@r00t4dm師傅也說到了這個:
于是反編譯了Nexus3所有jar包,然后搜索這個關鍵詞(使用的修復版本搜索,主要是看有沒有遺漏的地方沒修復;Nexue3有開源部分代碼,也可以直接在源碼搜索):
F:\compare-file\nexus-3.21.2-03-win64\nexus-3.21.2-03\system\com\sonatype\nexus\plugins\nexus-healthcheck-base\3.21.2-03\nexus-healthcheck-base-3.21.2-03\com\sonatype\nexus\clm\validator\ClmAuthenticationValidator.java: 26 return this.validate(ClmAuthenticationType.valueOf(iqConnectionXo.getAuthenticationType(), ClmAuthenticationType.USER), iqConnectionXo.getUsername(), iqConnectionXo.getPassword(), context); 27 } else { 28: context.buildConstraintViolationWithTemplate("unsupported annotated object " + value).addConstraintViolation(); 29 return false; 30 } .. 35 case 1: 36 if (StringUtils.isBlank(username)) { 37: context.buildConstraintViolationWithTemplate("User Authentication method requires the username to be set.").addPropertyNode("username").addConstraintViolation(); 38 } 39 40 if (StringUtils.isBlank(password)) { 41: context.buildConstraintViolationWithTemplate("User Authentication method requires the password to be set.").addPropertyNode("password").addConstraintViolation(); 42 } 43 .. 52 } 53 54: context.buildConstraintViolationWithTemplate("To proceed with PKI Authentication, clear the username and password fields. Otherwise, please select User Authentication.").addPropertyNode("authenticationType").addConstraintViolation(); 55 return false; 56 default: 57: context.buildConstraintViolationWithTemplate("unsupported authentication type " + authenticationType).addConstraintViolation(); 58 return false; 59 }F:\compare-file\nexus-3.21.2-03-win64\nexus-3.21.2-03\system\org\hibernate\validator\hibernate-validator\6.1.0.Final\hibernate-validator-6.1.0.Final\org\hibernate\validator\internal\constraintvalidators\hv\ScriptAssertValidator.java:34 if (!validationResult && !this.reportOn.isEmpty()) {35 constraintValidatorContext.disableDefaultConstraintViolation();36: constraintValidatorContext.buildConstraintViolationWithTemplate(this.message).addPropertyNode(this.reportOn).addConstraintViolation();37 }38 F:\compare-file\nexus-3.21.2-03-win64\nexus-3.21.2-03\system\org\hibernate\validator\hibernate-validator\6.1.0.Final\hibernate-validator-6.1.0.Final\org\hibernate\validator\internal\engine\constraintvalidation\ConstraintValidatorContextImpl.java: 55 } 56 57: public ConstraintViolationBuilder buildConstraintViolationWithTemplate(String messageTemplate) { 58 return new ConstraintValidatorContextImpl.ConstraintViolationBuilderImpl(messageTemplate, this.getCopyOfBasePath()); 59 }F:\compare-file\nexus-3.21.2-03-win64\nexus-3.21.2-03\system\org\sonatype\nexus\nexus-cleanup\3.21.0-02\nexus-cleanup-3.21.0-02\org\sonatype\nexus\cleanup\storage\config\CleanupPolicyAssetNamePatternValidator.java:18 } catch (RegexCriteriaValidator.InvalidExpressionException var4) {19 context.disableDefaultConstraintViolation();20: context.buildConstraintViolationWithTemplate(var4.getMessage()).addConstraintViolation();21 return false;22 }F:\compare-file\nexus-3.21.2-03-win64\nexus-3.21.2-03\system\org\sonatype\nexus\nexus-cleanup\3.21.2-03\nexus-cleanup-3.21.2-03\org\sonatype\nexus\cleanup\storage\config\CleanupPolicyAssetNamePatternValidator.java: 18 } catch (RegexCriteriaValidator.InvalidExpressionException var4) { 19 context.disableDefaultConstraintViolation(); 20: context.buildConstraintViolationWithTemplate(this.getEscapeHelper().stripJavaEl(var4.getMessage())).addConstraintViolation(); 21 return false; 22 }F:\compare-file\nexus-3.21.2-03-win64\nexus-3.21.2-03\system\org\sonatype\nexus\nexus-scheduling\3.21.2-03\nexus-scheduling-3.21.2-03\org\sonatype\nexus\scheduling\constraints\CronExpressionValidator.java: 29 } catch (IllegalArgumentException var4) { 30 context.disableDefaultConstraintViolation(); 31: context.buildConstraintViolationWithTemplate(this.getEscapeHelper().stripJavaEl(var4.getMessage())).addConstraintViolation(); 32 return false; 33 }F:\compare-file\nexus-3.21.2-03-win64\nexus-3.21.2-03\system\org\sonatype\nexus\nexus-security\3.21.2-03\nexus-security-3.21.2-03\org\sonatype\nexus\security\privilege\PrivilegesExistValidator.java: 42 if (!privilegeId.matches("^[a-zA-Z0-9\\-]{1}[a-zA-Z0-9_\\-\\.]*$")) { 43 context.disableDefaultConstraintViolation(); 44: context.buildConstraintViolationWithTemplate("Invalid privilege id: " + this.getEscapeHelper().stripJavaEl(privilegeId) + ". " + "Only letters, digits, underscores(_), hyphens(-), and dots(.) are allowed and may not start with underscore or dot.").addConstraintViolation(); 45 return false; 46 } .. 55 } else { 56 context.disableDefaultConstraintViolation(); 57: context.buildConstraintViolationWithTemplate("Missing privileges: " + missing).addConstraintViolation(); 58 return false; 59 }F:\compare-file\nexus-3.21.2-03-win64\nexus-3.21.2-03\system\org\sonatype\nexus\nexus-security\3.21.2-03\nexus-security-3.21.2-03\org\sonatype\nexus\security\role\RoleNotContainSelfValidator.java: 49 if (this.containsRole(id, roleId, processedRoleIds)) { 50 context.disableDefaultConstraintViolation(); 51: context.buildConstraintViolationWithTemplate(this.message).addConstraintViolation(); 52 return false; 53 }F:\compare-file\nexus-3.21.2-03-win64\nexus-3.21.2-03\system\org\sonatype\nexus\nexus-security\3.21.2-03\nexus-security-3.21.2-03\org\sonatype\nexus\security\role\RolesExistValidator.java: 42 } else { 43 context.disableDefaultConstraintViolation(); 44: context.buildConstraintViolationWithTemplate("Missing roles: " + missing).addConstraintViolation(); 45 return false; 46 }F:\compare-file\nexus-3.21.2-03-win64\nexus-3.21.2-03\system\org\sonatype\nexus\nexus-validation\3.21.2-03\nexus-validation-3.21.2-03\org\sonatype\nexus\validation\ConstraintViolationFactory.java: 75 public boolean isValid(ConstraintViolationFactory.HelperBean bean, ConstraintValidatorContext context) { 76 context.disableDefaultConstraintViolation(); 77: ConstraintViolationBuilder builder = context.buildConstraintViolationWithTemplate(this.getEscapeHelper().stripJavaEl(bean.getMessage())); 78 NodeBuilderCustomizableContext nodeBuilder = null; 79 String[] var8;
后面作者也發布了漏洞分析,確實用了buildConstraintViolationWithTemplate作為了漏洞的根源,利用這個關鍵點做的污點跟蹤分析。
從上面的搜索結果中可以看到,el表達式導致的那三個CVE關鍵點也在其中,同時還有其他幾個地方,有幾個使用了this.getEscapeHelper().stripJavaEl做了清除,還有幾個,看起來似乎也可以,心里一陣狂喜?然而,其他幾個沒有做清除的地方雖然能通過路由進入,但是利用不了,后面會挑選其中的一個做下分析。所以在開始說了官方可能修復了幾個類似的地方,猜想有兩種可能:
官方自己察覺到了那幾個地方也會存在el解析漏洞,所以做了清除
有其他漏洞發現者提交了那幾個做了清除的漏洞點,因為那幾個地方可以利用;但是沒清除的那幾個地方由于沒法利用,所以發現者并沒有提交,官方也沒有去做清除
不過感覺后一種可能性更大,畢竟官方不太可能有的地方做清除,有的地方不做清除,要做也是一起做清除工作。
這個漏洞對應上面的搜索結果是RolesExistValidator,既然搜索到了關鍵點,自己來手動逆向回溯下看能不能回溯到有路由處理的地方,這里用簡單的搜索回溯下。
關鍵點在RolesExistValidator的isValid,調用了buildConstraintViolationWithTemplate。搜索下有沒有調用RolesExistValidator的地方:
在RolesExist中有調用,這種寫法一般會把RolesExist當作注解來使用,并且進行校驗時會調用RolesExistValidator.isValid()。繼續搜索RolesExist:
有好幾處直接使用了RolesExist對roles屬性進行注解,可以一個一個去回溯,不過按照Role這個關鍵字RoleXO可能性更大,所以先看這個(UserXO也可以的),繼續搜索RoleXO:
會有很多其他干擾的,比如第一個紅色標注RoleXOResponse,這種可以忽略,我們找直接使用RoleXO的地方。在RoleComponent中,看到第二個紅色標注這種注解大概就知道,這里能進入路由了。第三個紅色標注使用了roleXO,并且有roles關鍵字,上面RolesExist也是對roles進行注解的,所以這里猜測是對roleXO進行屬性注入。有的地方反編譯出來的代碼不好理解,可以結合源碼看:
可以看到這里就是將提交的參數注入給了roleXO,RoleComponent對應的路由如下:
通過上面的分析,我們大概知道了能進入到最終的RolesExistValidator,不過中間可能還有很多條件需要滿足,需要構造payload然后一步一步測。這個路由對應的web頁面位置如下:
測試(這里使用的3.21.1版本,CVE-2018-16621是之前的漏洞,在3.21.1早修復了,不過3.21.1又被繞過了,所以下面使用的是繞過的情況,將$換成$\\x去繞過,繞過在后面兩個CVE再說):
修復方式:
加上了getEscapeHelper().stripJavaEL對el表達式做了清除,將${替換為了{,之后的兩個CVE就是對這個修復方式的繞過:
這就是上面說到的對之前stripJavaEL修復的繞過,這里就不細分析了,利用$\\x格式就不會被替換掉(使用3.21.1版本測試):
這個漏洞對應上面搜索結果是ConstraintViolationFactory:
buildConstraintViolationWith(標號1)出現在了HelperValidator(標號2)的isValid中,HelperValidator又被注解在HelperAnnotation(標號3、4)之上,HelperAnnotation注解在了HelperBean(標號5)之上,在ConstraintViolationFactory.createViolation方法中使用到了HelperBean(標號6、7)。按照這個思路要找調用了ConstraintViolationFactory.createViolation的地方。
也來手動逆向回溯下看能不能回溯到有路由處理的地方。
搜索ConstraintViolationFactory:
有好幾個,這里使用第一個BowerGroupRepositoriesApiResource分析,點進去看就能看出它是一個API路由:
ConstraintViolationFactory被傳遞給了super,在BowerGroupRepositoriesApiResource并沒有調用ConstraintViolationFactory的其他函數,不過它的兩個方法,也是調用了super對應的方法。它的super是AbstractGroupRepositoriesApiResource類:
BowerGroupRepositoriesApiResource構造函數中調用的super,在AbstractGroupRepositoriesApiResource賦值了ConstraintViolationFactory(標號1),ConstraintViolationFactory的使用(標號2),調用了createViolation(在后面可以看到memberNames參數),這也是之前要到達漏洞點所需要的,這個調用處于validateGroupMembers中(標號3),validateGroupMembers的調用在createRepository(標號4)和updateRepository(標號5)中都進行了調用,而這兩個方法通過上面的注解也可以看出,通過外部傳遞請求能到達。
BowerGroupRepositoriesApiResource的路由為/beta/repositories/bower/group,在后臺API找到它來進行調用(使用3.21.1測試):
還有AbstractGroupRepositoriesApiResource的其他幾個子類也是可以的:
對應上面搜索結果的CleanupPolicyAssetNamePatternValidator,可以看到這里并沒有做StripEL清除操作:
這個變量是通過報錯拋出放到buildConstraintViolationWithTemplate中的,要是報錯信息中包含了value值,那么這里就是可以利用的。
搜索CleanupPolicyAssetNamePatternValidator:
在CleanupPolicyAssetNamePattern類注解中使用了,繼續搜索CleanupPolicyAssetNamePattern:
在CleanupPolicyCriteria中的屬性regex被CleanupPolicyAssetNamePattern注解了,繼續搜索CleanupPolicyCriteria:
在CleanupPolicyComponent中的to CleanupPolicy方法中有調用,其中的cleanupPolicyXO.getCriteria也正好是CleanupPolicyCriteria對象。toCleanupPolicy在CleanupPolicyComponent的可通過路由進入的create、previewCleanup方法又調用了toCleanupPolicy。
構造payload測試:
然而這里并不能利用,value值不會被包含在報錯信息中,去看了下RegexCriteriaValidator.validate,無論如何構造,最終也只會拋出value中的一個字符,所以這里并不能利用。
與這個類似的是CronExpressionValidator,那里也是通過拋出異常,但是那里是可以利用的,不過被修復了,可能之前已經有人提交過了。還有其他幾個沒做清除的地方,要么被if、else跳過了,要么不能利用。
人工去回溯查找的方式,如果關鍵字被調用的地方不多可能還好,不過要是被大量使用,可能就不是那么好處理了。不過上面幾個漏洞,可以看到通過手動回溯查找還是可行的。
可以參考下@iswin大佬之前的分析https://www.anquanke.com/post/id/171116,這里就不再去調試截圖了。這里想寫下之前對這個漏洞的修復,說是加了權限來修復,要是只加了權限,那不是還能提交一下?不過,測試了下3.21.1版本,就算用admin權限也無法利用了,想去看下是不是能繞過。在3.14.0中測試,確實是可以的:
但是3.21.1中,就算加了權限,也是不行的。后面分別調試對比了下,以及通過下面這個測試:
JexlEngine jexl = new JexlBuilder().create();String jexlExp = "''.class.forName('java.lang.Runtime').getRuntime().exec('calc.exe')";JexlExpression e = jexl.createExpression(jexlExp);JexlContext jc = new MapContext();jc.set("foo", "aaa");e.evaluate(jc);
才知道3.14.0與上面這個測試使用的是org.apache.commons.jexl3.internal.introspection.Uberspect處理,它的getMethod方法如下:
而在3.21.1中Nexus設置的是org.apache.commons.jexl3.internal.introspection.SandboxJexlUberspect,這個SandboxJexlUberspect,它的get Method方法如下:
可以看出只允許調用String、Map、Collection類型的有限幾個方法了。
看完上面的內容,相信對Nexus3的漏洞大體有了解了,不會再無從下手的感覺。嘗試看下下其他地方,例如后臺有個LDAP,可進行jndi connect操作,不過那里調用的是context.getAttribute,雖然會遠程請求class文件,不過并不會加載class,所以并沒有危害。
有的漏洞的根源點可能會在一個應用中出現相似的地方,就像上面那個buildConstraintViolationWithTemplate這個keyword一樣,運氣好說不定一個簡單的搜索都能碰到一些相似漏洞(不過我運氣貌似差了點,通過上面的搜索可以看到某些地方的修復,說明已經有人先行一步了,直接調用了buildConstraintViolationWithTemplate并且可用的地方似乎已經沒有了)
仔細看下上面幾個漏洞的payload,好像相似度很高,所以可以弄個類似fuzz參數的工具,搜集這個應用的歷史漏洞payload,每個參數都可以測試下對應的payload,運氣好可能會撞到一些相似漏洞
以上是“Nexus Repository Manager 3幾次表達式解析漏洞的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。