初窥JAVA代码审计

admin 2022年10月28日22:55:09评论161 views字数 6744阅读22分28秒阅读模式

0x00 写在开头

国庆假期开了个新副本,学习了下java的语法和java中owasp top 10漏洞代码产生,本文审计项目是《java代码审计实战》实战的一个项目拿来练练手,初窥代码审计照葫芦画瓢跟着思路分析一下,刚上手java代码审计,文章内容有描述不严谨的地方师傅们多多指教。

0x01 环境搭建

ofcms是一个java 版CMS系统、基于java技术研发的内容管理系统、功能:栏目模板自定义、内容模型自定义、多个站点管理、在线模板页面编辑等功能、代码完全开源,技术选型:jfinal DB+Record mysql freemarker Encache spring 等 layui zTree bootstrap。

源代码下载:

https://gitee.com/oufu/ofcms/tree/V1.1.2/

下载之后idea打开目录,idea会自动解析所需要的包,还需要下载一个tomcat环境包。

tomcat下载 

https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.68/bin/apache-tomcat-9.0.68-windows-x64.zip

文件下载好之后配置运行环境,在idea里面配置好tomcat运行配置。

初窥JAVA代码审计

部署配置

初窥JAVA代码审计

配置好之后再修改数据库配置文件,ctrl + shift + f全局搜索jdbc.username关键词可以找到数据库配置文件。

初窥JAVA代码审计

修改成数据库的对应配置,数据库我这里用的vm vctl起的一个环境,vctl类似docker但是比docker难用,也可以用phpstudy起方便一些。

vctl system start // 启动vctlvctl pull mysql:5.7 // 拉取镜像// 运行服务 注意这里要以管理员用户运行,因为这里我做了目录持久化挂载vctl run -p 3306:3306 --name mysql $PWD/conf:/etc/mysql -v $PWD/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7// 进入容器操作vctl exec -it mysql /bin/bash// mysql 语句执行 确保外面可以连接GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;

数据库创建

create database ofcms charset utf8;
use ofcms;

数据库文件导入,数据库文件在doc/sql/ofcms-v1.2.2.sql下,可以通过命令行导入也可以直接用navicat导入。

运行环境

初窥JAVA代码审计

登陆到后台确定环境运行正常

初窥JAVA代码审计

0x02 漏洞审计

后台大概看了下功能模块

  • 代码生成

  • 模板编辑

  • 通知管理

  • 留言管理

文件读取漏洞

漏洞位置:后台=>模板设置=>模板文件

根据网站路由关键词全局搜索所在代码行getTemplates

初窥JAVA代码审计

定位到代码在TemplateController文件28行

初窥JAVA代码审计双击阅读代码,看代码的传参和功能实现逻辑,下面两个关键词方法是需要关注的点,getPare方法获取请求中的内容赋值传递给对应的方法。

  • 传参 getPara方法

  • 赋值 setattr 方法

搜索getPara关键词,获取到以下参数

String dirName = getPara("dir","");//上级目录String upDirName = getPara("up_dir","/");//类型区分String resPath = getPara("res_path");String fileName = getPara("file_name", "index.html");

根据网站后台抓包确定在模板目录传参使用了dir、up_dir

初窥JAVA代码审计

成功定位到传递的参数内容,跟进dirName使用位置

if(!"/".equals(upDirName)){      dir = upDirName+dirName;}else{      dir = dirName;}

这里使用了一个路径拼接,首先做了一个判断如果upDirName也就是前端传入参数up_dir不等于"/"那么执行下面的路径拼接,如果没有传入up_dir参数,那么默认值"/"就会走到41行。

初窥JAVA代码审计

跟进dir传递处理后传递给了pathFile

初窥JAVA代码审计

这里做了一个过滤,在文件列表显示时候只获取.html .xml .js文件后缀并返回到files文件数组。

初窥JAVA代码审计74行setAttr files数组为files参数,77行做了一个文件名判断不为空这里75行这里默认值是index.html,files数组不为空还有files数组长度不为空,进入78行for循环,如果fileName等于f.getName那么就确定了需要编辑的文件赋值给editFile,91行做了一个editFile是否为空,然后读取文件setAttr返回给前端页面,大概代码逻辑图

