• Java代码审计-因酷网校在线教育系统-越权漏洞分析


    登录个人账号后,点击基本资料。有更新资料的功能。

    2bad4101b46b41f38906a7bf559a0f27.png

    查看这个页面的html源码,进行代码审计。(这点怎么通过源码怎么找到的就不提了,写上实在啰嗦了。)

    代码jsp页面源码如下,查看这个表单信息

    注意:hidden 属性---这是一会越权的伏笔

    1. <div class="u-account-box">
    2.      <form method="post" id="updateForm">
    3.         <input type="hidden" name="user.userId" value="${user.userId}" />
    4.         <ol class="u-account-li">
    5.            <li>
    6.               <label class="u-a-title">
    7.                  <span class="fsize16 c-999">邮 箱span>
    8.               label>
    9.               <input type="text" class="u-a-inpt" name="${user.email}" value="${user.email}" placeholder="" readonly="readonly" disabled="disabled">
    10.              
    11.            li>
    12.            <li>
    13.               <label class="u-a-title">
    14.                  <span class="fsize16 c-999">手机号span>
    15.               label>
    16.               <input type="text" class="u-a-inpt" name="user.mobile" value="${user.mobile }" placeholder="" readonly="readonly" disabled="disabled">
    17.              
    18.            li>
    19.            <li>
    20.               <label class="u-a-title">
    21.                  <span class="fsize16 c-999">姓 名span>
    22.               label>
    23.               <input type="text" class="u-a-inpt" name="user.userName" value="${user.userName }" placeholder="" >
    24.              
    25.            li>
    26.            <li>
    27.               <label class="u-a-title">
    28.                  <span class="fsize16 c-999">昵 称span>
    29.               label>
    30.               <input type="text" class="u-a-inpt" name="user.showName" value="${user.showName}" placeholder="">
    31.              
    32.            li>
    33.            <li>
    34.               <label class="u-a-title">
    35.                  <span class="fsize16 c-999">性 别span>
    36.               label>
    37.               <input type="radio" name="user.sex" <c:if test="${user.sex==1}">checked="checked"c:if> value="1"/><span class="vam fsize14 c-666">span>
    38.               <input type="radio" name="user.sex" <c:if test="${user.sex==2}">checked="checked"c:if> value="2"/><span class="vam fsize14 c-666">span>
    39.              
    40.            li>
    41.            <li>
    42.               <label class="u-a-title">
    43.                  <span class="fsize16 c-999">年 龄span>
    44.               label>
    45.               <select name="user.age">
    46.                     <option value="0">0岁option>
    47.                     <c:forEach var="age" begin="1" end="110">
    48.                        <option <c:if test="${user.age==age}">selectedc:if> value="${age}">${age}岁option>
    49.                     c:forEach>
    50.               select>
    51.              
    52.            li>
    53.         ol>
    54.      form>
    55.      <div class="ml50 mt50 pl50">
    56.         <a href="javascript:void(0)" title="" class="comm-btn c-btn-7" onclick="updateUserInfo()">提 交a>
    57.      div>
    58.   div>

    找到提交触发的js代码

    user.js

    1. /**
    2. * 修改用户信息
    3. * @param userId 用户ID
    4. */
    5. function updateUserInfo(userId){
    6.   var params='';
    7.   $("#updateForm input,#updateForm select").each(function(){
    8.      params+=$(this).serialize()+"&";
    9.   });
    10.   $.ajax({
    11.      url:baselocation+'/uc/updateUser',
    12.      type:'post',
    13.      dataType:'json',
    14.      data:params,
    15.      success:function(result){
    16.         if(result.success==true){
    17.            showUserInfo();
    18.            dialog('提示信息',result.message,0);
    19.         }else{
    20.            dialog('提示信息',result.message,1);
    21.         }
    22.     }
    23.   });
    24. }

    这段代码是使用 jQuery 来收集表单中的输入字段(input)和选择字段(select),并将其序列化为 URL 参数字符串的示例。

    具体来说,代码首先声明了一个变量 params,用于存储最终生成的参数字符串。然后使用 jQuery.each() 方法遍历了 #updateForm input#updateForm select 两个选择器选中的元素。

    在遍历过程中,对于每个选中的元素,调用了 .serialize() 方法来序列化该元素,将其转换为 URL 编码的参数字符串。然后将得到的参数字符串添加到 params 变量中,通过字符串拼接的方式进行累加。最后,在每个字段之间添加了 & 字符串作为分隔符。

    通过这段代码的执行,你可以得到一个类似于 param1=value1¶m2=value2¶m3=value3 的参数字符串。它包含了表单中所有输入字段和选择字段的名称和值的对应关系。

    这段代码使用了 jQuery 的 $.ajax() 方法来向服务器发送一个 AJAX 请求,并处理服务器返回的结果。

    具体来说,代码中的 $.ajax() 方法包含了一个对象参数,其中包括以下属性:

    • url: baselocation+'/uc/updateUser':指定了请求的 URL 地址,这里的 baselocation 是一个变量或常量,表示基本的请求地址。

    • type: 'post':指定了请求的 HTTP 方法为 POST。

    • dataType: 'json':指定了期望的服务器响应数据类型为 JSON,这样 jQuery 会自动解析响应结果并将其转换为 JavaScript 对象。

    • data: params:指定了请求的数据内容,这里的 params 是之前生成的参数字符串。

    • success: function(result) { ... }:指定了当请求成功完成后的回调函数。其中,result 是服务器返回的响应数据。

    success 回调函数中,首先判断 result.success 是否为真(即 true)。若为真,则调用 showUserInfo() 函数展示用户信息,并通过 dialog() 函数显示一个提示信息框,其中 result.message 是成功消息内容。若 result.success 不为真,则同样通过 dialog() 函数显示一个提示信息框,其中 result.message 是失败消息内容。

    整个代码的作用是向 baselocation+'/uc/updateUser' 发送一个带有参数的 POST 请求,然后根据服务器返回的结果动态更新页面上的内容和显示提示信息。

    请注意,在运行此代码之前,确保引入了 jQuery 库,并在页面加载完毕后执行代码,或将代码放置在合适的事件处理程序中。

    如果你需要进一步的帮助,请提供更多上下文或相关代码。

    根据post提交的接口,/uc/updateUser,/uc 为指定的拦截器 ,

    站点spring-mvc.xml文件

    1. <mvc:interceptor>
    2.    <mvc:mapping path="/uc/*"/>
    3.    <mvc:mapping path="/uc/**/*"/>
    4.    <mvc:exclude-mapping path="/uc/tologin"/>
    5.    <mvc:exclude-mapping path="/uc/getloginUser"/>
    6.    <mvc:exclude-mapping path="/uc/register"/>
    7.    <mvc:exclude-mapping path="/uc/createuser"/>
    8.    <mvc:exclude-mapping path="/uc/login"/>
    9.    <mvc:exclude-mapping path="/uc/passwordRecovery"/>
    10.    <mvc:exclude-mapping path="/uc/sendEmail"/>
    11.    <bean class="com.inxedu.os.common.intercepter.IntercepterWebLogin">
    12.    bean>
    13. mvc:interceptor>

    IntercepterWebLogin继承HandlerInterceptorAdapter类

    class IntercepterWebLogin extends HandlerInterceptorAdapter

    具体来说,HandlerInterceptorAdapter 类可以实现以下功能:

    1. preHandle 方法:在请求处理之前执行的方法。可以用来进行登录状态验证、权限检查、日志记录等操作。如果该方法返回 true,则表示允许进入下一步的处理(比如调用控制器方法),如果返回 false,则表示拦截该请求。

    2. postHandle 方法:在请求处理之后、视图渲染之前执行的方法。可以用来修改请求的响应或处理其他后续操作。

    3. afterCompletion 方法:在整个请求完成后执行的方法。可用于进行一些资源清理或处理善后工作。

    /updateUser 就为我们响应的方法了,一定位于某个controller中。底层用反射机制实现的方法调用。

    定位的到响应的RequestMapping,也可以全局搜索updateUser定位到该方法。

    1. /**
    2.    * 修改用户信息
    3.    */
    4.   @RequestMapping("/updateUser")
    5.   @ResponseBody
    6.   public Map updateUserInfo(HttpServletRequest request){
    7.      Map json = new HashMap();
    8.      try{
    9.         String userName=request.getParameter("userName");//姓名
    10.         if(userName==null||userName.trim().equals("")){
    11.            json=this.setJson(false, "姓名不能为空", null);
    12.            return json;
    13.         }
    14.         String showName=request.getParameter("showName");//昵称
    15.         if(showName==null||showName.trim().equals("")){
    16.            json=this.setJson(false, "昵称不能为空", null);
    17.            return json;
    18.         }
    19.         String sex=request.getParameter("sex");//性别 1男 2女
    20.         if(sex==null||sex.trim().equals("")){
    21.            json=this.setJson(false, "性别不能为空", null);
    22.            return json;
    23.         }
    24.         String age=request.getParameter("age");//年龄
    25.         if(age==null||age.trim().equals("")){
    26.            json=this.setJson(false, "年龄不能为空", null);
    27.            return json;
    28.         }
    29.         String userId=request.getParameter("userId");//用户Id
    30.         if(userId==null||userId.trim().equals("")){
    31.            json=this.setJson(false, "用户Id不能为空", null);
    32.            return json;
    33.         }
    34.         User user=new User();
    35.         user.setUserId(Integer.parseInt(userId));//用户Id
    36.         user.setUserName(userName);//姓名
    37.         user.setShowName(showName);//昵称
    38.         user.setSex(Integer.parseInt(sex));//性别
    39.         user.setAge(Integer.parseInt(age));//年龄
    40.         userService.updateUser(user);//修改基本信息
    41.         json = this.setJson(true, "修改成功", user);
    42.     }catch (Exception e) {
    43.         json=this.setJson(false, "异常", null);
    44.         logger.error("updateUserInfo()---error",e);
    45.     }
    46.      return json;
    47.   }
    48. }

    @ResponseBody 不用管,这是底层为维护方法返回的json数据所增加的注解。

    这段代码是一个用于更新用户信息的方法。具体功能如下:

    1. 通过 HttpServletRequest 对象获取请求参数,包括 userName(姓名)、showName(昵称)、sex(性别)、age(年龄)和 userId(用户Id)等信息。

    2. 对每个参数进行非空判断,如果有任何一个参数为空或空字符串,则返回一个包含错误信息的 json 对象。

    3. 如果所有参数都不为空,则根据获取的参数创建一个 User 对象,并设置相应的属性值。

    4. 调用 userService.updateUser(user) 方法来更新用户的基本信息。

    5. 如果更新成功,返回一个包含成功信息和更新后的 user 对象的 json 对象;如果出现异常,则返回一个包含异常信息的 json 对象。

    user对象没有对用户输入的数据做验证,平且所有的数据字段我们都可以控制。直接set传进来的参数,执行updateUser,这就非常像越权漏洞了。

    正确的做法应该是,登录的用户只能修改自己的相关信息,用户Id(唯一键值)应该是固定自己的。

    这里就没有必要往下看了,因为之后在updateUser中做本用户的验证几率不大。

    如果不放心可以追进这个方法里,看看有没有对输入的数据做验证!是不是按照流程将指定的user参数进行更新。

    ........
     

    小彩蛋:仔细思考这个表单是否存在CRSF漏洞呢!................

  • 相关阅读:
    Vue第1天:特性概览
    接口测试用例设计
    论文阅读【5】Attention Is All You Need
    postman进行批量测试的步骤
    常用的git相关问题汇总
    利用MySQL主从复制延迟拯救误删数据
    基于SSM的宠物综合服务平台的设计与实现
    java计算机毕业设计奢品网站系统源码+系统+数据库+lw文档+mybatis+运行部署
    数据分析三剑客之一:Pandas详解
    相机数据恢复!详细步骤解析(2023新版)
  • 原文地址:https://blog.csdn.net/shelter1234567/article/details/133937216