大柚子

这世界不过如此

一、前言

近来在开始学习java的代码审计,故决定审计一波经典的铁人下载系统,安装过程这里就省略了,源码里有安装教程。

二、漏洞挖掘

非框架的代码审计,按照前台–后台,严重–低危,非交互–需交互,跟随代码流程尽量发现高危和易利用漏洞类型为主。

1、重安装漏洞

在之前安装的时候,会出现自动安装失败的情形,但是/install目录的重新安装页面是没有删除的。如果按照系统自带的安装是不存在重新安装漏洞的。让我们分析下安装的代码逻辑。

分析/install/index.html页面,在确认提交后会到/install/install.jsp文件继续跟进install.jsp,调用/install/install_setup.jsp

分析/install/install_setup.jsp发现会import语句

找到安装的主要逻辑代码,在WEB-INF/java/liuxing/util/Install.java中,安装时du方法会判断db_an的值,如果是yes可以安装,no不安装

通过在安装完后,updateConfig方法会将db_an的值设置为no,故虽然install页面没有删除,但是已经不能再次安装了。

所以,使用系统自带的安装功能时,不存在重安装漏洞;但是如果手工导入sql文件安装系统,自己又没有吧db_an的值写成no,没有删除install目录文件时,存在重安装漏洞。

2、SQL注入漏洞

首先测试首页搜索功能,发现调用“so.jsp”文件,且传入的参数为“name”,跟进

分析“so.jsp“文件,搜索传入的”name“参数值会传入”Ruanjianguanli“的“so”方法中,继续跟进

分析WEB-INF/java/liuxing/guanli/Ruanjianguanli.java类的so方法,调用了ruanjianDao.so()函数

ruanjianDao是什么,在Ruanjianguanli.java类的构造函数里,ruanjianDao是RuanjianMySQL的一个实例,继续跟进

分析WEB-INF/java/liuxing/dao/RuanjianMySQL.java类,搜索其中的”so“方法,发现最终的采用的是预编译来执行数据库操作的,这里不存在SQL注入漏洞。(注:并不是采用预编译就不存在漏洞,有的参数可能会忽略)

一般来说,有一处用了预编译,说明很多处都用了预编译的方式执行sql语句(不排除有些参数没有提前使用占位符,而是直接拼接)。我们可以全局搜索(execteQuery、createStatement、PreparedStatement、connection等)函数,排查是否存在直接拼接的SQL语句。

如上图所示,还是有蛮多的,但是存在漏洞的点还有待排查,基本都是需要登录台才能利用。(注:一方面是create Statement,其次方法中传入的 参数是string类型,且参数会拼接进sql语句中),如下示例:

在UserDaoMySQL.java类中有个“Shanchuyonghu“方法,在这个方法中会传入一个String类型的”ids“数组,该数组的第一个元素会拼接进sql语句中,最终拼接的sql语句为” delete from user where id in (‘ids[0],ids[1]…,ids[i]’) “,最终sql语句直接被“executeUpdate”方法直接调用

跟进,谁调用了UserDaoMySQL.java类的“Shanchuyonghu”方法(idea选中方法,右键有个“find user”),我这里是全局搜索,发现”Delete.jsp“和“guanliyonghu.jsp”调用了“Shanchuyonghu”方法,进行分析。

(1)分析Delete.jsp,里面代码的功能为将网页请求的id参数的值直接传入sid数组,sid数组的值直接传入“shanchuyonghu”方法,故id的值是用户可控的,这里存在sql注入漏洞。

Delete.jsp在网页中的位置为“/liuxing/admin/left6/Delete.jsp”,这里需要先登录后台,可以构造时间盲注语句


/liuxing/admin/left6/Delete.jsp?pageNo=1&id=2%27)+or+if(ascii(substr(database(),1,1))%3E107,0,sleep(5))--+

(2)再来分析guanliyouhu.jsp,其代码功能为获取checkbox2参数的值,在前端代码中,checkbox2是表单中的一个选择框,这里是把选中的行数据放到数组里。

在guanliyouhu.jsp中,checkbox2参数的值赋值为str数组,str数组的值赋值给shanchuyonghu方法,我们进一步跟踪能否控制checkbox2参数的值,在guanliyouhu.jsp中,说明了id、pageNo等值的来源,这里是没有办法控制的,故不存在SQL注入点。

3、XSS漏洞

因为系统比较简单,前台能够产生xss的地方比较少,会员注册后,登录,在修改邮箱处,存在XSS漏洞,键入payload:


""><script>alsrt(111)</script>

分析此处功能实现代码,请求接口文件为“denglu1.jsp”,里面将要修改的youxiang和id参数的值传入了“Userguanli”的“xiugaiyonghu2”方法中,跟进

