jfinal_cms-v5.1.0 审计黑盒

00x0不登录

0x0接口收集

前端

java 复制代码
front/article/
front/articlelike/no/
front/articlelike/yes/
front/comment/count
front/comment/del
front/comment/save
front/person/delblog/
front/regist/save
front/tags/

大部分是接口,但有登录鉴权

这个我猜测是文章点赞取消的接口,但是做了鉴权处理

代码分析(没完全明白)
java 复制代码
@ControllerBind(controllerKey = "/front/articlelike")
public class ArticleLikeController extends BaseProjectController {

	/**
	 * 喜欢
	 * 
	 * 2015年8月16日 下午4:20:10
	 * flyfox 369191470@qq.com
	 */
	public void yes() {
//获取get后面的id
//框架会自动创建实例getParaToInt()
		Integer articleId = getParaToInt();
//创建一个json实例
		JSONObject json = new JSONObject();
//放入操作
		json.put("status", 2);// 失败
//鉴权处理
		SysUser user = (SysUser) getSessionUser();
//如果没有登录
		if (user == null) {
			json.put("msg", "没有登录,不能操作!");
//读取返回
			renderJson(json.toJSONString());
			return;
		}
//如果没有id
		if (articleId == null || articleId <= 0) {
			json.put("msg", "操作异常");
			renderJson(json.toJSONString());
			return;
		}
java 复制代码
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
public @interface ControllerBind {
	String controllerKey();

	String viewPath() default "";
}
java 复制代码
@Override
	@SuppressWarnings({ "rawtypes", "unchecked" })
//方法标签,这是一个普通方法(可能在某个自定义的 Routes 子类中,比如 AutoBindRoutes),用于执行自动绑定逻辑。
	public void config() {
//ClassSearcher 是项目自带的工具类,用于在类路径和指定的 JAR 包中查找类。
		List<Class<? extends Controller>> controllerClasses = ClassSearcher.findInClasspathAndJars(Controller.class,
				includeJars);

		ControllerBind controllerBind = null;
//for遍历,扫描所有controller子类
		for (Class controller : controllerClasses) {
//排除指定的类(可选)
			if (excludeClasses.contains(controller)) {
				continue;
			}

//获取注释controllerBind = (ControllerBind)controller.getAnnotation(ControllerBind.class)

			controllerBind = (ControllerBind) controller.getAnnotation(ControllerBind.class);
//检查controllerBind是否为空
//通过反射获取该类上标注的 @ControllerBind 注解实例。如果没有标注,controllerBind 为 null。
			if (controllerBind == null) {
//检查全局开关
				if (!autoScan) {
					continue;
				}
//判断类名是否以suffix结尾
				if (!controller.getSimpleName().endsWith(suffix)) {
					logger.debug("routes.add " + controller.getName() + " is suffix not " + suffix);
					continue;
				}
				
				this.add(controllerKey(controller), controller);
				logger.debug("routes.add(" + controllerKey(controller) + ", " + controller.getName() + ")");
			} else if (StrKit.isBlank(controllerBind.viewPath())) {
				this.add(controllerBind.controllerKey(), controller);
				logger.debug("routes.add(" + controllerBind.controllerKey() + ", " + controller.getName() + ")");
			} else {
				this.add(controllerBind.controllerKey(), controller, controllerBind.viewPath());
				logger.debug("routes.add(" + controllerBind.controllerKey() + ", " + controller + ","
						+ controllerBind.viewPath() + ")");
			}
		}
	}
java 复制代码
//静态方法

public static <T> List<Class<? extends T>> findInClasspathAndJars(Class<T> clazz, List<String> includeJars) {
		String path = PathUtils.rebuild(classPathUrl.getFile());
		List<String> classFileList = findFiles(path, "*.class");
		String libPath = PathUtils.rebuild(lib);
		classFileList.addAll(findjarFiles(libPath, includeJars));
		return extraction(clazz, classFileList);
	}

7跳转首页

收集

复制代码
http://localhost:8080/jfinal_cms/admin/
http://localhost:8080/jfinal_cms/login/
http://localhost:8080/jfinal_cms
http://localhost:8080/jfinal_cms/front/regist.html

0x1 框架信息

大部分对的

0x2 xss

有/过滤,并且<>不会渲染

感觉是原来有,但是被修复了。

代码分析(未完成)
java 复制代码
@ControllerBind(controllerKey = "/front/tags")
public class TagsController extends BaseProjectController {

	public static final String path = "/tags/";

	@Before(FrontInterceptor.class)
	public void index() {
//获取get后面的值
		String tagName = getPara();
		try {
//如果空的,就默认
			tagName = (tagName == null ? "" : tagName);
//
			tagName = URLDecoder.decode(tagName, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}

		// 去除标签
		tagName = HtmlUtils.delHTMLTag(tagName);
		// 更新tag
		tagName = HtmlUtils.delSpecialCode(tagName);

		setAttr("tagName", tagName);

		// 数据列表,只查询展示的和类型为11,12的
		Page<TbArticle> articles = TbArticle.dao.paginate(getPaginator(), " select a.*", //
				" from (select distinct t.*  from tb_article t " //
						+ " left join tb_folder tf on tf.id = t.folder_id " //
						+ " left join tb_tags tag on tag.article_id = t.id " //
						+ " where (tag.tagname like ? or t.title like ?) " //
						+ " and t.status = 1 and t.type in (11,12)  " // 查询状态为显示,类型是预览和正常的文章
						+ " and tf.site_id = " + getSessionSite().getSiteId() //
						+ " order by t.sort,t.create_time desc ) a", "%" + tagName + "%", "%" + tagName + "%");
		setAttr("page", articles);

		// 显示50个标签
		if (articles.getTotalRow() > 0) {
			Page<TbTags> taglist = new FrontCacheService().getTagsByFolder(new Paginator(1, 50), articles.getList()
					.get(0).getFolderId());
			setAttr("taglist", taglist.getList());
		} else {
			Page<TbTags> taglist = new FrontCacheService().getTags(new Paginator(1, 50), getSessionSite().getSiteId());
			setAttr("taglist", taglist.getList());
		}

		// seo:title优化
		setAttr(JFlyFoxUtils.TITLE_ATTR, tagName + " - 搜索 - " + getAttr(JFlyFoxUtils.TITLE_ATTR));

		renderAuto(path + "search.html");
	}
java 复制代码
//过滤

 public static String decode(String s, String enc)
        throws UnsupportedEncodingException{

    //默认设置开关
    boolean needToChange = false;
获取get编码长度
        int numChars = s.length();
//判断长度是否大于500,是/2,不是原来,创建相应长度数组
        StringBuffer sb = new StringBuffer(numChars > 500 ? numChars / 2 : numChars);

        int i = 0;

        if (enc.length() == 0) {//检查有没有utf8

            throw new UnsupportedEncodingException ("URLDecoder: empty string enc parameter");
        }

        char c;
        byte[] bytes = null;
//装进去
        while (i < numChars) {
//获取字符
            c = s.charAt(i);
            switch (c) {

            case '+':
//转化空格
                sb.append(' ');
                i++;
//打开开关
                needToChange = true;
//跳出判断
                break;
//%处理
            case '%':
               

                try {

                    //如果数组是空的,第一次
                    if (bytes == null){
//创建一个数组-i/3
//编码占用3个字符
                        bytes = new byte[(numChars-i)/3];}

                    int pos = 0;
//判断get长度是不是到了末尾
                    while ( ((i+2) < numChars) &&
                            (c=='%')) {
//截取转码转16进制
                        int v = Integer.parseInt(s.substring(i+1,i+3),16);
//如果<0
                        if (v < 0)
                            throw new IllegalArgumentException("URLDecoder: Illegal hex characters in escape (%) pattern - negative value");
                        bytes[pos++] = (byte) v;
//i+3
                        i+= 3;
//末尾
                        if (i < numChars)
                            c = s.charAt(i);
                    }

                    




                    if ((i < numChars) && (c=='%'))
                        throw new IllegalArgumentException(
                         "URLDecoder: Incomplete trailing escape (%) pattern");

                    sb.append(new String(bytes, 0, pos, enc));
                } catch (NumberFormatException e) {
                    throw new IllegalArgumentException(
                    "URLDecoder: Illegal hex characters in escape (%) pattern - "
                    + e.getMessage());
                }
                needToChange = true;
                break;
            default:
                sb.append(c);
                i++;
                break;
            }
        }

//返回

        return (needToChange? sb.toString() : s);
    }
}
java 复制代码
public StringBuffer(int capacity) {
        super(capacity);
    }
java 复制代码
AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }

0x3 SQL

http://localhost:8080/jfinal_cms/?orderType=4

看看有没有注入

代码分析

没有注入

java 复制代码
public Page<TbArticle> getArticleByOrder(Paginator paginator, int siteId, int orderType) {
		String key = ("articleOrder_" + paginator.getPageNo() + "_" + paginator.getPageSize() + "_" + siteId + "_" + orderType);
		String fromSql = " from tb_article t " //
				+ " left join tb_folder tf on tf.id = t.folder_id " //
				+ " where " + getPublicWhere() //
				+ " and tf.site_id = ? ";
		if (orderType==1) { // 默认
			fromSql +=" order by t.sort,t.create_time desc";
		} else if (orderType==2){ // 最新
			fromSql +=" order by t.create_time desc";
		} else if (orderType==3){ // 精品
			fromSql +=" order by (t.count_comment*10+t.count_view) desc";
		} else if (orderType==4){ // 待回复的
			fromSql +=" and t.count_comment = 0 order by t.create_time desc";
		}
		// 推荐文章列表
		Page<TbArticle> articles = TbArticle.dao.paginateCache(cacheName, key, paginator, "select t.* ", fromSql, siteId);
		return articles;
	}

00x1 admin登录

0x0抓包

管理员编辑

java 复制代码
GET /jfinal_cms/front/person/editblog/4249 HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:148.0) Gecko/20100101 Firefox/148.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.9,zh-TW;q=0.8,zh-HK;q=0.7,en-US;q=0.6,en;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Referer: http://localhost:8080/jfinal_cms/home.html
Cookie: JSESSIONID=4B80C6600606346C89833707F6AF2CC6; Hm_lvt_1040d081eea13b44d84a4af639640d51=1774074337; Hm_lpvt_1040d081eea13b44d84a4af639640d51=1774099683; HMACCOUNT=CFD43E6B2F46D5DF; session_user="wgPmpe3hEuJWIL+I+kHtxqag1wutWsMhm6eaAgoJH0c="
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Priority: u=0, i

管理员发布

java 复制代码
POST /jfinal_cms/front/person/saveblog/4249 HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:148.0) Gecko/20100101 Firefox/148.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.9,zh-TW;q=0.8,zh-HK;q=0.7,en-US;q=0.6,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 2609
Origin: http://localhost:8080
Connection: keep-alive
Referer: http://localhost:8080/jfinal_cms/front/person/editblog/4249
Cookie: JSESSIONID=4B80C6600606346C89833707F6AF2CC6; Hm_lvt_1040d081eea13b44d84a4af639640d51=1774074337; Hm_lpvt_1040d081eea13b44d84a4af639640d51=1774099903; HMACCOUNT=CFD43E6B2F46D5DF; session_user="wgPmpe3hEuJWIL+I+kHtxqag1wutWsMhm6eaAgoJH0c="
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Priority: u=0

