Java安全之Filter權(quán)限繞過的實(shí)現(xiàn)
在一些需要挖掘一些無條件RCE中,大部分類似于一些系統(tǒng)大部分地方都做了權(quán)限控制的,而這時候想要利用權(quán)限繞過就顯得格外重要。在此來學(xué)習(xí)一波權(quán)限繞過的思路。
0x01 權(quán)限控制實(shí)現(xiàn)常見的實(shí)現(xiàn)方式,在不調(diào)用Spring Security、Shiro等權(quán)限控制組件的情況下,會使用Filter獲取請求路徑,進(jìn)行校驗。
編寫一個servlet
package com.nice0e3;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@WebServlet('/helloServlet')public class helloServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getWriter().write('hello!!!'); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response); }}
定義一個Filter
package com.nice0e3.filter;import com.nice0e3.User;import javax.servlet.*;import javax.servlet.annotation.WebFilter;import javax.servlet.http.HttpServletRequest;import java.io.IOException;@WebFilter('/*')public class demoFilter implements Filter { public void destroy() { } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {HttpServletRequest request = (HttpServletRequest) req;String uri = request.getRequestURI();StringBuffer requestURL = request.getRequestURL();System.out.println(requestURL);if(uri.startsWith('/system/login')) { //登陸接口設(shè)置⽩白名單,即登錄頁面 System.out.println('login_page'); resp.getWriter(). write('login_page'); chain.doFilter(request, resp);}else if(uri.endsWith('.do')||uri.endsWith('.action')) {//檢測當(dāng)前⽤戶是否登陸 User user =(User) request.getSession().getAttribute('user'); if(user == null) {resp.getWriter(). write('unauthorized access'); //未授權(quán)訪問System.out.println('unauthorized access');resp.getWriter(). write('go to login_page');//跳轉(zhuǎn)登錄System.out.println('go to login_page'); }} } public void init(FilterConfig config) throws ServletException { }}
這里使用 request.getRequestURI();獲取URI為 /system/login開頭 則直接放行。結(jié)尾,為.do和.action的請求去做校驗,獲取session有沒有user的值,沒有的話即返回unauthorized access,如果不為.do和.action的請求或session中存在user即放行。
訪問main頁面,顯示未授權(quán)訪問并且跳轉(zhuǎn)到登錄的頁面
在Java中通常會使用request.getRequestURL()和request.getRequestURI()這兩個方法獲取請求路徑,然后對請求路徑做校驗。
../繞過方式
這里采用../的方式繞過
這里就繞過了,權(quán)限控制,直接能訪問到main,而不是顯示未授權(quán)訪問。在繞過時候可以找一些白名單的路徑,然后使用../去繞過。
payload:/system/login/../../login/main.do
繞過原理分析上圖可以看到我們前面為system/login開頭
符合匹配的規(guī)則,而匹配上該規(guī)則后則是直接放行,讓系統(tǒng)認(rèn)為訪問路徑是一個登錄的路徑,但在后面加入2個../進(jìn)行跳轉(zhuǎn)到根目錄,并且拼接上login/main.do,這時候?qū)嶋H訪問到的是http://127.0.0.1/login/main.do。
但使用
StringBuffer requestURL = request.getRequestURL();if(requestURL.toString().startsWith('/system/login'))
request.getRequestURL();該方法獲取URL是攜帶http://127.xxx等信息的。其實(shí)這里比較廢話,因為驗證首部的字符路徑的話,使用 request.getRequestURI();來獲取請求路徑部分來校驗。
URL截斷繞過
基于前面Filter代碼將../進(jìn)行過濾
package com.nice0e3.filter;import com.nice0e3.User;import javax.servlet.*;import javax.servlet.annotation.WebFilter;import javax.servlet.http.HttpServletRequest;import java.io.IOException;@WebFilter('/*')public class demoFilter implements Filter { public void destroy() { } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {HttpServletRequest request = (HttpServletRequest) req;String uri = request.getRequestURI();if(uri.contains('./')){ resp.getWriter().write('error'); return;}StringBuffer requestURL = request.getRequestURL();System.out.println(requestURL);if(uri.startsWith('/system/login')) { //登陸接口設(shè)置⽩白名單,即登錄頁面 System.out.println('login_page'); resp.getWriter(). write('login_page'); chain.doFilter(request, resp);}else if(uri.endsWith('.do')||uri.endsWith('.action')) {//檢測當(dāng)前⽤戶是否登陸 User user =(User) request.getSession().getAttribute('user'); if(user == null) {resp.getWriter(). write('unauthorized access'); //未授權(quán)訪問System.out.println('unauthorized access');resp.getWriter(). write('go to login_page');//跳轉(zhuǎn)登錄System.out.println('go to login_page'); }} chain.doFilter(request,resp); } public void init(FilterConfig config) throws ServletException { }}
添加多了一個uri.contains('./')做過濾只要包含./字符直接報錯。
這時候會報錯,可見上圖???;進(jìn)行繞過
payload:/login/main.do;123
繞過分析
URL中有一個保留字符分號;,主要為參數(shù)進(jìn)行分割使用,有時候是請求中傳遞的參數(shù)太多了,所以使用分號;將參數(shù)對(key=value)連接起來作為一個請求參數(shù)進(jìn)⾏傳遞。
再來看到代碼,代碼中識別.do和.action的后綴的字符,而加入;加上隨便內(nèi)容后,代碼中就識別不到了。則會走到最下面的chain.doFilter(request,resp);,而在后面添加;分號不會對地址的訪問有任何影響。
多/繞過
創(chuàng)建一個后臺接口,只允許admin用戶登錄訪問
package com.nice0e3.Servlet;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@WebServlet('/system/UserInfoSearch.do')public class UserInfoServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getWriter().write('admin_login!!!'); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); }}
而權(quán)限控制這步肯定是在Filter里面實(shí)現(xiàn)
String uri = request.getRequestURI();if(uri.equals('/system/UserInfoSearch.do')){ User user =(User) request.getSession().getAttribute('user'); String role = user.getRole(); if(role.equals('admin')) {//當(dāng)前⽤用戶為admin,允許訪問該接⼝chain.doFilter(request, resp); } else {resp.getWriter().write('Unauthorized');return; }}
這時候去對/system/UserInfoSearch.do做了校驗,獲取URI地址后匹配如果是這個/system/UserInfoSearch.do,則驗證用戶身份,加入不為admin,則顯示Unauthorized,越權(quán)訪問。
可直接訪問到admin用戶才可訪問的頁面下。
payload: //system/UserInfoSearch.do;123
繞過分析
看到代碼中只是對比了URI是否為/system/UserInfoSearch.do,而多加一個/并不影響正常解析,而又能讓該規(guī)則匹配不到。
URL編碼繞過
還是用上面的代碼演示,繞過手法則是換成url編碼繞過的方式。
payload:/system/%55%73%65%72%49%6e%66%6f%53%65%61%72%63%68%2e%64%6f
繞過分析
當(dāng)Filter處理完相關(guān)的流程后,中間件會對請求的URL進(jìn)行一次URL解碼操作,然后請求解碼后的Servlet,而在request.getRequestURL()和request.getRequestURI()中并不會自動進(jìn)行解碼,所以這時候直接接收過來進(jìn)行規(guī)則匹配,則識別不出來。這時候?qū)е铝死@過。
Spring MVC中追加/繞過
在SpringMVC中假設(shè)以如下方法配置:
<servlet-mapping><servlet-name>SpringMVC</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
特定情況下Spring匹配web路徑的時候會容錯后面的/
如,/admin/main.do/
修復(fù)
使用該代碼接受URI
String uri1 = request.getServletPath() + (request.getPathInfo() != null ? request.getPathInfo() : '');
下面來嘗試前面的幾種繞過方式。
分號階段繞過 payload: /login/main.do;123
多/繞過payload: //system/UserInfoSearch.do;123
URL編碼繞過payload:/system/%55%73%65%72%49%6e%66%6f%53%65%61%72%63%68%2e%64%6f
../繞過payload:/system/login/../../login/main.do
均不可用,使用上面的方式接受URI后,接受過去的時候發(fā)送特殊字符一律被剔除了。打斷點(diǎn)可見。
關(guān)注點(diǎn)
前面提到過request.getRequestURL()和request.getRequestURI(),這些危險字符并不會自動剔除掉??芍攸c(diǎn)關(guān)注該方法。
參考
https://blog.csdn.net/qq_38154820/article/details/106799046
0x02 結(jié)尾不只是Filter里面可以做權(quán)限繞過,在使用到一些Shiro框架的時候,也會有一些權(quán)限繞過的方式。
到此這篇關(guān)于Java安全之Filter權(quán)限繞過的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Java Filter權(quán)限繞過內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!
相關(guān)文章:
