作者:jweny@360云安全
文章首發于安全客:https://www.anquanke.com/post/id/230935

0x01 漏洞描述

Apache Shiro是一個強大且易用的Java安全框架,執行身份驗證、授權、密碼和會話管理。使用Shiro的易于理解的API,您可以快速、輕松地獲得任何應用程序,從最小的移動應用程序到最大的網絡和企業應用程序。

當它和 Spring 結合使用時,在一定權限匹配規則下,攻擊者可通過構造特殊的 HTTP 請求包完成身份認證繞過。

影響范圍:Apache Shiro < 1.7.1

0x02 漏洞環境搭建

shiro 1.7.0

https://github.com/jweny/shiro-cve-2020-17523 兩種姿勢的漏洞環境均已更新。

0x03 poc測試

姿勢一:

http://127.0.0.1:8080/admin/%20http://127.0.0.1:8080/admin/%20/

使用空格等空字符,可繞過shiro身份驗證。

image-20210205120522547

姿勢二:

經過和p0desta師傅交流,發現還有另一種特殊場景下的利用方式。

http://127.0.0.1:8080/admin/%2ehttp://127.0.0.1:8080/admin/%2e/

但是.(還有/)在Spring的路徑匹配的規則中是代表路徑分隔符的,不作為普通字符進行匹配。因此在默認條件下訪問 /admin/.會返回404。

但是在開啟全路徑的場景下setAlwaysUseFullPath(true)是可以正常匹配的。

image-20210205102100797

0x04 漏洞分析

Shiro中對于URL的獲取及匹配在org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver#getChain

先簡單看下這個getChain方法:

carbon (2)

image-20210205103341569

該方法先檢查requestURI是否以/結尾,如果是,就刪掉最后一個/

然后在匹配路徑的循環中,會先判斷下路徑規則pathPattern是否以/結尾,如果是也會刪除。然后再去調用pathMatches()方法進行路徑匹配。

因此兩種利用方式中,是否以/結尾都沒有關系,因為開始經過getChain方法就會被刪除。

4.1 空格繞過分析

關注下pathMatches()方法:

調出Evaluate,分別計算一下pathMatches("/admin/*","/admin/1")pathMatches("/admin/*","/admin/ "),前者正常匹配,后者匹配失敗。

image-20210203134044268

image-20210203134119174

開始調試,調試開始會經過一陣漫長的F7。一直到doMatch("/admin/*","/admin/ ")。可見,tokenizeToStringArray返回的pathDirs已經沒有第二層路徑了。因此會導致/admin/*/admin不匹配。

image-20210203150854085

跟一下tokenizeToStringArray方法,發現其調用tokenizeToStringArray方法時的trimTokens參數為true。

image-20210203150959413

tokenizeToStringArray方法,在參數trimTokens為true時,會經過trim()處理,因此導致空格被清除。再次返回getChain時最后一個/被刪除。因此tokenizeToStringArray返回的pathDirs沒有第二層路徑。

image-20210203151053344

總結一下:存在漏洞的shiro版本,由于調用tokenizeToStringArray方法時,trimTokens參數默認為true,空格會經過trim()處理,因此導致空格被清除。再次返回getChain時最后一個/被刪除,所以/admin/admin/*匹配失敗,導致鑒權繞過。而Spring接受到的訪問路徑為/admin/%20,按照正常邏輯返回響應,因此導致權限被繞過。

4.2 /./繞過分析

看到第二種姿勢的/././,是不是想起了某個熟悉方法?沒錯,就是normalize()

carbon (3)

簡單翻譯下就是:

條件 示例
正斜杠處理成反斜杠 \ -> /
雙反斜杠處理成反斜杠 // -> /
以/.或者/..結尾,則在結尾添加/ /. -> /./ /.. -> /../
歸一化處理/./ /./ -> /
路徑跳躍 /aaa/../bbb -> /bbb

所以/admin/.在被處理成/admin/./之后變成了/admin/

image-20210205113301788

在經過org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver#getChain處理,由于/結尾,如果是,就刪掉最后一個/,變成了/admin`/admin/admin/*不匹配,因此繞過了shiro鑒權。

image-20210205113518970

而此時Spring收到的請求為/admin/.如果沒有開啟全路徑匹配的話,在Spring中./是作為路徑分隔符的,不參與路徑匹配。因此會匹配不到mapping,返回404。

image-20210205114350972

開啟全路徑匹配的話,會匹配整個url,因此Spring返回200。

這里附上開啟全路徑匹配的代碼:

@SpringBootApplication
public class SpringbootShiroApplication extends SpringBootServletInitializer implements BeanPostProcessor {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(SpringbootShiroApplication.class);
    }

    public static void main(String[] args) {

        SpringApplication.run(SpringbootShiroApplication.class, args);
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        if (bean instanceof RequestMappingHandlerMapping) {
            ((RequestMappingHandlerMapping) bean).setAlwaysUseFullPath(true);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        return bean;
    }
}

0x05 官方的修復方案

經過以上的分析,造成shiro權限繞過的原因有兩個:

  1. tokenizeToStringArray函數沒有正確處理空格。
  2. 處理最后一個/的邏輯,不應在循環匹配路徑的邏輯之前。

因此官方的修復方案為:

https://github.com/apache/shiro/commit/0842c27fa72d0da5de0c5723a66d402fe20903df

  1. tokenizeToStringArraytrimTokens參數置為false。image-20210203154342100
  2. 調整刪除最后一個/的邏輯。修改成先匹配原始路徑,匹配失敗后再去走刪除最后一個/的邏輯。image-20210205115522098

0x06 關于trim

原理上來說trim()會清空字符串前后所有的whitespace,空格只是其中的一種,但是在測試中發現除了空格以外的其他whitespace,例如%08%09%0a,spring+tomcat 處理時都會返回400。

因此第一種姿勢除了空格,尚未發現其他好用的payload。

0x07 參考

https://github.com/apache/shiro/commit/0842c27fa72d0da5de0c5723a66d402fe20903df

https://www.anquanke.com/post/id/216096

https://www.cnblogs.com/syp172654682/p/9257282.html


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1478/