ホームページ > バックエンド開発 > Python チュートリアル > Python と libnmapd を上手に使って Nmap スキャン結果を抽出する

Python と libnmapd を上手に使って Nmap スキャン結果を抽出する

高洛峰
リリース: 2017-02-25 10:29:46
オリジナル
1791 人が閲覧しました

イントラネット侵入を実行し、多数のホストやサービスに直面するときは常に、自動化された方法を使用して nmap スキャン結果から情報を抽出します。これにより、Web サービスでのパス ブラスト、SSL/TLS サービスで使用されるキーやプロトコルのテスト、その他の対象を絞ったテストなど、さまざまな種類のサービスの自動検出が容易になります。

私は侵入テストでも IPthon または *nix シェルをよく使用します。これらは、スクリプトで直接使用するか、REPL 環境で使用するか、ディスクにコードを書き込むかに関係なく、Python 経由でアクセスできます。使用するのもアクセスするのも非常に簡単ですシェルコマンドを介して。


構成
nmap スキャン結果を解析する最初のステップは、nmap スキャンを実行することです。ここではあまり詳しく説明しませんが、この記事のコードを直接使用したい場合は、スキャン構造を XML ファイル (-oX または -oA) に保存し、サービス検出を実行する必要があります。ポートを開き (-sV)、関連スクリプトを実行します (-sC)。
この記事のコマンドは、IPython などの Python REPL 環境で実行しており、libnmap モジュールがインストールされていることを前提としています (easy_install または pip を使用してインストールできます)。
始める前に、まず、NmapParser モジュールをインポートし、XML スキャン結果ファイルを読み取る必要があります (この例では、名前は現在の作業ディレクトリにある「up_hosts_all_ports_fullscan.xml」です)

from libnmap.parser import NmapParser
nmap_report = NmapParser.parse_fromfile('up_hosts_all_ports_fullscan.xml')
ログイン後にコピー

この記事の残りの部分には、1 行のコードでさまざまな有用な情報を抽出する一連のメソッドが含まれています。すべての例は、nmap スキャン結果が上記のようにファイルに保存されていることを前提としています。以下にいくつかの基本的なサンプル コードを示します。これらを IPython で直接実行する場合は、最初に上記のコードを実行してください。これにより、コードがコンソールに直接出力されて表示されます。通常はこれを最初に実行して、出力データが期待どおりであることを確認します。
その後、変数名を選択し、「=」を使用してデータを変数に割り当てることができるため、後続のコードで直接呼び出すことも、シェル コマンドで使用するためにディスクに書き込むこともできます。複数回使用したいものがある場合は、コード スニペットを Python スクリプトに貼り付けることも、より複雑なロジックを追加することもできますが、これにより REPL 環境の処理が難しくなる可能性があります。これをすばやく実行する方法を説明します。最後のセクションで操作します。

ポート情報
指定したポート番号が開いているホスト
指定したポート番号が開いているすべてのホストを表示します。ホストアドレス (文字列) を含むリストを生成します。以下では、ポート 443 を例として取り上げます。必要な値に変更できます。

 [ a.address for a in nmap_report.hosts if (a.get_open_ports()) and 443 in [b[0] for b in a.get_open_ports()] ]
ログイン後にコピー

開いているポートの数

一連のホストの開いているポートの数を表示します。ポート数 (int) を含むリストを生成し、ソートします。

 sorted(set([ b[0] for a in nmap_report.hosts for b in a.get_open_ports()]), key=int)
ログイン後にコピー

ホストのオープンポートに対応するサービス(ポート番号別にグループ化)

すべてのホストのオープンポート番号をポート番号別にグループ化して並べて表示します。複数のリストを含むリスト (つまり、リストの各要素もリスト) を生成します。各メンバー リストの最初の要素はポート番号 (int)、2 番目の要素はオープン アドレスを含むホスト IP アドレスです。対応するポート (文字列) リスト。

 [ [a, [ b.address for b in nmap_report.hosts for c in b.get_open_ports() if a==c[0] ] ] for a in sorted(set([ b[0] for a in nmap_report.hosts for b in a.get_open_ports()]),key=int) ]
SSL/TLS 和 HTTP/HTTPS
ログイン後にコピー

SSLを使用するホストとポート

SSLを使用するすべてのホストとポートを表示します。これは、サービスが「SSL」チャネルを使用しているかどうか、または関連するスクリプトが結果で pem 証明書を検出したかどうかを確認することによって行われます。一連のリストを含むリストを生成します。各メンバー リストにはホスト アドレス (文字列) とポート番号 (int) が含まれます。

 [ [a.address, b.port] for a in nmap_report.hosts for b in a.services if b.tunnel=='ssl' or "'pem'" in str(b.scripts_results) ]
