主机安全扫描入门-用Java封装Nmap

本文涉及的产品
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
简介: 主机安全扫描入门-用Java封装Nmap

市面上用python封装Nmap的特别多,方法很简单,调用nmap的命令,执行并解析结果。

为了方便工具化以及微服务的调用,我用Java对Nmap进行了封装。

这里以实现存活性扫描和端口扫描为例,首先,我们创建一个类,里面包含了我们对命令的解析,以保证调用方可以直接调用函数从而实现对命令的调用。

/**
 * nmap参数
 */
public class NmapArgs {
   

    private boolean toXml;
    private boolean allScan;
    private boolean survival; // 存活性扫描
    private boolean synPort; // syn端口扫描

    private Long randomFile;
    public String resultFile;


    public NmapArgs toXml(){
   
        toXml = true;
        randomFile = new Double(Math.random()*1000000000L).longValue();
        return this;
    }

    public NmapArgs allScan(){
   
        allScan = true;
        return this;
    }

    public NmapArgs survival(){
   
        survival = true;
        return this;
    }

    public NmapArgs synPort(){
   
        synPort = true;
        return this;
    }

    public String toArgs(){
   
        StringBuilder command = new StringBuilder();
        command.append("nmap");
        if (toXml){
   
            command.append(" -oX /root/nmap_test/").append(randomFile).append(".xml");
            resultFile = "/root/nmap_test/" + randomFile + ".xml";
        }
        if (allScan){
   
            command.append(" -A");
        }
        if (survival){
   
            command.append(" -sP");
        }
        if (synPort){
   
            command.append(" -sS");
        }
        return command.append(" ").toString();
    }
}

... ... 
// 调用方法
    private static Nmap scan(String command, String resultFile) {
   
    Nmap nmap = null;
    try {
   
        Process process = Runtime.getRuntime().exec(command);
        int cnt = 0;
        while (process.isAlive()) {
   
            logger.info(command + " 进程执行中" + cnt * 5 + "秒");
            Thread.sleep(5 * 1000);
            cnt++;
        }
    } catch (IOException e) {
   
        e.printStackTrace();
    } catch (InterruptedException e) {
   
        e.printStackTrace();
    }

    int cnt = 5;
    try {
   
        while (cnt >= 0) {
   
            nmap = readResult(resultFile);
            if (Objects.nonNull(nmap.runstats.finished)) {
   
                if (nmap.runstats.finished.exit.equals("success")) {
   
                    // TODO: 2022/3/29 成功
                    return nmap;
                }
            }
            cnt--;
        }
    } catch (Exception e) {
   
        e.printStackTrace();
    }
    return null;
}

这里首先利用NmapArgs来构造执行命令的参数,然后调用的scan方法里面使用

Process process = Runtime.getRuntime().exec(command);

来执行命令。等到结果出来了,解析xml即可。
使用就很简单了。例如:
实现端口扫描

public static Nmap scanPort(String targets) {
   
    NmapArgs nmapArgs = new NmapArgs();
    String command = nmapArgs.toXml().toArgs().concat(targets);
    String file = nmapArgs.resultFile;
    return scan(command, file);
}

实现存活性扫描

public static Nmap scanSurvival(String targets) {
   
    NmapArgs nmapArgs = new NmapArgs();
    String command =  nmapArgs.toXml().survival().toArgs().concat(targets);
    String file = nmapArgs.resultFile;
    return scan(command,file);
}

命令行的调用是非常简单的,我们需要做的比较复杂的操作主要是对结果进行解析。根据上面代码中的指令,可以看见,我们最后是将结果导出到xml中,所以这里,我们需要实现对nmap结果进行解析。

对Nmap的xml进行解析是封装nmap最为繁琐的一步,这里我利用自己实现的一个自动化对接的工具,做到了对nmap结果的及解析。下面是我生成的结构:

import java.util.List;

public class Nmap {
   
    public String scanner;
    public String args;
    public String start;
    public String startstr;
    public String version;
    public String xmloutputversion;
    public NmapScaninfo scaninfo;
    public NmapVerbose verbose;
    public NmapDebugging debugging;
    public List<NmapHost> hosts;
    public NmapRunstats runstats;
}

... ...
public class NmapDebugging {
   
    public String level;
}
... ...
public class NmapHost {
   
    public String starttime;
    public String endtime;
    public NmapHostStatus status;
    public NmapHostAddress address;
    public String hostnames;
    public NmapHostPorts ports;
    public NmapHostTimes times;
}
... ...
public class NmapHostAddress {
   