在WEB-INF/java/liuxing/dao/UserDaoMySQL.java类的Xiugaiyonghu2方法中调用了userDao函数,userDao是UserDaoMySQL的一个实例,继续跟踪UserDaoMySQL中Xiugaiyonghu2方法。

在“UserDaoMySQL”中“Xiugaiyonghu2”方法中可以看到,直接将前端传过来的youxiang值写入数据库,没有任何安全防护,从而导致了存储型XSS

在后台管理员功能处修改用户邮箱处也会触发xss,实现方法是”UserDaoMySQL”中“Xiugaiyonghu”方法 ,本质是一样的。

且在前端denglu1.jsp中,邮箱的值是直接从数据库中获取的。

4、访问控制

在没有登录账户的时候,访问/admin/admin.jsp页面,会被重定向到/buzai.htm页面。打开admin.jsp页面,看看里面的跳转逻辑,搜索关键字:


RequestDispatcher
getRequestDispatcher
sendRedirect
setHeader
forward

没有发现跳转的语句,判断是全局Filter的权限认证。查看WEB-INF/web.xml,发现针对所有jsp文件的AuthFilter过滤器。

跟进filter-class,找到WEB-INF/java/liuxing/util/AuthFilter.java文件,分析doFilter函数:

关键语句在于两个if判断:

如果路径不是指定的4个安装系统相关的路径,会尝试从数据库的lujing表中查询web路径。(注:这里需要跟进WEB-INF/java/liuxing/util/LuJing.java文件翻看代码,里面为找到路径返回“false“,没找到路径返回”true”),所以对于数据库中不存在的管理员路径/admin/admin.jsp,返回true。如果这时候访问者没有session,或者读不到admin的session,就会返回true,然后就被重定向到/buzai.htm页面。

所以,这里也不存在越权访问页面什么的漏洞。程序用session中的user和admin属性区分普通用户和管理员用户,猜想
也没有垂直越权之类的漏洞,没有仔细查看。根据session中的id属性区分普通用户,平行越权也放弃了查找(还是我太菜)

5、后台任意文件上传漏洞

在登录后台后,“其他管理”–“添加友情链接”、“软件管理”–“软件发布”页面,都可以上传文件,在web.xml中或者顺着jsp页面调用寻找,都能够找到具体的逻辑代码。

几个类的内部代码看起来差不多,我们以WEB-INF/java/liuxing/util/shanchuan2.java文件为例,关键代码如下:


 try {
         List fileItems = upload.parseRequest(req);
         Iterator iter = fileItems.iterator();
         String regExp = ".+\\\\(.+)$";
         String[] errorType = new String[]{".exe", ".com", ".cgi", ".asp"};
         Pattern p = Pattern.compile(regExp);

         while(true) {
            FileItem item;
            String name;
            long size;
            do {
               do {
                  if (!iter.hasNext()) {
                     return;
                  }

                  item = (FileItem)iter.next();
                  if (item.isFormField() && item.getFieldName().equals("date")) {
                     date = item.getString();
                  }
               } while(item.isFormField());

               name = item.getName();
               size = item.getSize();
            } while((name == null || name.equals("")) && size == 0L);

            Matcher m = p.matcher(name);
            boolean result = m.find();
            if (!result) {
               throw new IOException("无法上传");
            }

            for(int temp = 0; temp < errorType.length; ++temp) {
               if (m.group(1).endsWith(errorType[temp])) {
                  throw new IOException(name + ": wrong type");
               }
            }

            try {
               String names = m.group(1);
               String men = this.getExt(names);
               item.write(new File(this.getServletContext().getRealPath("/") + "wen/" + date + men));
               res.sendRedirect("../admin/left3/chenggong2.jsp?" + date + men);
            } catch (Exception var21) {
               out.println(var21);
            }
         }
      } catch (IOException var22) {
         out.println(var22);
      } catch (FileUploadException var23) {
         out.println(var23);
         out.println("文件大小超出限制");
      }

   }

其中会先判断上传的文件名,要符合正则表达式“.+\\\\(.+)$”,才能够正常上传。即形似xxx\\xx的文件名,估计是为了匹配Windows路径中的\,比如C:\a.jpg。定义了内部禁止的后缀名”.exe”,”.com”,”.cgi”,”.asp”,这就是唯一的过滤方式了。

继续往下看,写文件时,关键的一句代码:


item.write(new File(this.getServletContext().getRealPath("/") + "wen/" + date + men));

即将文件存放在/wen目录下,保存为date+men形式的文件名,两者都是可以控制的,直接修改写shell。

三、总结

还是java基础不行,只能跟着前人脚步走,但这也算是自己一些学习记录吧,后续加油

Print Friendly, PDF & Email

发表回复

您的电子邮箱地址不会被公开。