续 NCCloudGatewayServlet 命令执行漏洞 补丁绕过
之前的文章分析过,这个补丁只是对com.ufida.zior.console.IActionInvokeService和nc.bs.pub.util.ProcessFileUtils,并且类名不能包含nc.itf.uap.IUAPQueryBS。
public void checkBlackITFAuthority(String serviceClassName, Object[] argValues) throws BusinessException {
if ("com.ufida.zior.console.IActionInvokeService".equalsIgnoreCase(serviceClassName) && "nc.bs.pub.util.ProcessFileUtils".equalsIgnoreCase(String.valueOf(argValues[0]))) {
Logger.error("目前没有查【nc.bs.pub.util.ProcessFileUtils】接口权限");
throw new BusinessException("目前没查询【nc.bs.pub.util.ProcessFileUtils】接口权限");
}
if ("nc.itf.uap.IUAPQueryBS".equalsIgnoreCase(serviceClassName)) {
String argSql = ((String) argValues[0]).toLowerCase();
for (String word : BannedSqlWord) {
if (argSql.contains(word)) {
Logger.error("SQL语句中存在敏感词:" + word);
throw new BusinessException("SQL语句中存在敏感词:" + word);
}
}
}
}所以绕过方法也很简单,再找一个其他的sink类即可,这里提供另外一个写文件的方法nc.impl.uap.pfxxdev.PfxxDevFileServiceImpl#writePluginJavaCodeToServer,实际上还有很多可以利用的,具体就不详细分析了。
public void writePluginJavaCodeToServer(byte[] javasource, String filename, String modulename) throws BusinessException {
String sourcepath = RuntimeEnv.getInstance().getNCHome() + "/modules/" + modulename + "/META-INF/var/source/" + filename;
String classpath = RuntimeEnv.getInstance().getNCHome() + "/modules/" + modulename + "/META-INF/var/classes/";
try {
File file = new File(classpath);
if (!file.exists()) {
file.mkdirs();
}
FileUtils.writeBytesToFile(javasource, sourcepath);
} catch (IOException e) {
Logger.error(NCLangResOnserver.getInstance().getStrByID("uapde_pfxx", "PfxxDevFileServiceImpl-000001"), e);
throw new BusinessException(NCLangResOnserver.getInstance().getStrByID("uapde_pfxx", "PfxxDevFileServiceImpl-000002"));
}
}实际上,这个反射调用和之前的反序列化的最终效果都是一样的,可以调用Service的任意方法,并且参数可控。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package nc.impl.uap.pfxxdev;
import java.io.File;
import java.io.IOException;
import nc.bs.framework.common.RuntimeEnv;
import nc.bs.logging.Logger;
import nc.bs.ml.NCLangResOnserver;
import nc.itf.uap.pfxxdev.IPfxxDevFileService;
import nc.vo.jcom.io.fileparse.FileParseException;
import nc.vo.jcom.io.fileparse.IntellijFileReader;
import nc.vo.jcom.io.fileparse.IntellijFileReaderPool;
import nc.vo.jcom.lang.StringUtil;
import nc.vo.pfxx.exception.FileConfigException;
import nc.vo.pfxx.pub.PfxxServerSidePathVocabulary;
import nc.vo.pfxx.util.FileUtils;
import nc.vo.pub.BusinessException;
public class PfxxDevFileServiceImpl implements IPfxxDevFileService {
public byte[] getXMLDocFromTestPlugin(String filename) throws BusinessException {
if (StringUtil.isEmpty(filename)) {
throw new BusinessException(NCLangResOnserver.getInstance().getStrByID("uapde_pfxx", "PfxxDevFileServiceImpl-000000"));
} else {
filename = filename.replace('\\', '/');
String filepath = PfxxServerSidePathVocabulary.EXPORTBILLS_PATH + "test/" + filename;
try {
IntellijFileReader filereader = IntellijFileReaderPool.getIntellijFileReader(new PluginTestXMLParser(new File(filepath)));
return (byte[])filereader.getResult();
} catch (FileParseException e) {
Logger.error(e.getMessage(), e);
throw new FileConfigException(filepath, e.getMessage());
}
}
}
public void writePluginJavaCodeToServer(byte[] javasource, String filename, String modulename) throws BusinessException {
String sourcepath = RuntimeEnv.getInstance().getNCHome() + "/modules/" + modulename + "/META-INF/var/source/" + filename;
String classpath = RuntimeEnv.getInstance().getNCHome() + "/modules/" + modulename + "/META-INF/var/classes/";
try {
File file = new File(classpath);
if (!file.exists()) {
file.mkdirs();
}
FileUtils.writeBytesToFile(javasource, sourcepath);
} catch (IOException e) {
Logger.error(NCLangResOnserver.getInstance().getStrByID("uapde_pfxx", "PfxxDevFileServiceImpl-000001"), e);
throw new BusinessException(NCLangResOnserver.getInstance().getStrByID("uapde_pfxx", "PfxxDevFileServiceImpl-000002"));
}
}
}