search_header=&model.id=4249&model.folder_id=257&model.title=%E8%B5%84%E8%AE%AF%E7%AB%99%E4%BB%8B%E7%BB%8D&tags=%E8%B5%84%E8%AE%AF&tags_content=%E8%B5%84%E8%AE%AF&model.content=%3Cp%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%E8%B5%84%E8%AE%AF%E6%98%AF%E7%94%A8%E6%88%B7%E5%9B%A0%E4%B8%BA%E5%8F%8A%E6%97%B6%E5%9C%B0%E8%8E%B7%E5%BE%97%E5%AE%83%E5%B9%B6%E5%88%A9%E7%94%A8%E5%AE%83%E8%80%8C%E8%83%BD%E5%A4%9F%E5%9C%A8%E7%9B%B8%E5%AF%B9%E7%9F%AD%E7%9A%84%E6%97%B6%E9%97%B4%E5%86%85%E7%BB%99%E8%87%AA%E5%B7%B1%E5%B8%A6%E6%9D%A5%E4%BB%B7%E5%80%BC%E7%9A%84%E4%BF%A1%E6%81%AF%EF%BC%8C%E8%B5%84%E8%AE%AF%E6%9C%89%E6%97%B6%E6%95%88%E6%80%A7%E5%92%8C%E5%9C%B0%E5%9F%9F%E6%80%A7%EF%BC%8C%E5%AE%83%E5%BF%85%E9%A1%BB%E8%A2%AB%E6%B6%88%E8%B4%B9%E8%80%85%E5%88%A9%E7%94%A8%E3%80%82%E5%B9%B6%E4%B8%94%E2%80%9C%E6%8F%90%E4%BE%9B%EF%BC%8D%E4%BD%BF%E7%94%A8%EF%BC%88%E9%98%85%E8%AF%BB%E6%88%96%E5%88%A9%E7%94%A8%EF%BC%89%EF%BC%8D%E5%8F%8D%E9%A6%88%E2%80%9D%E4%B9%8B%E9%97%B4%E8%83%BD%E5%A4%9F%E5%BD%A2%E6%88%90%E4%B8%80%E4%B8%AA%E9%95%BF%E6%9C%9F%E7%A8%B3%E5%AE%9A%E7%9A%84CS%E9%93%BE%EF%BC%8C%E5%85%B7%E6%9C%89%E8%BF%99%E4%BA%9B%E7%89%B9%E7%82%B9%E6%89%8D%E5%8F%AF%E4%BB%A5%E7%A7%B0%E4%B9%8B%E4%B8%BA%E8%B5%84%E8%AE%AF%E3%80%82+%E4%BB%8E%E4%B8%A5%E6%A0%BC%E7%9A%84%E6%84%8F%E4%B9%89%E4%B8%8A%E8%AE%B2%EF%BC%8C%E6%96%B0%E9%97%BB%E6%98%AF%E4%B8%80%E7%A7%8D%E8%B5%84%E8%AE%AF%E3%80%82%E8%B5%84%E8%AE%AF%E6%98%AF%E4%B8%80%E7%A7%8D%E4%BF%A1%E6%81%AF%EF%BC%8C%E6%B6%B5%E7%9B%96%E7%9A%84%E4%B8%8D%E5%8F%AA%E6%98%AF%E6%96%B0%E9%97%BB%EF%BC%8C%E8%BF%98%E5%8F%AF%E4%BB%A5%E5%8C%85%E6%8B%AC%E5%85%B6%E4%BB%96%E5%AA%92%E4%BB%8B%E3%80%82%E5%A6%82%E4%BA%B2%E4%B8%B4%E4%B8%93%E5%AE%B6%E8%AE%B2%E5%BA%A7%E7%AD%89%E7%AD%89%EF%BC%9B%E6%96%B0%E9%97%BB%E7%9A%84%E7%9B%AE%E6%A0%87%E5%8F%97%E4%BC%97%E7%9B%B8%E5%AF%B9%E5%AE%BD%E6%B3%9B%EF%BC%8C%E6%B2%A1%E6%9C%89%E4%B8%A5%E6%A0%BC%E7%9A%84%E5%8F%97%E4%BC%97%E5%88%92%E5%88%86%EF%BC%8C%E5%AD%A6%E8%AF%AD%E8%A8%80%E7%9A%84%E4%BA%BA%E5%8F%AF%E4%BB%A5%E5%8E%BB%E9%98%85%E8%AF%BB%E7%A7%91%E6%8A%80%E6%96%B0%E9%97%BB%E3%80%82%E5%AD%A6%E6%8A%80%E6%9C%AF%E7%9A%84%E4%B9%9F%E5%AE%8C%E5%85%A8%E5%8F%AF%E4%BB%A5%E5%8E%BB%E9%98%85%E8%AF%BB%E6%96%87%E5%AD%A6%E6%96%B0%E9%97%BB%EF%BC%8C%E8%80%8C%E8%B5%84%E8%AE%AF%E7%9A%84%E5%8F%97%E4%BC%97%E7%9A%84%E7%9B%AE%E6%A0%87%E6%80%A7%E7%9B%B8%E5%AF%B9%E6%AF%94%E8%BE%83%E5%BC%BA%E3%80%82%3C%2Fp%3E%3Cp%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%E6%9C%AC%E7%AB%99%E8%B5%84%E8%AE%AF%E7%BD%91%E7%AB%99%E5%9C%B0%E5%9D%80%EF%BC%9A%3Ca+href%3D%22http%3A%2F%2Fmtg.jflyfox.com%22+target%3D%22_blank%22+title%3D%22mtg.jflyfox.com%22%3Emtg.jflyfox.com%3C%2Fa%3E%3Cbr%2F%3E%3C%2Fp%3E

