Disclaimer
This code is meant for educational purpose only, you should be well aware that you must not in any case use the code to scan for vulnerable host in production, to test the code, please load in your VM and use host-only network interface to test and learn in a safe environment.
All credits go to worawit.
The python codes
- analysis.py – This code uses Worawit’s checker.py code and Worawit’s mysmb library
- reconn.py – Uses nmap to check for live host that has tcp 445 opened
- network_discovery.py – Automatically checks which network the interface is connected to, the subnet is later used by reconn.py to check for hosts that have tcp 445 opened.
Requirements
Copy and paste these and save as requirements.txt.
ipaddress==1.0.22
netifaces==0.10.9
python-nmap==0.6.1
impacket==0.9.19
For the above python codes to work you need to install modules in the requirements.txt, pip install -r requirements.txt
impacket is required to use Worawit’s mysmb library.
Execution
Run the analysis.py to get the result printout.
Why not run the Worawit’s checker.py
anaylsys.py is mostly Worawit’s checker.py code and Worwit’s mysmb module, checker.py takes in sys.argv[1], which I do not know how to pass argument like this within a python script. I have also tried subprocess.run, however running checker.py had failed.
network_disovery.py codes
from netifaces import interfaces, ifaddresses from ipaddress import IPv4Interface # Refer to doc https://pypi.org/project/netifaces/ # interfaces method returns a list of interface. # ifaddresses method returns a dictionary on specific interface. # 18 returns layer 2 information i.e. mac address. # 2 returns layer 3 information i.e. IP address. # Hence I am only interested if any interfaces in my computer has a valid IP address. # Then I use another if loop to filter away localhost address. # The information is structured in a dictionary for easy manipulation. def check_local_valid_address(): available_interfaces = interfaces() for interface in available_interfaces: if ifaddresses(interface).get(2): if ifaddresses(interface).get(2)[0].get('addr') != '127.0.0.1': intf = interface intf_ip = ifaddresses(interface).get(2)[0].get('addr') intf_netmask = ifaddresses(interface).get(2)[0].get('netmask') intf_info = {'interface': intf, 'ip_address': intf_ip, 'netmask': intf_netmask} cidr = str(convert_subnet_to_cidr(intf_info['netmask'])) return address_belongs_to_which_subnet(intf_info['ip_address'] + '/' + cidr) # See demonstration in https://docs.python.org/3/library/ipaddress.html#ipaddress.IPv4Interface # Under network section. # The result will return an IPv4Address object hence I use str() to convert to string object. def address_belongs_to_which_subnet(host_address): return str(IPv4Interface(host_address).network) # count the number of 1 in the binary representation of 255, 254, 252, 248, 240, 224, 192, 128 # refer to this https://stackoverflow.com/questions/38085571/how-use-netaddr-to-convert-subnet-mask-to-cidr-in-python # credit goes to Eugene Yarmash who replied in the post. def convert_subnet_to_cidr(subnet_mask): return (sum(bin(int(x)).count('1') for x in subnet_mask.split('.')))
reconn.py codes
from nmap import PortScanner from network_discovery import check_local_valid_address def find_eternal_blue_vuln_hosts(): vuln_hosts = [] nm = PortScanner() # Get the subnet from network_discovery.py and use it to scan nm.scan(check_local_valid_address(),'445') for host in nm.all_hosts(): # Check if tcp/445 is open or not, this ensures tcp/445 is accessible before # doing further analysis using analysis.py # PortScanner returns a dictionary of the result, you need to check # the dictionary keys from nm[host]. if nm[host]['tcp'][445]['state'] == 'open': # collect only hosts that have 445 opened. vuln_hosts.append(nm[host]['addresses']['ipv4']) return vuln_hosts
analysis.py code
from reconn import find_eternal_blue_vuln_hosts from struct import pack import sys # https://github.com/worawit/MS17-010/ sys.path.append('/opt/eternalblue/MS17-010') from mysmb import MYSMB # From Worawit # credits go to Worawit, the below uses codes from worawit def which_host_is_vuln(): collect_vuln_hosts = [] for host in find_eternal_blue_vuln_hosts(): conn = MYSMB(host) conn.login('', '') tid = conn.tree_connect_andx('\\\\' + host + '\\' + 'IPC$') conn.set_default_tid(tid) TRANS_PEEK_NMPIPE = 0x23 recvPkt = conn.send_trans(pack('<H', TRANS_PEEK_NMPIPE), maxParameterCount=0xffff, maxDataCount=0x800) status = recvPkt.getNTStatus() if status == 0xC0000205: # STATUS_INSUFF_SERVER_RESOURCES collect_vuln_hosts.append('The target {} is not patched'.format(host)) return collect_vuln_hosts if __name__ == '__main__': hosts = which_host_is_vuln() if hosts: for host in hosts: print(host) else: print("Though there are hosts that are opened to 445 but they are not vulnerable to eternalblue.")
Results
Two Win7 hosts that have their host firewalls disabled.
Results from running the code from kali linux.