初窥JAVA代码审计

图-文件读取漏洞代码逻辑-1

通过上面的代码流程逻辑的分析,dir、file_name没有做任何的过滤处理传递到后端传递到92行FileUtils.readString方法读取文件。

尝试构造路径穿越读取上级路径和文件,但是这里因为限制了读取文件的类型,所以利用的点很有限,但是读取路径信息是没有问题的。

初窥JAVA代码审计

通过burp构造数据包成功获取到tomcat路径信息

初窥JAVA代码审计

传递file_name参数获取到对应文件内容,但是在读取白名单以外的文件后缀就没办法了,图-文件读取漏洞代码逻辑-1 79行代码起了作用。

初窥JAVA代码审计

获取文件内容失败

文件写入漏洞

模板编辑在保存的时候有写入文件的操作,跟进对应路由admin/cms/template/save.json初窥JAVA代码审计

完整代码如下

public void save() {    String resPath = getPara("res_path");    File pathFile = null;    if("res".equals(resPath)){        pathFile = new File(SystemUtile.getSiteTemplateResourcePath());    }else {        pathFile = new File(SystemUtile.getSiteTemplatePath());    }    String dirName = getPara("dirs");    if (dirName != null) {        pathFile = new File(pathFile, dirName);    }    String fileName = getPara("file_name");    // 没有用getPara原因是,getPara因为安全问题会过滤某些html元素。    String fileContent = getRequest().getParameter("file_content");    fileContent = fileContent.replace("&lt;", "<").replace("&gt;", ">");    File file = new File(pathFile, fileName);    FileUtils.writeString(file, fileContent);    rendSuccessJson();}

还是和上面一样找出传递了哪些参数,传递了res_path、dirs、file_name、file_content参数,刚才在浏览器抓包的时候也可以看到通过POST请求传递了以下内容

file_path=D:apache-tomcat-9.0.68webappsofcms_admin_warWEB-INFpagedefaultindex.html&dirs=/&res_path=&file_name=index.html&file_content=<#assign+column_name='/'/>

内容我截取了部分内容,通过分析代码file_path、dirs、file_name、file_content都没有经过过滤,可以通过路径穿越的方式向上级指定目录写任意文件,

两种利用方式

利用方式1

通过dirs控制写的路径

初窥JAVA代码审计

利用方式1

通过file_name控制写的路径

初窥JAVA代码审计

可以写入jsp到对应的静态文件路径达到getshell目的

模板注入漏洞

漏洞位置:后台=>模板设置=>模板文件

编辑模板文件,在index.html头部加上以下内容

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

命令执行成功

初窥JAVA代码审计

任意文件上传

文件上传功能都是使用的com.jfinal.upload.UploadFile类

漏洞位置:

漏洞位置1 后台=>运营管理=>友情链接=>编辑上传图片

初窥JAVA代码审计

漏洞位置2 后台=>内容管理=>文章管理=>编辑上传图片

初窥JAVA代码审计

任意文件上传的位置有多处,jsp可以上传但是存在一个问题,只有目录包含了static/的路径才可以解析,没办法控制上传文件的路径。

漏洞位置1

ComnController.java文件101行upload、editUploadImage方法

@Clearpublic void upload() {    try {        UploadFile file = this.getFile("file", "image");        file.getFile().createNewFile();        Map<String, Object> data = new HashMap<String, Object>();        data.put("filePath", "/upload/image/" + file.getFileName());        data.put("fileName", file.getFileName());        rendSuccessJson(data);    } catch (Exception e) {        rendFailedJson(ErrorCode.get("9999"));    }}
@Clearpublic void editUploadImage() {try { UploadFile file = this.getFile("file", "image"); file.getFile().createNewFile(); Map<String, Object> msg = new HashMap<String, Object>(); Map<String, Object> data = new HashMap<String, Object>(); data.put("src", SystemUtile.getParam("http_image_url") + "/upload/image/" + file.getFileName()); data.put("title", file.getFileName()); msg.put("data", data); msg.put("code", 0); msg.put("msg", "处理成功"); rendJson(msg);} catch (Exception e) { rendFailedJson(ErrorCode.get("9999"));}}

jfinal-3.2自带的一个文件后缀过滤

初窥JAVA代码审计

用windows特性绕过上传文件成功

初窥JAVA代码审计

漏洞位置2

UeditorAction.java文件uploadImage、uploadFile、uploadVideo、uploadScrawl方法都可以上传jsp文件,同样目录不可控无法解析。

示例

初窥JAVA代码审计

sql注入

漏洞位置:后台=>系统设置=>代码生成=>增加表

随便输入了一个字符点击新增,出现sql报错信息

初窥JAVA代码审计

根据路由system/generate定位到对应代码

初窥JAVA代码审计

ctrl + b根据传参跟进到48行代码

初窥JAVA代码审计

跟进到Db.java文件252行

初窥JAVA代码审计

继续跟进一步一步跟进到Db.pro.java文件282行,代码如下

int update(Config config, Connection conn, String sql, Object... paras) throws SQLException {    PreparedStatement pst = conn.prepareStatement(sql);    config.dialect.fillStatement(pst, paras);    int result = pst.executeUpdate();    DbKit.close(pst);    return result;}

update传参sql到conn.prepareStatement(sql),创建了一个pst PreparedStatement对象,pst.executeUpdate()执行执行了传入的sql语句,但是这里sql语句是update语句才会生效,构造一个update报错语句测试。

初窥JAVA代码审计

成功报错获取到数据库名,使用sqlmap构造数据包,使用python .sqlmap.py -r 23.txt --batch,ad_id=*标记注入位置。

POST /ofcms_admin_war/admin/system/generate/create.json?sqlid= HTTP/1.1Host: localhost:8080Content-Length: 62sec-ch-ua: "Chromium";v="105", "Not)A;Brand";v="8"Accept: application/json, text/javascript, */*; q=0.01Content-Type: application/x-www-form-urlencoded; charset=UTF-8X-Requested-With: XMLHttpRequestsec-ch-ua-mobile: ?0User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.5195.102 Safari/537.36sec-ch-ua-platform: "Windows"Origin: http://localhost:8080Sec-Fetch-Site: same-originSec-Fetch-Mode: corsSec-Fetch-Dest: emptyReferer: http://localhost:8080/ofcms_admin_war/admin/f.html?p=system/generate/add.htmlAccept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9Cookie: JSESSIONID=9D780D7FDD8ED8688D718D3A37146EF9; Webstorm-ab1afb59=f884fe2b-ed88-4d51-8544-41e503afa445; JSESSIONID=4E086CA062A4826D64252774316AAE49; XSRF-TOKEN=4802db00-a6e2-46fa-87ac-5e29f6f65d5b; remember-me=YWRtaW46MTY2NzM5MzczMjA3NTozYzJmODhlYWE1YmI3ODBkZmVjNjI1N2EzZWM3YjhkNQConnection: close
sql=update of_cms_ad set ad_id=*

成功利用sqlmap获取数据库名、表名

初窥JAVA代码审计

0x03 总结

第一次审计跟着文章还有书照葫芦画瓢,对框架审计有个大概的了解,正向开发能力还是不够,遇到不知道的函数方法只有跟着百度和debug代码输出内容还有作用

0x04 参考文章

《网络安全 java代码审计实战》书籍实战篇

酒仙桥六号部队文章

https://www.secpulse.com/archives/185233.html

java 基础知识

https://blog.csdn.net/weixin_42504649/article/details/114615038

Java SSTI freemarker

https://www.cnblogs.com/CoLo/p/16706091.html

ofcms审计扩展 

https://sec-in.com/article/281

jfinal  

https://blog.csdn.net/nfgch/article/details/106733234

往期回顾

从sql注入到内网

HackTheBox:10.10.10.180靶机记录

vulnhub:CHILL HACK靶机记录

回炉重造 | 精通php反序列化之道


·END·
 


泛星安全团队

初窥JAVA代码审计


原文始发于微信公众号(泛星安全团队):初窥JAVA代码审计

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年10月28日22:55:09
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   初窥JAVA代码审计http://cn-sec.com/archives/1377318.html

发表评论

匿名网友 填写信息