一.基础信息

1.1: 题外话

先讲讲我自己吧,大半年没更新了有朋友问我java还更吗?我说更的因为我身体的原因导致这大半年没更新,
我经常拉肚子去医院做的肠镜和胃镜,发现胃里有个息肉好在不是什么大问题,师傅们还是需要注意身体。

1.2:安装和调试

通过网盘分享的文件:FastMeeting_Ent_ServerV4.30.5.4.exe
链接: [https://pan.baidu.com/s/1ZoEozpofXXEQ8_LC6i_lRQ](https://pan.baidu.com/s/1ZoEozpofXXEQ8_LC6i_lRQ) 提取码: dpvm 
--来自百度网盘超级会员v4的分享
安装还是蛮简单的,下一步下一步就是了,之后打开tomcat修改start.bat文件,修改调试关机重启就ok了。
rem start "javawebserver" /D.\ "..\jre\bin\javawebserver" -Djava.util.logging.config.file=".\conf\logging.properties" -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=".\endorsed" -classpath "..\jre\lib;.\bin\bootstrap.jar;.\bin\tomcat-juli.jar" -Dcatalina.base="." -Dcatalina.home="." -Djava.io.tmpdir=".\temp" org.apache.catalina.startup.Bootstrap start
..\jre\bin\javawebserver -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Djava.util.logging.config.file=".\conf\logging.properties" -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=".\endorsed" -server -Xms2g -Xmx2g -XX:+UseG1GC -XX:MetaspaceSize=256M -classpath "..\jre\lib;.\bin\bootstrap.jar;.\bin\tomcat-juli.jar" -Dcatalina.base="." -Dcatalina.home="." -Djava.io.tmpdir=".\temp" org.apache.catalina.startup.Bootstrap start

二.鉴权

这个系统是典型的ssm框架,鉴权还是满有意思的只能说,这里讲一个技巧就是鉴权特别多的时候懒得一个一个找,
在可以调试的清空下,我们可以在页面找一个可以访问的路由找到路由断点,看堆栈一个一个看就行还是非常方便的,
我们就用好视通举个例子,图一中找一个能访问的路由,之后反编译代码搜索这个路由/login/validateCode.do图二,
下面就是断点看看咯,图三,还是比较实用的,在就是请求出现302等跳转的时候,直接找HttpServletResponse接口setStatus下断点就行,
其他响应一样操作。

这里我们还是先手动看看项目吧,代码一中可以看到这是springmvc的项目,第一个过滤器filter是shiro的我们先看看是
不是用到了鉴权方面直接filterChainDefinitions代码二,这是弄了个啥呀所以这里一定不是鉴权的filter过滤器,因为没看到
authc所以这里可以过了,再看看代码一中第二个过滤器,DownloadFilter。
	<servlet>
		<description>spring mvc servlet</description>
		<servlet-name>springMvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<description>spring mvc 配置文件</description>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath*:conf/spring/springServlet.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>springMvc</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
	<filter>
		<filter-name>shiroFilter</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
		<init-param>
			<param-name>targetFilterLifecycle</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>shiroFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	<filter>
		<filter-name>DownloadFilter</filter-name>
		<filter-class>com.hst.ces.filter.DownloadFilter</filter-class>
		<init-param>
			<param-name>filterUrl</param-name>
			<param-value>download,filename</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>DownloadFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
   	<!-- Shiro Filter -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" />
		<property name="loginUrl" value="/login/toLogin.do" />
		<property name="successUrl" value="/index/index" />
		<!-- <property name="unauthorizedUrl" value="/login_toLogin" /> -->
		
		<!-- <property name="filters">
            <map>
                <entry key="kickout" value-ref="kickoutSessionControlFilter"/> 
            </map>
        </property> -->
       
		<property name="filterChainDefinitions">
			<value>
	           	/resources/fmWeb/**		=anon
	           	/resources/plugin/**	=anon
	           	/resources/skin/**		=anon
	           	/resources/**			=anon
	           	<!--  /login/login.do = kickout -->
			</value>
		</property>
	</bean>
代码一这个就有点小说法了,首先先走入了needCheck进去看看代码二,其中获取uri转换成小写来匹配是否
存在private String[] urlArray = new String[]{"download", "file"};这两个参数的,存在之后进入代码一,
String[] var9 = (String[])parameterMap.get(key);获取请求参数内容出现../就403,查阅了一下发现是对历史漏洞的一个修复。
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse)servletResponse;
        if (this.needCheck(request)) {
            Map<String, String[]> parameterMap = request.getParameterMap();
            Iterator var7 = parameterMap.keySet().iterator();

            while(var7.hasNext()) {
                String key = (String)var7.next();
                String[] var9 = (String[])parameterMap.get(key);
                int var10 = var9.length;

                for(int var11 = 0; var11 < var10; ++var11) {
                    String value = var9[var11];
                    if (value.contains("../")) {
                        response.setStatus(403);
                        PrintWriter out = response.getWriter();

                        try {
                            out.println("Illegal file path \"" + value + "\"");
                        } finally {
                            if (Collections.singletonList(out).get(0) != null) {
                                out.close();
                            }

                        }

                        return;
                    }
                }
            }
        }
private String[] urlArray = new String[]{"download", "file"};
private boolean needCheck(HttpServletRequest request) {
        String url = request.getRequestURI();
        String[] var3 = this.urlArray;
        int var4 = var3.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            String filterUrl = var3[var5];
            if (url.toLowerCase().contains(filterUrl)) {
                return true;
            }
        }

        return false;
    }
到这里都没有发现真正的鉴权在哪说明在springmvc配置文件中,存在四个拦截器代码一,这里第一个并不是,
第2个看名字应该都知道了TokenExistInterceptor进入看看,图一中是通过session拿去token存在内容就是true,
那么很明显我们并不能修改token的内容,所以们办法绕过(不一样比如放行路由中存在设置token的就绕过了)。
 <mvc:interceptors>
  	    <!-- 实现本地化信息的监听来实现url参数动态指定locale,V4.4解决安全问题把切换语言的方法改到后台
        <bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
        	<property name="paramName" value="lang" />
        </bean> -->
       <mvc:interceptor>
            <mvc:mapping path="/**/*.do" />
            <!-- V4.7 解决会话固定的安全问题带出来的极端情况,防止有用户在登录的过程中,其它用户直接访问login/toIndex.do能登录成功。 -->
            <!-- login下除了/toIndex.do、/tab.do、/logout.do放行,其它请求要经过拦截器 -->
            <mvc:exclude-mapping path="/login/*ogin.do" />
			<mvc:exclude-mapping path="/login/to*Error.do" />
			<mvc:exclude-mapping path="/login/validateCode.do" />
			<mvc:exclude-mapping path="/login/getResourcePlatformAddr.do" />
			<mvc:exclude-mapping path="/login/setLanguage.do" />
			<mvc:exclude-mapping path="/login/createQRCode.do" />
			<mvc:exclude-mapping path="/login/clientDownload.do" />
            <mvc:exclude-mapping path="/launch/**" />
            <!-- V4.3 不能通过链接直接访问,解决该链接跨站点请求伪造问题[IE8浏览器不兼容,先放行] -->
            <mvc:exclude-mapping path="/register/**" />
            <mvc:exclude-mapping path="/license/**" />
            <!-- 以下三条针对IE浏览器播放视频监控不到http referer特意放行 -->
            <mvc:exclude-mapping path="/record/play.do"/>
            <mvc:exclude-mapping path="/record/playBase.do"/>
            <mvc:exclude-mapping path="/record/downloadRecord.do"/>
            <!-- 放行统一认证服务 -->
            <mvc:exclude-mapping path="/oauth2/token"/>
            <mvc:exclude-mapping path="/v1/tokeninfo"/>
		   <!-- 放行级联调用的清除缓存 -->
		   <mvc:exclude-mapping path="/cache/clearAllCache"/>
            <bean class="com.hst.ces.interceptor.UrlLegalInterceptor"/>
        </mvc:interceptor>
        <mvc:interceptor>
            <mvc:mapping path="/**/*.do" />
            <mvc:exclude-mapping path="/login/**" />
            <mvc:exclude-mapping path="/launch/**" />
            <mvc:exclude-mapping path="/register/**" />
            <mvc:exclude-mapping path="/license/**" />
            <!-- 放行统一认证服务 -->
            <mvc:exclude-mapping path="/oauth2/token"/>
            <mvc:exclude-mapping path="/v1/tokeninfo"/>
            <!-- 放行人脸识别-->
            <mvc:exclude-mapping path="/face/validRequest.do"/>
            <mvc:exclude-mapping path="/face/uploadFace.do"/>
			<!-- 放行级联调用的清除缓存 -->
			<mvc:exclude-mapping path="/cache/clearAllCache"/>
            <bean class="com.hst.ces.interceptor.TokenExistInterceptor"/>
        </mvc:interceptor>
        <mvc:interceptor>
            <mvc:mapping path="/**/*.do" />
            <mvc:exclude-mapping path="/login/**" />
            <mvc:exclude-mapping path="/launch/**" />
            <mvc:exclude-mapping path="/register/**" />
            <mvc:exclude-mapping path="/license/**" />
            <!-- 放行统一认证服务 -->
            <mvc:exclude-mapping path="/oauth2/token"/>
            <mvc:exclude-mapping path="/v1/tokeninfo"/>
            <!-- 放行人脸识别-->
            <mvc:exclude-mapping path="/face/validRequest.do"/>
            <mvc:exclude-mapping path="/face/uploadFace.do"/>
			<!-- 放行级联调用的清除缓存 -->
			<mvc:exclude-mapping path="/cache/clearAllCache"/>
            <bean class="com.hst.ces.interceptor.SessionTimeoutInterceptor"/>
        </mvc:interceptor>
        <mvc:interceptor>
			<mvc:mapping path="/**/*.do*"/>
			<mvc:exclude-mapping path="/login/**" />
			<mvc:exclude-mapping path="/launch/**" />
			<mvc:exclude-mapping path="/register/**" />
			<mvc:exclude-mapping path="/license/**" />
			<mvc:exclude-mapping path="/user/*ditSelf.do" />
			<!-- 放行统一认证服务 -->
            <mvc:exclude-mapping path="/oauth2/token"/>
            <mvc:exclude-mapping path="/v1/tokeninfo"/>
            <!-- 放行人脸识别-->
            <mvc:exclude-mapping path="/face/validRequest.do"/>
            <mvc:exclude-mapping path="/face/uploadFace.do"/>
			<!-- 放行级联调用的清除缓存 -->
			<mvc:exclude-mapping path="/cache/clearAllCache"/>
			<bean class="com.hst.ces.interceptor.RightsHandlerInterceptor"/>
		</mvc:interceptor>
		 
    </mvc:interceptors>

三.开始审计

3.1: 任意文件下载

上面我们得知token是从session拿的所以这里没办法绕过,现在的思路就是在不鉴权的路由中发现漏洞,
因为存在三个拦截器并且都是拦截的所有<mvc:mapping path="/**/*.do" />,那么就得找这四个中都存在放行的,
第一个不用看我们看后面三个<mvc:exclude-mapping path="/register/**" />我们找找有没有什么安全问题代码一,
其中download明显是一个文件下载漏洞,但是不要忘记了之前的filter是存在修复,但是这里依旧可以绕过。

之前只是过滤了../但是不要忘记这个是window的程序呀通过..\就绕过了,下面图一。

3.2:添加管理员

挺奇葩的只能说,项目存在多个微服务其中存在wsdl,不知道怎么看微服务访问的话可以看一下\tomcat\conf\server.xml
文件图一,接着看这个微服务的web.xml其中发现了org.codehaus.xfire.transport.http.XFireConfigurableServlet。

<REALM CLASSNAME-‘ORG.APACHE.CATALINA-REALM.LOCKOUTREALM’> 2!– THIS REALM USES THE USERDATABASE CONFIQURED IN THE GLOBAL JNDI RESOURCES UNDER THE KEY “USERDATABASE”,ANY EDITS THAT ARE PERFORMED AGAINST THIS USERDATABASE ARE IMMEDIATELY AVAILABLE FOR USE BY THE REALM.–» CREALM CLASSNAME三”ORG:APACHE.CATALINAREALM,USERDATABASEREALM” RESOURCENAME三”USERDATABASE”/> </REALM> NAME-“LOCALHOST” UNPACKWARS-“TRUE” DEPLOYONSTARTUP-“FALSE”> HOST APPBASE,,WEBAPPS,AUTODEPLOY-,FALSE”NAME:”LOCA :—SINGLESIGNON VALVE,SHARE AUTHENTICATION BETWEEN WEB APPLICATIONS DOCUMENTATION AT://DOCS/CONFIG/VALVE.HTML –> -I> <VALVE CLASSNAME “ “ORG.APACHE.CATALINA.AUTHENTICATOR.SINGLESIGNON”/ <!- ACCESS LOG PROCESSES ALL EXAMPLE. DOCUMENTATION AT://DOCS/CONFIG/VALVE.HTML NOTE:THE PATTERN USED IS EQUIVALENT TO USING PATTERN-“COMMON’- <VANE CLASSNAME’‘ORG-APACHECATAFINAVAVAVES ERRERURTS ERURLVAVE’ SHOWREPORTS FALS FALS FALS FALSE”/ VALVE’ DRECTORY- LOGS”PATTERN二”%H %U %U AT &QUOT %6R&QUOT;%B’PREFIX- LOCALHOST ACCESS LOG’SUFFX- “TA VALVE CLASSNAME-“ORG.APACHE.CATALINA.VALVES.ACCESSLOGVALVE”S <CONTEXT PATH-“” DOCBASE “FMWEB” RELOADABLE CROSSCONTEXT-TRUE RALSE CONTEXT PATH “/AUTHSERVER”DOCBA AUTHSERVER RELOADABLE CROSSCONTEXT”TRUE <CONTEXT PATH-“/FMAPI” DOCB: “FMAPI”RELOADABLE “FALSE SCONTEXT “TRUE”/> ‘FALSE’ CROSSCONTEXT-‘TRUE”/> <CONTEXT PATH”/GTONESERVICES3.5” DOCBASE-“GTONES GTONESERVICES3.5 RELOADABLE-“FA CCONTEXT PATH:”/MEEFING-SENER RELOABLER” DOCBASE; TALE_ TASOURCE-SENER RELOADABLE_ COSSCONTEXT / </HOST> </ENGINE> </SERVICE> </SERVER> –>

接着看配置文件这里我们直接看实现图一,在图二中可以看到直接可以添加管理员用户,但是这里存在一个问题就是再登录的时候会验证
dvo.getDepartID()必须是0才代表管理员用户,但是在图二中是通过查询了数据库表里面的内容来当做dvo.getDepartID()的并不能控制,
那么再找找其他方法发现AllDepart方法。

可以看到图一存在两个参数,第一个参数存在值的时候就会去遍历这里完全没必要只需要不传入内容为空就可跳过这段代码,
那么我们就来到了图二,这里虽然我们也是通过查询出来的结果作为getDepartID代码一,但是我们可以穿一个vo.getDepartID()
这个id为0查询不到返回的就是0刚好写入插入,那么要走到else语句里面我们就需要代码2小于于0,代码其实就是查询管理员表
getNodeID对应的id查到了返回肯定大于1就会进入更新,小于零及时插入穿一个不存在的id就行了。
DepartVO dvo = DepartBO.getInstance().QueryDepartIDByBackUpDepartID(vo.getDepartID(), vo.getNodeID());
count = DepartBO.getInstance().DepartIDByDepartID(vo.getDepartID(), vo.getNodeID());

其实这里并不是通用的,因为其中会传入一个vo.getNodeID()这个id虽然在数据库中但是并不是固定的五位数字,
因为在登录的时候需要验证这个数字,当然可以直接爆破但是实战下还是。。。。