ログイン後にコピー

次のコンテンツには上記と同じ情報が含まれていますが、リストのリストの代わりに、join 関数を使用して「ホスト:ポート番号」(文字列) を含むリストを作成します。

 [ ':'.join([a.address, str(b.port)]) for a in nmap_report.hosts for b in a.services if b.tunnel=='ssl' or "'pem'" in str(b.scripts_results) ]
ログイン後にコピー
ログイン後にコピー

Web サービスのホストとポートが含まれます

すべての Web サービスと、それに対応するポート番号とプロトコル (http または https) を表示します。これにより、複数のリストのリストが生成されます。各メンバー リストには、プロトコル (文字列)、アドレス (文字列)、およびポート番号 (int) が含まれます。ただし、ここでいくつか問題があり、nmap が https を使用している Web サイトを報告するときに、サービスが「https」であると表示される場合と、「ssl」チャネルを使用して「http」と表示される場合があるため、データ形式を調整しました。出力の均一化のために。

 [ [(b.service + b.tunnel).replace('sl',''), a.address, b.port] for a in nmap_report.hosts for b in a.services if b.open() and b.service.startswith('http') ]
ログイン後にコピー

同じ情報がまだここにありますが、URL (文字列) がプロトコル、ホスト、ポート番号の元のリストに追加されます。

 [ (b.service + b.tunnel).replace('sl','') + '://' + a.address + ':' + str(b.port) + '/' for a in nmap_report.hosts for b in a.services if b.open() and b.service.startswith('http') ]
ログイン後にコピー

その他のサービス情報
不明なサービス

nmap が認識できないすべてのサービスを表示します。複数のリストを含むリストを生成します。各メンバー リストには、アドレス (文字列)、ポート番号 (int)、および nmap によってスキャンされたポート フィンガープリント (文字列) が含まれます。この情報は主に、これらの特定のサービスの後続の手動レビューを容易にするために生成され、自動化されたプロセスには関与しません。

 [ [ a.address, b.port, b.servicefp ] for a in nmap_report.hosts for b in a.services if (b.service =='unknown' or b.servicefp) and b.port in [c[0] for c in a.get_open_ports()] ]
ログイン後にコピー

nmap で識別されたソフトウェア
nmap スキャンによって識別されたすべてのソフトウェアを表示します。製品のアルファベット順のリストを生成します。

 sorted(set([ b.banner for a in nmap_report.hosts for b in a.services if 'product' in b.banner]))
ログイン後にコピー

软件对应的主机和端口号,按产品分组
显示扫描出软件对应的主机和端口,按产品分组。生成一个包含多个列表的列表,其中每个成员列表的第一个元素为软件的名称(string),随后是另一个列表包含地址(string)和端口号(int)。

 [ [ a, [ [b.address, c.port] for b in nmap_report.hosts for c in b.services if c.banner==a] ] for a in sorted(set([ b.banner for a in nmap_report.hosts for b in a.services if 'product' in b.banner])) ]
ログイン後にコピー

同上相同的信息,只是输出略有不同。同样还是生成一个包含多个列表的列表,成员列表的第一个元素还是软件的名称(string),但第二个是一个包含 “主机:端口号” 的列表。

 [ [ a, [ ':'.join([b.address, str(c.port)]) for b in nmap_report.hosts for c in b.services if c.banner==a] ] for a in sorted(set([ b.banner for a in nmap_report.hosts for b in a.services if 'product' in b.banner])) ]
ログイン後にコピー

搜索指定关键词相关的主机和端口
显示所有与给定关键词相关联的主机和端口,从 nmap 扫描结果的原始文本中查找包含产品名称、服务名称等等。下面以 “Oracle” 为例。生成一个包含多个列表的列表,其中每个成员列表包含主机地址(string)和端口号(int)。

 [ [a.address, b.port] for a in nmap_report.hosts for b in a.services if b.open() and 'Oracle' in str(b.get_dict()) + str(b.scripts_results) ]
ログイン後にコピー

同上一样的方法,只是将存储的信息修改后一律使用小写进行搜索(下面示例为小写的 “oracle”),输出格式还是跟上面一样。

 [ [a.address, b.port] for a in nmap_report.hosts for b in a.services if b.open() and 'oracle' in (str(b.get_dict()) + str(b.scripts_results)).lower() ]
ログイン後にコピー


其他的事情

