이제 파이썬과 nmap 통해 port scanner를 제작 해보도록 하겠습니다.
참조 - 해커의언어, 치명적 파이썬 / TJ오코너
1. optparse 제작
먼저 optparse를 통해 아래와같은 소스를 제작해 보도록 하겠습니다.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import optparse | |
port = '21,22,23,25,42,53,70,79,80,88,110,118,156,161,220,8080' | |
def main(): | |
parser = optparse.OptionParser('usage %prog <options> \n-H <target host> : input target host name \n-p <target port> : input target port name \n-A <all port> : target is all port') | |
parser.add_option('-H', dest='tgtHost', type='string', help='specify target host') | |
parser.add_option('-p', dest='tgtPort', type='string', help='specify target port[s] separated by comma') | |
parser.add_option('-A', dest='allPort', action='store_true', help='target port is all') | |
(options, args) = parser.parse_args() | |
tgtHost = options.tgtHost | |
tgtPorts = str(options.tgtPort).split(',') | |
allPort = options.allPort | |
if ((tgtPorts[0] == 'None') & (allPort == None)) | (tgtHost == None) : | |
print(parser.usage) | |
exit(0) | |
if (allPort == True): | |
print('allport') | |
else: | |
print('port') | |
if __name__ == '__main__': | |
main() |
-H와 -p -A 옵션을 통해 각각 아래의 기능을 구현합니다.
-H = Host name (ex. 127.0.0.1)
-p = port number (ex. 22)
-A = 직접 명시해 놓은 port (21,22,23,25,42,53,70,79,80,88,110,118,156,161,220,8080)을 스캐닝 합니다.
line 15: 15번 라인을 통해 -H옵션이 없거나 -p나 -A옵션중 하나가 쓰이지 않았다면 프로그램을 종료하도록 처리합니다.
line 19, 22: 19번 라인과 22번 라인을 통해 각 각 -p옵션과 -A옵션을 처리합니다.
-A옵션이 있을 때엔 위에 port변수에 명시한 port들을 scanning하는 분기를 처리하고
-A옵션이 없고 -p옵션이 있을 때에는 -p옵션에 명시한 port들을 scanning하는 분기를 처리합니다.
2. portscanner 제작
nmap을 통해 아래와 같은 함수를 제작해 줍니다.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import nmap | |
def nmapScan(tgtHost, tgtPort): | |
nmScan = nmap.PortScanner() | |
nmScan.scan(tgtHost, tgtPort) | |
state = nmScan[tgtHost]['tcp'][int(tgtPort)]['state'] | |
print(" [*] " + tgtHost + " tcp/" + tgtPort + " " + state) |
line 4: 4번 라인을 통해 nmap.PortScanner를 load해 줍니다.
line 5: 5번 라인을 통해 함수 호출때 입력받은 인자(ip주소, 포트넘버)를 load 합니다.
line 6: 6번 라인을 통해 nmScan을 통해 현재 상태 state값을 받아옵니다.
line 7: 7번 라인을 통해 값을 print 해 줍니다.
3. portscanner 완성 및 실행
위에 제작한 1, 2번을 아래와 같이 합쳐줍니다.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import optparse | |
import socket | |
import nmap | |
port = '21,22,23,25,42,53,70,79,80,88,110,118,156,161,220,8080' | |
def nmapScan(tgtHost, tgtPort): | |
nmScan = nmap.PortScanner() | |
nmScan.scan(tgtHost, tgtPort) | |
state = nmScan[tgtHost]['tcp'][int(tgtPort)]['state'] | |
print(" [*] " + tgtHost + " tcp/" + tgtPort + " " + state) | |
def main(): | |
parser = optparse.OptionParser('usage %prog <options> \n-H <target host> : input target host name \n-p <target port> : input target port name \n-A <all port> : target is all port') | |
parser.add_option('-H', dest='tgtHost', type='string', help='specify target host') | |
parser.add_option('-p', dest='tgtPort', type='string', help='specify target port[s] separated by comma') | |
parser.add_option('-A', dest='allPort', action='store_true', help='target port is all') | |
(options, args) = parser.parse_args() | |
tgtHost = options.tgtHost | |
tgtPorts = str(options.tgtPort).split(',') | |
allPort = options.allPort | |
if ((tgtPorts[0] == 'None') & (allPort == None)) | (tgtHost == None) : | |
print(parser.usage) | |
exit(0) | |
if (allPort == True): | |
tgtPorts = str(port).split(',') | |
for tgtPort in tgtPorts: | |
nmapScan(tgtHost, tgtPort) | |
else: | |
for tgtPort in tgtPorts: | |
nmapScan(tgtHost, tgtPort) | |
if __name__ == '__main__': | |
main() |
27, 32번 line의 if else문도 수정 합니다.
------------------------------------------실행 모습---------------------------------------
# python3 TCPportscanner -H 127.0.0.1 -p 22
[*] 127.0.0.1 tcp/22 open
# python3 TCPportscanner -H 127.0.0.1 -A
[*] 127.0.0.1 tcp/21 closed
[*] 127.0.0.1 tcp/22 open
[*] 127.0.0.1 tcp/23 open
[*] 127.0.0.1 tcp/25 closed
[*] 127.0.0.1 tcp/42 closed
[*] 127.0.0.1 tcp/53 closed
[*] 127.0.0.1 tcp/70 closed
[*] 127.0.0.1 tcp/79 closed
[*] 127.0.0.1 tcp/80 closed
[*] 127.0.0.1 tcp/88 closed
[*] 127.0.0.1 tcp/110 closed
[*] 127.0.0.1 tcp/118 closed
[*] 127.0.0.1 tcp/156 closed
[*] 127.0.0.1 tcp/161 closed
[*] 127.0.0.1 tcp/220 closed
[*] 127.0.0.1 tcp/8080 closed
( httpd 80번 포트 서비스 오픈 후 실행)
# service httpd start
Starting httpd: httpd: apr_sockaddr_info_get() failed for 500009674769
httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName
[ OK ]
# python3 TCPportscanner -H 127.0.0.1 -A
[*] 127.0.0.1 tcp/21 closed
[*] 127.0.0.1 tcp/22 open
[*] 127.0.0.1 tcp/23 open
[*] 127.0.0.1 tcp/25 closed
[*] 127.0.0.1 tcp/42 closed
[*] 127.0.0.1 tcp/53 closed
[*] 127.0.0.1 tcp/70 closed
[*] 127.0.0.1 tcp/79 closed
[*] 127.0.0.1 tcp/80 open
[*] 127.0.0.1 tcp/88 closed
[*] 127.0.0.1 tcp/110 closed
[*] 127.0.0.1 tcp/118 closed
[*] 127.0.0.1 tcp/156 closed
[*] 127.0.0.1 tcp/161 closed
[*] 127.0.0.1 tcp/220 closed
[*] 127.0.0.1 tcp/8080 closed
------------------------------------------실행 모습---------------------------------------