    public String addr;
    public String addrtype;
}
... ...
public class NmapHostPorts {
   
    public NmapHostPortsExtraports extraports;
    public List<NmapHostPortsPort> port;
}
... ...
public class NmapHostPortsExtraports {
   
    public String state;
    public String count;
    public List<NmapHostPortsExtraportsExtrareasons> extrareasons;
}
... ...
public class NmapHostPortsExtraportsExtrareasons {
   
    public String reason;
    public String count;
}
... ...
public class NmapHostPortsPort {
   
    public String protocol;
    public NmapHostPortsPortService service;
    public NmapHostPortsPortState state;
    public String portid;
}
... ...
public class NmapHostPortsPortService {
   
    public String name;
    public String method;
    public String conf;
}
... ...
public class NmapHostPortsPortState {
   
    public String state;
    public String reason;
    public String reasonTtl;
}
... ...
public class NmapHostStatus {
   
    public String state;
    public String reason;
    public String reasonTtl;
}
... ...
public class NmapHostTimes {
   
    public String srtt;
    public String rttvar;
    public String to;
}
... ...
public class NmapRunstats {
   
    public NmapRunstatsFinished finished;
    public NmapRunstatsHosts hosts;
}
... ...
public class NmapRunstatsFinished {
   
    public String time;
    public String timestr;
    public String elapsed;
    public String summary;
    public String exit;
}
... ...
public class NmapRunstatsHosts {
   
    public String up;
    public String down;
    public String total;
}
... ...
public class NmapScaninfo {
   
    public String type;
    public String protocol;
    public String numservices;
    public String services;
}
... ...
public class NmapVerbose {
   
    public String level;
}

