파이썬(Python)/화이트해킹,침투테스트(Hack,Penetration)

Python NMAP 포트스캐너 만들기(wireshark로 결과 확인하기)

끄적끄적아무거나 2021. 8. 15. 09:27
반응형

파이썬 nmap으로 port scanner 만들기

 

nmap은 네트워크 검사, 모니터, 시험에 유용한 소프트웨어이다. 파이썬에도 라이브러리를 제공해서 파이썬과 연결해서 사용할 수 있다. nmap을 설치하고 간단하게 파이썬에서 사용하는 방법은 https://scribblinganything.tistory.com/235 글을 참조하길 바란다.

 

앞선 포스트에서 socket으로 포트스캔을 하였다. (https://scribblinganything.tistory.com/258) socket은 파이썬 내장 함수로 별도의 설치 없이 바로 실행할 수 있다. 이번에는 nmap을 사용해서 실행 해보겠다. 

 


구현하기

 

코드>>

import nmap
import ipaddress
import re

port_regex = re.compile("([0-9]+){1,5}-([0-9]+){1,5}")
ip_regex1 = re.compile("^\d")
nmap_scan = nmap.PortScanner()

while True:
    ip_addr_input = input("IP주소를 입력하세요(ex: 127.0.0.1) :")
    try:
        ip_regex1_valid = ip_regex1.search(ip_addr_input.replace(" ",""))
        if ip_regex1_valid:
            ip_addr = ipaddress.ip_address(ip_addr_input)
            print(ip_addr)
            print(type(ip_addr))
            break
    except:
        print("잘못된 주소 형식입니다.")

while True:
    port_min = 0
    port_max = 65535
    port_range = input("포트범위를 정해주세요(ex:0-65535) :")
    port_range_valid = port_regex.search(port_range.replace(" ",""))
    if port_range_valid:
        port_min = int(port_range_valid.group(1))
        port_max = int(port_range_valid.group(2))
        break

for port in range(port_min, port_max + 1):
    try:
        port_condition = nmap_scan.scan(ip_addr_input, str(port))
        print(port_condition)
        state = (port_condition['scan'][ip_addr_input]['tcp'][port]['state'])
        print(f"{port} 포트 상태는 '{state}'입니다")
    except:
        print(f"{port} 포트는 닫혀있습니다")

 

결과>>

IP주소를 입력하세요(ex: 127.0.0.1) :211.43.203.70
211.43.203.70
<class 'ipaddress.IPv4Address'>
포트범위를 정해주세요(ex:0-65535) :442-444
{'nmap': {'command_line': 'nmap -oX - -p 442 -sV 211.43.203.70', 'scaninfo': {'tcp': {'method': 'syn', 'services': '442'}}, 'scanstats': {'timestr': 'Thu Aug 12 17:35:35 2021', 'elapsed': '1.11', 'uphosts': '1', 'downhosts': '0', 'totalhosts': '1'}}, 'scan': {'211.43.203.70': {'hostnames': [{'name': '', 'type': ''}], 'addresses': {'ipv4': '211.43.203.70'}, 'vendor': {}, 'status': {'state': 'up', 'reason': 'reset'}, 'tcp': {442: {'state': 'filtered', 'reason': 'no-response', 'name': 'cvc_hostd', 'product': '', 'version': '', 'extrainfo': '', 'conf': '3', 'cpe': ''}}}}}
442 포트 상태는 'filtered'입니다
{'nmap': {'command_line': 'nmap -oX - -p 443 -sV 211.43.203.70', 'scaninfo': {'tcp': {'method': 'syn', 'services': '443'}}, 'scanstats': {'timestr': 'Thu Aug 12 17:35:48 2021', 'elapsed': '13.41', 'uphosts': 
'1', 'downhosts': '0', 'totalhosts': '1'}}, 'scan': {'211.43.203.70': {'hostnames': [{'name': '', 'type': ''}], 'addresses': {'ipv4': '211.43.203.70'}, 'vendor': {}, 'status': {'state': 'up', 'reason': 'syn-ack'}, 'tcp': {443: {'state': 'open', 'reason': 'syn-ack', 'name': 'http', 'product': 'Apache httpd', 'version': '', 'extrainfo': '', 'conf': '10', 'cpe': 'cpe:/a:apache:http_server'}}}}}
443 포트 상태는 'open'입니다
{'nmap': {'command_line': 'nmap -oX - -p 444 -sV 211.43.203.70', 'scaninfo': {'tcp': {'method': 'syn', 'services': '444'}}, 'scanstats': {'timestr': 'Thu Aug 12 17:35:49 2021', 'elapsed': '1.12', 'uphosts': '1', 'downhosts': '0', 'totalhosts': '1'}}, 'scan': {'211.43.203.70': {'hostnames': [{'name': '', 'type': ''}], 'addresses': {'ipv4': '211.43.203.70'}, 'vendor': {}, 'status': {'state': 'up', 'reason': 'syn-ack'}, 'tcp': {444: {'state': 'filtered', 'reason': 'no-response', 'name': 'snpp', 'product': '', 'version': '', 'extrainfo': '', 'conf': '3', 'cpe': ''}}}}}
444 포트 상태는 'filtered'입니다

 

주석>>

이전에 socket으로 포트스캐너를 만들었던 방식과 거의 유사하다. 차이는 아래 코드만 있다.

for port in range(port_min, port_max + 1):
    try:
        port_condition = nmap_scan.scan(ip_addr_input, str(port))
        print(port_condition)
        state = (port_condition['scan'][ip_addr_input]['tcp'][port]['state'])
        print(f"{port} 포트 상태는 '{state}'입니다")
    except:
        print(f"{port} 포트는 닫혀있습니다")

 

위 코드는 원하는 ip 주소와 port를 넣어서 nmap으로 동작시키면 나오는 결과를 port_condition으로 받았다. 해당 내용은 print를 하여서 확인하였는데 결과에서 볼수 있다.

 

결과는 dictionary 형태로 나와서 포트의 상태를 원하는 키값을 넣어서 가져올 수 있다. 그리고 "command_line"을 보면 nmap을 어떤 명령을 실행 시켜 진행했는지 알 수 있다.

 

nmap -oX -  -p 442 -sV 211.43.203.70 

 

-oX는 nmap을 XML 형식으로 가져오겠다는 의미이다.

 

-p는 포트번호이다.

 

-sV는 해당 아이피의 서버나 데몬의 버전을 출력한다. 

 


와이어 샤크로 결과 확인하기

 

filter : tcp.port == 443 and ip.addr == 211.43.203.70

wireshark의 필터링 기능을 사용해서 필터한 결과 그림1과 같이 443번 포트로 3 핸드쉐이크(3 way handshake)가 진행되고 연결이되었음을 알 수 있다.

그림1

 

반응형