响应

java 复制代码
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: application/json;charset=UTF-8
Content-Length: 12
Date: Sat, 21 Mar 2026 13:34:00 GMT

{"status":1}

管理员点赞

0x1 恶意加载

这里疑似有文件上传

代码分析

java 复制代码
<tr>
									<td class="right_td">头像地址:</td>
									<td class="left_td"><input name="model.title_url"
									 value="${model.title_url!''}"></td>
								</tr>
java 复制代码
<div class="form-group">
							    <label for="title_url" class="col-sm-2 control-label">头像地址</label>
							    <div class="col-sm-10">
							      <input name="model.title_url" type="text" class="form-control" id="title_url" 
							      	value="${model.title_url!''}" placeholder="头像地址">
							    </div>

jsp

java 复制代码
<form class="form-horizontal" name="form1" action="" method="post">
						<input type="hidden" name="model.userid" value="${model.userid}" />
						<div  class="form-group text-center">
							<div class="col-sm-offset-2 col-sm-10">
							<% 
							var userPic = model.title_url;
							if(isEmpty(userPic)){
								userPic = BASE_PATH + 'static/images/user/user.png';
							} else if(!strutil.startWith(userPic , 'http')) {
								userPic = ASE_PATH + userPic;
							}
						 %>
							<img id="title_pic" alt="头像"  width="64" height="64" 
						 			class="img_radius" src="${userPic}">
						 	</div>
						</div>

0x2 sql

00x2 用户登录

相关推荐
zzh0812 小时前
MySQL数据库操作笔记
数据库·笔记·mysql
6+h2 小时前
【Redis】底层原理解析(SDS / 跳表 / IO多路复用 / 单线程模型)
数据库·redis·bootstrap
idolao2 小时前
CentOS 7 安装 nginx-1.3.15.tar.gz 详细步骤(从源码编译到启动配置)
linux·运维·数据库
EnCi Zheng2 小时前
J7A-已有数据表如何安全添加新字段 [特殊字符]️
数据库·安全·oracle
biubiuibiu2 小时前
探秘新飞机:从包装到起飞的全程指南
数据库·python
专注VB编程开发20年3 小时前
SQL SERVER数据库DTE加密和字段加密
数据库·sql server
pupudawang3 小时前
MySQL中日期和时间戳的转换:字符到DATE和TIMESTAMP的相互转换
数据库·mysql
V1ncent Chen3 小时前
SQL大师之路 12 函数基础
数据库·sql·mysql·数据分析
焚 城3 小时前
SQL PARTITION BY用法
数据库·sql