也就是说,可以将Xml文件里面的内容,转化成Nmap这个大对象。转换的方法我也放在下面了(都是自动生成的,体力活)

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class NmapExchange {
   
    public static Nmap exchangeNmap(Map<String, Object> tmp) {
   
        Nmap tmpDto = new Nmap();
        tmpDto.scanner = (String) tmp.getOrDefault("scanner", "");
        tmpDto.args = (String) tmp.getOrDefault("args", "");
        tmpDto.start = (String) tmp.getOrDefault("start", "");
        tmpDto.startstr = (String) tmp.getOrDefault("startstr", "");
        tmpDto.version = (String) tmp.getOrDefault("version", "");
        tmpDto.xmloutputversion = (String) tmp.getOrDefault("xmloutputversion", "");
        tmpDto.scaninfo = exchangeNmapScaninfo((Map<String, Object>) tmp.getOrDefault("scaninfo", new HashMap<>()));
        tmpDto.verbose = exchangeNmapVerbose((Map<String, Object>) tmp.getOrDefault("verbose", new HashMap<>()));
        tmpDto.debugging = exchangeNmapDebugging((Map<String, Object>) tmp.getOrDefault("debugging", new HashMap<>()));
//        tmpDto.host = exchangeNmapHost((Map<String, Object>) tmp.getOrDefault("host", new HashMap<>()));
        tmpDto.runstats = exchangeNmapRunstats((Map<String, Object>) tmp.getOrDefault("runstats", new HashMap<>()));
        return tmpDto;
    }

    public static NmapScaninfo exchangeNmapScaninfo(Map<String, Object> tmp) {
   
        NmapScaninfo tmpDto = new NmapScaninfo();
        tmpDto.type = (String) tmp.getOrDefault("type", "");
        tmpDto.protocol = (String) tmp.getOrDefault("protocol", "");
        tmpDto.numservices = (String) tmp.getOrDefault("numservices", "");
        tmpDto.services = (String) tmp.getOrDefault("services", "");
        return tmpDto;
    }

    public static NmapVerbose exchangeNmapVerbose(Map<String, Object> tmp) {
   
        NmapVerbose tmpDto = new NmapVerbose();
        tmpDto.level = (String) tmp.getOrDefault("level", "");
        return tmpDto;
    }

    public static NmapDebugging exchangeNmapDebugging(Map<String, Object> tmp) {
   
        NmapDebugging tmpDto = new NmapDebugging();
        tmpDto.level = (String) tmp.getOrDefault("level", "");
        return tmpDto;
    }

    public static NmapHost exchangeNmapHost(Map<String, Object> tmp) {
   
        NmapHost tmpDto = new NmapHost();
        tmpDto.starttime = (String) tmp.getOrDefault("starttime", "");
        tmpDto.endtime = (String) tmp.getOrDefault("endtime", "");
        tmpDto.status = exchangeNmapHostStatus((Map<String, Object>) tmp.getOrDefault("status", new HashMap<>()));
        tmpDto.address = exchangeNmapHostAddress((Map<String, Object>) tmp.getOrDefault("address", new HashMap<>()));
        tmpDto.hostnames = (String) tmp.getOrDefault("hostnames", "");
        tmpDto.ports = exchangeNmapHostPorts((Map<String, Object>) tmp.getOrDefault("ports", new HashMap<>()));
        tmpDto.times = exchangeNmapHostTimes((Map<String, Object>) tmp.getOrDefault("times", new HashMap<>()));
        return tmpDto;
    }

    public static NmapHostStatus exchangeNmapHostStatus(Map<String, Object> tmp) {
   
        NmapHostStatus tmpDto = new NmapHostStatus();
        tmpDto.state = (String) tmp.getOrDefault("state", "");
        tmpDto.reason = (String) tmp.getOrDefault("reason", "");
        tmpDto.reasonTtl = (String) tmp.getOrDefault("reason_ttl", "");
        return tmpDto;
    }

    public static NmapHostAddress exchangeNmapHostAddress(Map<String, Object> tmp) {
   
        NmapHostAddress tmpDto = new NmapHostAddress();
        tmpDto.addr = (String) tmp.getOrDefault("addr", "");
        tmpDto.addrtype = (String) tmp.getOrDefault("addrtype", "");
        return tmpDto;
    }

    public static NmapHostPorts exchangeNmapHostPorts(Map<String, Object> tmp) {
   
        NmapHostPorts tmpDto = new NmapHostPorts();
        tmpDto.extraports = exchangeNmapHostPortsExtraports((Map<String, Object>) tmp.getOrDefault("extraports", new HashMap<>()));
        tmpDto.port = new ArrayList<>();
        try {
   
            List<Map<String, Object>> x = (List<Map<String, Object>>) tmp.getOrDefault("port", new ArrayList<>());
            for (Map<String,Object> y : x){
   
                tmpDto.port.add(exchangeNmapHostPortsPort(y));
            }
        }catch (Exception e){
   

        }
        return tmpDto;
    }

    public static NmapHostPortsExtraports exchangeNmapHostPortsExtraports(Map<String, Object> tmp) {
   
        NmapHostPortsExtraports tmpDto = new NmapHostPortsExtraports();
        tmpDto.state = (String) tmp.getOrDefault("state", "");
        tmpDto.count = (String) tmp.getOrDefault("count", "");
        tmpDto.extrareasons = new ArrayList<>();
        try {
   
            List<Map<String, Object>> x = (List<Map<String, Object>>) tmp.getOrDefault("extrareasons", new ArrayList<>());
            for (Map<String, Object> y : x){
   
                tmpDto.extrareasons.add(exchangeNmapHostPortsExtraportsExtrareasons(y));
            }
        }catch (Exception e){
   
        }

        return tmpDto;
    }

    public static NmapHostPortsExtraportsExtrareasons exchangeNmapHostPortsExtraportsExtrareasons(Map<String, Object> tmp) {
   
        NmapHostPortsExtraportsExtrareasons tmpDto = new NmapHostPortsExtraportsExtrareasons();
        tmpDto.reason = (String) tmp.getOrDefault("reason", "");
        tmpDto.count = (String) tmp.getOrDefault("count", "");
        return tmpDto;
    }

    public static NmapHostPortsPort exchangeNmapHostPortsPort(Map<String, Object> tmp) {
   
        NmapHostPortsPort tmpDto = new NmapHostPortsPort();
        tmpDto.protocol = (String) tmp.getOrDefault("protocol", "");
        tmpDto.service = exchangeNmapHostPortsPortService((Map<String, Object>) tmp.getOrDefault("service", new HashMap<>()));
        tmpDto.state = exchangeNmapHostPortsPortState((Map<String, Object>) tmp.getOrDefault("state", new HashMap<>()));
        tmpDto.portid = (String) tmp.getOrDefault("portid", "");
        return tmpDto;
    }

    public static NmapHostPortsPortService exchangeNmapHostPortsPortService(Map<String, Object> tmp) {
   
        NmapHostPortsPortService tmpDto = new NmapHostPortsPortService();
        tmpDto.name = (String) tmp.getOrDefault("name", "");
        tmpDto.method = (String) tmp.getOrDefault("method", "");
        tmpDto.conf = (String) tmp.getOrDefault("conf", "");
        return tmpDto;
    }

    public static NmapHostPortsPortState exchangeNmapHostPortsPortState(Map<String, Object> tmp) {
   
        NmapHostPortsPortState tmpDto = new NmapHostPortsPortState();
        tmpDto.state = (String) tmp.getOrDefault("state", "");
        tmpDto.reason = (String) tmp.getOrDefault("reason", "");
        tmpDto.reasonTtl = (String) tmp.getOrDefault("reason_ttl", "");
        return tmpDto;
    }

    public static NmapHostTimes exchangeNmapHostTimes(Map<String, Object> tmp) {
   
        NmapHostTimes tmpDto = new NmapHostTimes();
        tmpDto.srtt = (String) tmp.getOrDefault("srtt", "");
        tmpDto.rttvar = (String) tmp.getOrDefault("rttvar", "");
        tmpDto.to = (String) tmp.getOrDefault("to", "");
        return tmpDto;
    }

    public static NmapRunstats exchangeNmapRunstats(Map<String, Object> tmp) {
   
        NmapRunstats tmpDto = new NmapRunstats();
        tmpDto.finished = exchangeNmapRunstatsFinished((Map<String, Object>) tmp.getOrDefault("finished", new HashMap<>()));
        tmpDto.hosts = exchangeNmapRunstatsHosts((Map<String, Object>) tmp.getOrDefault("hosts", new HashMap<>()));
        return tmpDto;
    }

    public static NmapRunstatsFinished exchangeNmapRunstatsFinished(Map<String, Object> tmp) {
   
        NmapRunstatsFinished tmpDto = new NmapRunstatsFinished();
        tmpDto.time = (String) tmp.getOrDefault("time", "");
        tmpDto.timestr = (String) tmp.getOrDefault("timestr", "");
        tmpDto.elapsed = (String) tmp.getOrDefault("elapsed", "");
        tmpDto.summary = (String) tmp.getOrDefault("summary", "");
        tmpDto.exit = (String) tmp.getOrDefault("exit", "");
        return tmpDto;
    }

    public static NmapRunstatsHosts exchangeNmapRunstatsHosts(Map<String, Object> tmp) {
   
        NmapRunstatsHosts tmpDto = new NmapRunstatsHosts();
        tmpDto.up = (String) tmp.getOrDefault("up", "");
        tmpDto.down = (String) tmp.getOrDefault("down", "");
        tmpDto.total = (String) tmp.getOrDefault("total", "");
        return tmpDto;
    }
}