相同的证书名称
显示找到的 SSL 证书和使用 nmap 脚本解析后得到证书名称相同的部分。这样在当你从一个 IP 地址开始扫描且反向 DNS 失效的时候,可以帮助确定系统的主机名。生成一个包含多个列表的列表,其中每个成员列表包含 IP 地址(string)和提取出的主机名(string)。

 [ [a.address, c['elements']['subject']['commonName'] ] for a in nmap_report.hosts for b in a.services for c in b.scripts_results if c.has_key('elements') and c['elements'].has_key('subject') ]
ログイン後にコピー

处理以上结果的方法

正向前面所说,上述的例子,当你直接粘贴进 IPython REPL 时只是将输出打印在屏幕上。这的确不错,因为这样你可以随时查看到自己感兴趣的信息,但你可能还会想做更多的事情。之所以去生成上述信息,一大好处就在于你可以根据结果轻松执行一些自动化的操作。
如果你已经很熟悉 Python,应当可以很容易完成这些工作,那么你可以跳过这一节。但如果你不熟悉,那么本节会讲述一些很基本的知识,告诉你如何使用上述的代码段。

保存到磁盘
如果你想将上述代码段的输出结果保存到磁盘上的文本文件中,你需要将输出的列表转换为适当的字符串格式(具体取决于你的需求),然后在将这个字符串写入文件。在 Python 中,你可以使用 join 函数来整合这些列表并将其写入文件,这里只是一个示例。
我们想要从生成的列表中提取出支持 SSL 的主机和端口,并将它们保存到一个新的文件中,这样可以在 bash 中使用循环来完成并使用命令行工具来进行测试。
我通常会在 IPython 中使用一行代码来完成这些,虽然一行代码会比较方便,但这里为了方便阅读和理解,我会将代码拆分出来说。
让我们来解析之前生成了一个包含 “主机:端口” 的列表,请注意我们使用了 str 函数将端口号从整数类型装换为了字符类型,这样使得它也能够使用 join 函数与其他字符串拼接在一起。

 [ ':'.join([a.address, str(b.port)]) for a in nmap_report.hosts for b in a.services if b.tunnel=='ssl' or "'pem'" in str(b.scripts_results) ]
ログイン後にコピー
ログイン後にコピー

让我们来给上面这段代码的结果分配名为 “ssl_services” 变量,以方便后续的调用。

 ssl_services = [ ':'.join([a.address, str(b.port)]) for a in nmap_report.hosts for b in a.services if b.tunnel=='ssl' or "'pem'" in str(b.scripts_results) ]
ログイン後にコピー

现在,让我们来使用 join 函数将列表的每一个元素拼接起来并使用 (‘\n') 进行换行,然后给它分配一个名为 “ssl_services_text” 的变量。

 ssl_services_text = '\n'.join(ssl_services)
ログイン後にコピー

随后,我们就可以在当前工作目录下创建一个名为 “ssl_services_file.txt” 的新文建,并将 “ssl_services_text” 变量的内容写入其中。

open('ssl_services_file.txt','w').write(ssl_services_text)

就这么简单,后续你可以根据自己的需要来使用文件内容了。

使用其他 Python 代码
也许你还会想用其他的 Python 代码来完成上述工作?同样很简单,下面就是另一个示例,这里我们遍历每一个 nmap 识别出的 web 服务及其网页的请求结果。
下面会生成一个包含 URLs 的列表,我们分配一个名为 “urls” 的变量给它。

 urls = [ (b.service + b.tunnel).replace('sl','') + '://' + a.address + ':' + str(b.port) + '/' for a in nmap_report.hosts for b in a.services if b.open() and b.service.startswith('http') ]
ログイン後にコピー

下一步,我们先进行一些准备工作,导入 requests 模块,然后设置一个简单的 getAndSave 函数进行 web 请求并将返回结果保存到磁盘上,文件名按 url 自动生成。你可能会注意到下面代码中,在 get 请求中使用了 “verify=False” 选项,这会在发送请求时忽略证书验证的错误,这个选项经常在测试内部机器时使用,因为内部机器基本不会有可信的证书颁发机构颁发的 SSL 证书。

 import requests
def getAndSave(url):
r = requests.get(url, verify=False)
open('_'.join(url.split('/')[2:]).replace(':',''),'wb').write(r.text.encode('utf8'))
ログイン後にコピー

现在,让我们增加一些代码来遍历每一个 url,请求每个站点的 robots.txt 文件,并将其保存到本地以供后续使用。

 for a in urls:
getAndSave(a + 'robots.txt')
ログイン後にコピー

这样就会将每一个站点的 robots.txt 文件爬取到当前工作目录下。这只是一个很简单的例子。

总结

希望你在阅读完本文后,可以自己灵活的使用 Python 解析 nmap 扫描结果。

更多巧用python和libnmapd,提取Nmap扫描结果相关文章请关注PHP中文网!

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート