【Python×nmap】基礎と使い方


ホストの調査に便利なnmapですが、スクリプト言語から使えたら便利です。
Pythonにはnmapのモジュールが用意されています。

そこでPython+nmapでポートスキャンをしてみましょう。


モジュールのインストール


pipでモジュールをインストールすることができます。

pip install python-nmap


スキャン


nmapパッケージがPortScannerを持っています。
インスタンスを作りスキャンを実行できます。

import nmap
ps = nmap.PortScanner()
# scan port 1 to 65535
ps.scan('192.168.11.11','1-65535', '-sSV')


オブジェクトのscanメソッドの第三引数にはフラグを指定できます。
フラグはシェルコマンドのnmapと同じもので大丈夫です。
今回はSYN Scanを指定してます。
別に何でもいいんですけどねぇ。

scanを実行するとIPアドレスをキーとするディクショナリーがインスタンスに追加されます。
その配下にスキャン情報が格納されています。

それを踏まえてこんな感じで結果を取得できます。

ports = ps['192.168.11.11']['tcp'].keys() #1
for port in ports:
    print("{}:{}".format(port,ps['192.168.11.11'].tcp(port))) #2


#1でスキャンに成功した(パケット応答があった)ポートを取得しています。
#2でポート番号に関するtcpスキャン情報を取得します。

512:{'product': 'netkit-rsh rexecd', 'state': 'open', 'version': '', 'name': 'exec', 'conf': '10', 'extrainfo': '', 'reason': 'syn-ack', 'cpe': 'cpe:/o:linux:linux_kernel'}
513:{'product': '', 'state': 'open', 'version': '', 'name': 'login', 'conf': '3', 'extrainfo': '', 'reason': 'syn-ack', 'cpe': ''}
514:{'product': '', 'state': 'open', 'version': '', 'name': 'tcpwrapped', 'conf': '8', 'extrainfo': '', 'reason': 'syn-ack', 'cpe': ''}
2049:{'product': '', 'state': 'open', 'version': '2-4', 'name': 'nfs', 'conf': '10', 'extrainfo': 'RPC #100003', 'reason': 'syn-ack', 'cpe': ''}
6667:{'product': 'Unreal ircd', 'state': 'open', 'version': '', 'name': 'irc', 'conf': '10', 'extrainfo': '', 'reason': 'syn-ack', 'cpe': 'cpe:/a:unrealircd:unrealircd'}
5900:{'product': 'VNC', 'state': 'open', 'version': '', 'name': 'vnc', 'conf': '10', 'extrainfo': 'protocol 3.3', 'reason': 'syn-ack', 'cpe': ''}
21:{'product': 'vsftpd', 'state': 'open', 'version': '2.3.4', 'name': 'ftp', 'conf': '10', 'extrainfo': '', 'reason': 'syn-ack', 'cpe': 'cpe:/a:vsftpd:vsftpd:2.3.4'}
22:{'product': 'OpenSSH', 'state': 'open', 'version': '4.7p1 Debian 8ubuntu1', 'name': 'ssh', 'conf': '10', 'extrainfo': 'protocol 2.0', 'reason': 'syn-ack', 'cpe': 'cpe:/o:linux:linux_kernel'}
23:{'product': 'Linux telnetd', 'state': 'open', 'version': '', 'name': 'telnet', 'conf': '10', 'extrainfo': '', 'reason': 'syn-ack', 'cpe': 'cpe:/o:linux:linux_kernel'}
25:{'product': 'Postfix smtpd', 'state': 'open', 'version': '', 'name': 'smtp', 'conf': '10', 'extrainfo': '', 'reason': 'syn-ack', 'cpe': 'cpe:/a:postfix:postfix'}
6697:{'product': 'Unreal ircd', 'state': 'open', 'version': '', 'name': 'irc', 'conf': '10', 'extrainfo': '', 'reason': 'syn-ack', 'cpe': 'cpe:/a:unrealircd:unrealircd'}
3632:{'product': 'distccd', 'state': 'open', 'version': 'v1', 'name': 'distccd', 'conf': '10', 'extrainfo': '(GNU) 4.2.4 (Ubuntu 4.2.4-1ubuntu4)', 'reason': 'syn-ack', 'cpe': ''}
53:{'product': 'ISC BIND', 'state': 'open', 'version': '9.4.2', 'name': 'domain', 'conf': '10', 'extrainfo': '', 'reason': 'syn-ack', 'cpe': 'cpe:/a:isc:bind:9.4.2'}
8009:{'product': 'Apache Jserv', 'state': 'open', 'version': '', 'name': 'ajp13', 'conf': '10', 'extrainfo': 'Protocol v1.3', 'reason': 'syn-ack', 'cpe': ''}
5432:{'product': 'PostgreSQL DB', 'state': 'open', 'version': '8.3.0 - 8.3.7', 'name': 'postgresql', 'conf': '10', 'extrainfo': '', 'reason': 'syn-ack', 'cpe': 'cpe:/a:postgresql:postgresql:8.3'}
8180:{'product': 'Apache Tomcat/Coyote JSP engine', 'state': 'open', 'version': '1.1', 'name': 'http', 'conf': '10', 'extrainfo': '', 'reason': 'syn-ack', 'cpe': 'cpe:/a:apache:coyote_http_connector:1.1'}
445:{'product': 'Samba smbd', 'state': 'open', 'version': '3.X', 'name': 'netbios-ssn', 'conf': '10', 'extrainfo': 'workgroup: WORKGROUP', 'reason': 'syn-ack', 'cpe': 'cpe:/a:samba:samba:3'}
139:{'product': 'Samba smbd', 'state': 'open', 'version': '3.X', 'name': 'netbios-ssn', 'conf': '10', 'extrainfo': 'workgroup: WORKGROUP', 'reason': 'syn-ack', 'cpe': 'cpe:/a:samba:samba:3'}
2121:{'product': 'ProFTPD', 'state': 'open', 'version': '1.3.1', 'name': 'ftp', 'conf': '10', 'extrainfo': '', 'reason': 'syn-ack', 'cpe': 'cpe:/a:proftpd:proftpd:1.3.1'}
1099:{'product': 'GNU Classpath grmiregistry', 'state': 'open', 'version': '', 'name': 'rmiregistry', 'conf': '10', 'extrainfo': '', 'reason': 'syn-ack', 'cpe': ''}
80:{'product': 'Apache httpd', 'state': 'open', 'version': '2.2.8', 'name': 'http', 'conf': '10', 'extrainfo': '(Ubuntu) DAV/2', 'reason': 'syn-ack', 'cpe': 'cpe:/a:apache:http_server:2.2.8'}
8787:{'product': 'Ruby DRb RMI', 'state': 'open', 'version': '', 'name': 'drb', 'conf': '10', 'extrainfo': 'Ruby 1.8; path /usr/lib/ruby/1.8/drb', 'reason': 'syn-ack', 'cpe': 'cpe:/a:ruby-lang:ruby:1.8'}
39124:{'product': '', 'state': 'open', 'version': '1-3', 'name': 'mountd', 'conf': '10', 'extrainfo': 'RPC #100005', 'reason': 'syn-ack', 'cpe': ''}
43996:{'product': '', 'state': 'open', 'version': '1-4', 'name': 'nlockmgr', 'conf': '10', 'extrainfo': 'RPC #100021', 'reason': 'syn-ack', 'cpe': ''}
51551:{'product': '', 'state': 'open', 'version': '', 'name': '', 'conf': '', 'extrainfo': '', 'reason': 'syn-ack', 'cpe': ''}
42469:{'product': '', 'state': 'open', 'version': '1', 'name': 'status', 'conf': '10', 'extrainfo': 'RPC #100024', 'reason': 'syn-ack', 'cpe': ''}
3306:{'product': 'MySQL', 'state': 'open', 'version': '5.0.51a-3ubuntu5', 'name': 'mysql', 'conf': '10', 'extrainfo': '', 'reason': 'syn-ack', 'cpe': 'cpe:/a:mysql:mysql:5.0.51a-3ubuntu5'}
111:{'product': '', 'state': 'open', 'version': '2', 'name': 'rpcbind', 'conf': '10', 'extrainfo': 'RPC #100000', 'reason': 'syn-ack', 'cpe': ''}
6000:{'product': '', 'state': 'open', 'version': '', 'name': 'X11', 'conf': '10', 'extrainfo': 'access denied', 'reason': 'syn-ack', 'cpe': ''}
1524:{'product': 'Metasploitable root shell', 'state': 'open', 'version': '', 'name': 'shell', 'conf': '10', 'extrainfo': '', 'reason': 'syn-ack', 'cpe': ''}


上のスキャン結果はMetasploitableのものです。

ちなみにスキャン情報はscanを実行すると戻り値としても取得できますが、
私めは戻り値を使うよりも上の方法が楽かなと思っている次第でございます。