这里将xml转成hashmap结构之后,再转成对象。这里有个细节点:可能有的朋友会觉得,既然我都有HashMap了,为啥还需要这么复杂,我直接利用Json库里面的方法转成对象不就行了吗,为啥还得一个一个取出来放进去?这里这样做的目的是防止数据有结构错误,Json库会直接出错,从而造成容错性很差,特别是在一些字段无法进行直接强转的情况下。

那么问题来了,我们如何将xml转成HashMap呢?
这里就要用到相关的库了

<dependency>
  <groupId>com.fasterxml.jackson.dataformat</groupId>
  <artifactId>jackson-dataformat-xml</artifactId>
  <version>2.12.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.13.0</version>
</dependency>

然后最终将xmlStr转成Nmap对象的代码如下:

public static Nmap getNmapFromXmlStr(String xmlStr) {
   
    ObjectMapper xmlMapper = new XmlMapper();
    System.out.println(xmlStr);
    Map y = null;
    try {
   
        y = xmlMapper.readValue(xmlStr, Map.class);
        Nmap nmap = NmapExchange.exchangeNmap(y);
        nmap.hosts = new ArrayList<>();
        String[] a = xmlStr.split("\n");
        int flag = 0;
        StringBuilder builder = new StringBuilder();
        for (String b : a) {
   
            if (b.startsWith("<host ") || b.startsWith("<host>")) {
   
                flag = 1;
            }
            if (flag == 1) {
   
                builder.append(b).append("\n");
            }
            if (b.startsWith("</host>")) {
   
                flag = 0;
                NmapHost nmapHost = NmapExchange.exchangeNmapHost(xmlMapper.readValue(builder.toString(), Map.class));
                nmap.hosts.add(nmapHost);
                builder = new StringBuilder();
            }
        }
        return nmap;
    } catch (JsonProcessingException e) {
   
        e.printStackTrace();
    }
    return null;
}

