• Java安全之Filter权限绕过


    Java安全之Filter权限绕过

    0x00 前言

    在一些需要挖掘一些无条件RCE中,大部分类似于一些系统大部分地方都做了权限控制的,而这时候想要利用权限绕过就显得格外重要。在此来学习一波权限绕过的思路。

    0x01 权限控制实现

    常见的实现方式,在不调用Spring Security、Shiro等权限控制组件的情况下,会使用Filter获取请求路径,进行校验。

    编写一个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")) {  //登陆接口设置⽩白名单,即登录页面
                System.out.println("login_page");
                resp.getWriter(). write("login_page");
    
                chain.doFilter(request, resp);
            }
            else if(uri.endsWith(".do")||uri.endsWith(".action")) {
    //检测当前⽤户是否登陆
                User user =(User) request.getSession().getAttribute("user");
                if(user == null) {
                    resp.getWriter(). write("unauthorized access"); //未授权访问
                    System.out.println("unauthorized access");
                    resp.getWriter(). write("go to login_page");//跳转登录
                    System.out.println("go to login_page");
                }
            }
    
    
        }
    
        public void init(FilterConfig config) throws ServletException {
    
        }
    }
    
    

    这里使用 request.getRequestURI();获取URI为 /system/login开头 则直接放行。结尾,为.do.action的请求去做校验,获取session有没有user的值,没有的话即返回unauthorized access,如果不为.do.action的请求或session中存在user即放行。

    访问main页面,显示未授权访问并且跳转到登录的页面

    在Java中通常会使用request.getRequestURL()request.getRequestURI()这两个方法获取请求路径,然后对请求路径做校验。

    ../绕过方式

    这里采用../的方式绕过

    这里就绕过了,权限控制,直接能访问到main,而不是显示未授权访问。在绕过时候可以找一些白名单的路径,然后使用../去绕过。

    payload:/system/login/../../login/main.do

    绕过原理分析

    上图可以看到我们前面为system/login开头

    符合匹配的规则,而匹配上该规则后则是直接放行,让系统认为访问路径是一个登录的路径,但在后面加入2个../进行跳转到根目录,并且拼接上login/main.do,这时候实际访问到的是http://127.0.0.1/login/main.do

    但使用

     StringBuffer requestURL = request.getRequestURL();
    if(requestURL.toString().startsWith("/system/login"))
    

    request.getRequestURL();该方法获取URL是携带http://127.xxx等信息的。其实这里比较废话,因为验证首部的字符路径的话,使用 request.getRequestURI();来获取请求路径部分来校验。

    URL截断绕过

    基于前面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();
    
            if(uri.contains("./")){
                resp.getWriter().write("error");
                return;
            }
            StringBuffer requestURL = request.getRequestURL();
            System.out.println(requestURL);
            if(uri.startsWith("/system/login")) {  //登陆接口设置⽩白名单,即登录页面
                System.out.println("login_page");
                resp.getWriter(). write("login_page");
    
                chain.doFilter(request, resp);
            }
            else if(uri.endsWith(".do")||uri.endsWith(".action")) {
    //检测当前⽤户是否登陆
                User user =(User) request.getSession().getAttribute("user");
                if(user == null) {
                    resp.getWriter(). write("unauthorized access"); //未授权访问
                    System.out.println("unauthorized access");
                    resp.getWriter(). write("go to login_page");//跳转登录
                    System.out.println("go to login_page");
                }
            }
    
        chain.doFilter(request,resp);
        }
    
        public void init(FilterConfig config) throws ServletException {
    
        }
    }
    
    

    添加多了一个uri.contains("./")做过滤只要包含./字符直接报错。

    这时候会报错,可见上图。可进行绕过

    payload:/login/main.do;123

    绕过分析

    URL中有一个保留字符分号;,主要为参数进行分割使用,有时候是请求中传递的参数太多了,所以使用分号;将参数对(key=value)连接起来作为一个请求参数进⾏传递。

    再来看到代码,代码中识别.do.action的后缀的字符,而加入;加上随便内容后,代码中就识别不到了。则会走到最下面的chain.doFilter(request,resp);,而在后面添加分号不会对地址的访问有任何影响。

    绕过

    创建一个后台接口,只允许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);
        }
    }
    
    

    而权限控制这步肯定是在Filter里面实现

         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")) {
    //当前⽤用户为admin,允许访问该接⼝
                    chain.doFilter(request, resp);
                }
                else {
                    resp.getWriter().write("Unauthorized");
                    return;
                }
            }
    

    这时候去对/system/UserInfoSearch.do做了校验,获取URI地址后匹配如果是这个/system/UserInfoSearch.do,则验证用户身份,加入不为admin,则显示Unauthorized,越权访问。

    可直接访问到admin用户才可访问的页面下。

    payload: //system/UserInfoSearch.do;123

    绕过分析

    看到代码中只是对比了URI是否为/system/UserInfoSearch.do,而多加一个/并不影响正常解析,而又能让该规则匹配不到。

    URL编码绕过

    还是用上面的代码演示,绕过手法则是换成url编码绕过的方式。

    payload:/system/%55%73%65%72%49%6e%66%6f%53%65%61%72%63%68%2e%64%6f

    绕过分析

    当Filter处理完相关的流程后,中间件会对请求的URL进行一次URL解码操作,然后请求解码后的Servlet,而在request.getRequestURL()和request.getRequestURI()中并不会自动进行解码,所以这时候直接接收过来进行规则匹配,则识别不出来。这时候导致了绕过。

    Spring MVC中追加/绕过

    在SpringMVC中假设以如下方法配置:

    <servlet-mapping>
    <servlet-name>SpringMVC</servlet-name>
    <url-pattern>/</url-pattern>
    </servlet-mapping>
    

    特定情况下Spring匹配web路径的时候会容错后面的/

    如,/admin/main.do/

    修复

    使用该代码接受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后,接受过去的时候发送特殊字符一律被剔除了。打断点可见。

    关注点

    前面提到过request.getRequestURL()request.getRequestURI(),这些危险字符并不会自动剔除掉。可重点关注该方法。

    参考

    https://blog.csdn.net/qq_38154820/article/details/106799046

    0x02 结尾

    不只是Filter里面可以做权限绕过,在使用到一些Shiro框架的时候,也会有一些权限绕过的方式。

    WX:TG9yaTI1NDgyNjYxNDU= 欢迎各位师傅来一起做技术交流
  • 相关阅读:
    WQS二分
    虚树
    洛谷集训队题单Part1
    动态点分治
    点分治
    最小乘积模型
    线段树分治
    分层图最短路
    学长学姐们的测试-2
    线性dp
  • 原文地址:https://www.cnblogs.com/nice0e3/p/14801884.html
Copyright © 2020-2023  润新知