【问题标题】:Parsing through NMAP XML issue通过 NMAP XML 问题解析
【发布时间】:2017-08-29 19:17:18
【问题描述】:

如果你愿意的话,考虑一下你有一个默认的 nmap XML 输出的世界。

我专门试图解析出 IP 地址(这里没有问题)和操作系统供应商(这里有问题)。

问题是因为 xml 标签有多个实例以及属性,我不知道如何使用 untangle 语法从也需要索引的标签中提取和属性。

xml 看起来像这样:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="file:///usr/bin/../share/nmap/nmap.xsl" type="text/xsl"?>
<!-- Nmap 7.40 scan initiated Tue Aug 29 12:45:56 2017 as: nmap -sV -O -oX ./nmap_results.xml 1.2.3.4/24 -->
<nmaprun attributes="">
    <scaninfo attributes="" />
    <debugging attributes="" />
    <host attributes="">
        <status attributes="" />
        <address attributes="" />
        <hostnames>
            <hostname attributes="" />
        </hostnames>
        <ports>
            <extraports attributes="">
                <extrareasons attributes="" />
            </extraports>
            <port attributes="">
                <state attributes="" />
                <service attributes="" />
            </port>
            <port attributes="">
                <state attributes="" />
                <service attributes="">
                    <cpe>stuff</cpe>
                    <cpe>more stuff</cpe>
                </service>
            </port>
            ...

假设我想从端口的第一个实例中提取属性。

在我的 python 中,我会假设它看起来像这样:

#!/bin/env python
import untangle

nmap = untangle.parse('./location/to/results.xml')

alive = int(nmap.nmaprun.runstats.hosts['up'])

count = range(0,alive,1)
for tick in count:
    print(nmap.nmaprun.host[tick].ports.port[0, 'attribute'])

这里的问题是 port[0, 'attribute']) 的实例,因为它想要并且需要那个 0 索引,但是我也想提取一些属性。

这里是python错误:

/usr/bin/python2.7 /path/to/my/dot.py
Traceback (most recent call last):
  File "/path/to/my/dot.py", line 10, in <module>
    print(nmap.nmaprun.host[tick].ports.port[0, 'vendor'])
TypeError: list indices must be integers, not tuple

Process finished with exit code 1

如果我尝试只使用属性名称而不使用索引,我会得到:

/usr/bin/python2.7 /path/to/my/dot.py
Traceback (most recent call last):
  File "/path/to/my/dot.py", line 10, in <module>
    print(nmap.nmaprun.host[tick].ports.port['vendor'])
TypeError: list indices must be integers, not str

Process finished with exit code 1

如果我只提供索引,我会得到一个包含所有属性的字符串,但我只需要一个。

我做错了什么还是有办法?

【问题讨论】:

  • 你能发布一个完整的 XML 文件吗?发布 sn-p 会使测试变得困难。
  • nmap.nmaprun.host[tick].ports.port[0]的类型是什么?
  • 我在这里上传了一个完整的 xml (pastebin.com/EgguG1Ss)
  • Python 说:&lt;class 'untangle.Element'&gt; None &lt;type 'NoneType'&gt;
  • 您是否限制使用 untangle 模块来解析 xml?附言如果你会使用 smth 像:print(nmap.nmaprun.host[tick].ports.port[0]['portid'] 呢?

标签: python xml xml-parsing


【解决方案1】:

我没有盲目地猜测,而是下载了模块(它是一个单独的 .py 文件)并开始使用它。我学到了什么:

  1. 基于 xml 节点标签(这将成为对象属性)
  2. Element 支持索引 ([Python]: object.__getitem__(self, key)) 并返回名称与给定键匹配的 xml 节点属性
  3. 当一个xml节点有多个相同标签的节点时,对应的转换对象将是Element对象的一个列表
  4. Element 支持迭代 ([Python]: object.__iter__(self)) 并在迭代时自动生成

从项目符号 3. 和 4. 得出的结果是,最好始终迭代可能出现一次或多次的元素 旁注 *.

这里有一些代码可以证明这一点:

#!/bin/env python

import untangle

FILE_NAME = "a.xml" # "./location/to/results.xml" # You should change the name back to match your location


def main():
    nmap = untangle.parse(FILE_NAME)
    up_host_count = int(nmap.nmaprun.runstats.hosts['up'])
    host_iterator = nmap.nmaprun.host
    for host in host_iterator:
        print("IP Address: {}".format(host.address["addr"]))

        vendors = set()
        osmatch_iterator = host.os.osmatch
        for osmatch in osmatch_iterator:
            osclass_iterator = osmatch.osclass
            for osclass in osclass_iterator:
                vendor = osclass["vendor"]
                if vendor is not None:
                    vendors.add(vendor)
        print("    OS Vendors: {}".format(vendors))

        port_iterator = host.ports.port
        for port in port_iterator:
            print("    Port number: {}".format(port["portid"]))


if __name__ == "__main__":
    main()

注意事项

  • 代码中的每个for 循环都是迭代的示例(我在上面谈到过),我从提供的 xml 示例(完整版本)中得到它,看看哪里还有更多多于一个具有相同标签的节点
  • 当然,除了总是检查对象的类型,还有迭代的替代方法,但这既不好也不可扩展
  • 问题中不需要端口处理,但我将其放在那里,因为有一个示例涉及端口时不起作用
  • 由于 nmap 扫描可以识别来自不同供应商 (在我们的例子中不会发生),尤其是在 Ux(Unix) 风格之间会发生,我为 OS添加了一些逻辑> 供应商部分只显示一次(您可以手动修改 xml 文件,并为 osclass 节点之一指定 Linux 以外的供应商并查看它出现在输出中)
  • 使用 Python3Python2 运行代码

输出

E:\Work\Dev\StackOverflow\q45946779>python b.py
IP Address: 127.0.0.1
    OS Vendors: set([u'Linux'])
    Port number: 22
    Port number: 111
    Port number: 631
    Port number: 2222
    Port number: 8081
    Port number: 30000

旁注*:我谈到了一个可以出现一次或多次的元素,但是这种方法(我说的是untangle 模块方法)如果em>xml 不完整。取以下代码行(不再使用,但我保留它只是为了说明一点):

up_host_count = int(nmap.nmaprun.runstats.hosts['up'])

如果 xml 中缺少任何节点 nmaprunrunstatshosts,则该行将出现 AttributeError。同一行,但带有防错功能,如下所示:

up_host_count = int(getattr(getattr(getattr(nmap, "nmaprun", None), "runstats", None), "hosts", None)["up"] or 0)

但这很丑,而且在推进 xml 树深度时会变得更加混乱。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2012-03-14
  • 2023-03-17
  • 2012-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-22
相关资源
最近更新 更多