这段代码在之前提到的scan方法中的readResult方法中被调用

private static Nmap readResult(String fileName) {
   
    StringBuilder xmlStr = new StringBuilder();
    try {
   
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(new File(fileName))));
        String line = "";
        while ((line = bufferedReader.readLine()) != null) {
   
            xmlStr.append(line).append("\n");
        }
    } catch (FileNotFoundException e) {
   
        e.printStackTrace();
    } catch (IOException e) {
   
        e.printStackTrace();
    }
    Nmap nmap = XmlUtils.getNmapFromXmlStr(xmlStr.toString());
    return nmap;
}

而此时我们就实现对nmap命令的封装和对其结果的反序列化,这一系列打包成一个jar给别人用就行了。

目录
相关文章
|
12天前
|
存储 Java
Java扫描某个文件夹且要保证不重复扫描,如何实现?
【10月更文挑战第18天】Java扫描某个文件夹且要保证不重复扫描,如何实现?
30 3
|
13天前
|
存储 安全 Java
从入门到精通:Java Map全攻略,一篇文章就够了!
【10月更文挑战第17天】本文详细介绍了Java编程中Map的使用,涵盖Map的基本概念、创建、访问与修改、遍历方法、常用实现类(如HashMap、TreeMap、LinkedHashMap)及其特点,以及Map在多线程环境下的并发处理和性能优化技巧,适合初学者和进阶者学习。
30 3
|
4天前
|
存储 安全 Java
🌟Java零基础-反序列化:从入门到精通
【10月更文挑战第21天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
23 5
|
1天前
|
安全 Java 调度
Java中的多线程编程入门
【10月更文挑战第29天】在Java的世界中,多线程就像是一场精心编排的交响乐。每个线程都是乐团中的一个乐手,他们各自演奏着自己的部分,却又和谐地共同完成整场演出。本文将带你走进Java多线程的世界,让你从零基础到能够编写基本的多线程程序。
6 1
|
7天前
|
Java 数据处理 开发者
Java多线程编程的艺术:从入门到精通####
【10月更文挑战第21天】 本文将深入探讨Java多线程编程的核心概念,通过生动实例和实用技巧,引导读者从基础认知迈向高效并发编程的殿堂。我们将一起揭开线程管理的神秘面纱,掌握同步机制的精髓,并学习如何在实际项目中灵活运用这些知识,以提升应用性能与响应速度。 ####
28 3
|
9天前
|
Java
Java中的多线程编程:从入门到精通
本文将带你深入了解Java中的多线程编程。我们将从基础概念开始,逐步深入探讨线程的创建、启动、同步和通信等关键知识点。通过阅读本文,你将能够掌握Java多线程编程的基本技能,为进一步学习和应用打下坚实的基础。
|
10天前
|
存储 安全 Java
从入门到精通:Java Map全攻略,一篇文章就够了!
【10月更文挑战第19天】本文介绍了Java编程中重要的数据结构——Map,通过问答形式讲解了Map的基本概念、创建、访问与修改、遍历方法、常用实现类(如HashMap、TreeMap、LinkedHashMap)及其特点,以及Map在多线程环境下的使用和性能优化技巧,适合初学者和进阶者学习。
35 4
|
10天前
|
Java
[Java]Socket套接字(网络编程入门)
本文介绍了基于Java Socket实现的一对一和多对多聊天模式。一对一模式通过Server和Client类实现简单的消息收发;多对多模式则通过Server类维护客户端集合,并使用多线程实现实时消息广播。文章旨在帮助读者理解Socket的基本原理和应用。
13 1
|
10天前
|
SQL IDE Java
入门Cloud Toolkit:简化你的Java应用开发与部署流程
【10月更文挑战第19天】作为一名长期从事Java开发的程序员,我一直致力于寻找能够简化日常开发工作的工具。在众多工具中,阿里巴巴推出的Cloud Toolkit引起了我的注意。这款免费的插件旨在帮助开发者更轻松地进行开发、测试及部署工作,尤其是在与云服务交互时表现尤为出色。本文将从个人的角度出发,介绍Cloud Toolkit的基本功能及其使用技巧,希望能帮助初学者快速上手这款实用工具。
13 1
|
21天前
|
安全 Java 测试技术
🌟Java零基础-反射:从入门到精通
【10月更文挑战第4天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
20 2