Commit df94fd71 authored by yogesh.m's avatar yogesh.m

Merge branch 'Asset_Discovery_Without_UI' of...

Merge branch 'Asset_Discovery_Without_UI' of https://gitlab-pm.knowledgelens.com/yogesh.m/asset_discovery into Asset_Discovery_Without_UI
parents e0819350 05d95f59
*.pyc
*.cypython-311.pyc
assets.json
migrations
.idea
\ No newline at end of file
# Default ignored files
/shelf/
/workspace.xml
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 3.8" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="PLAIN" />
<option name="myDocStringFormat" value="Plain" />
</component>
</module>
\ No newline at end of file
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8" project-jdk-type="Python SDK" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/asset_discovery.iml" filepath="$PROJECT_DIR$/.idea/asset_discovery.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
\ No newline at end of file
This diff is collapsed.
configuration:
threads: 20 #number of threads to scan at once
transfer frequency: 1 #how frequent the scan needs to be
unifytwin_server_ip_address: https://webhook.site/43393e36-6b04-4481-8485-fad2c7cd549f #Data will be sent back here
edge_device_location : Dalmia Cement
null_loopback: False
interfaces: eth0
blacklist_ip: ['46.4.105.116','172.67.214.157','3.6.115.64','104.21.53.154']
blacklist_dns: ['webhook.site.']
ui_host: 0.0.0.0
ui_port: 8081
active_scan: False
active_scan_start: 2.2.2.20
active_scan_end: 2.2.2.30
transmit_assets: False
import binascii
import json
from protocol_discover_helpers import modbus_discover,enip_discover,s7_discover,omron_discover,bacnet_discover,codesys_discover,dnp3_discover
class Packet_Analyzer():
def __init__(self):
self.data=None
self.protocol_list={502: modbus_discover,44818:enip_discover,102:s7_discover,9600:omron_discover,47808:bacnet_discover,2455:codesys_discover,20000:dnp3_discover}
def identify_protocol(self,hex_pkt):
protocols=""
if(hex_pkt[46:48] == b"06"):
protocols=protocols+"tcp"
port=self.get_tcp_port(hex_pkt)
if(port in self.protocol_list):
port_protocol = self.protocol_list[port].protocol_identify(hex_pkt)
if (port_protocol):
protocols = protocols + port_protocol
if (hex_pkt[46:48] == b"11"):
protocols = protocols + "udp"
port = self.get_udp_port(hex_pkt)
if (port in self.protocol_list):
port_protocol = self.protocol_list[port].protocol_identify(hex_pkt)
if(port_protocol):
protocols = protocols + port_protocol
return protocols
def get_ip(self,hex_pkt):
if(hex_pkt[24:28]==b"0800"):
ip_inhex= hex_pkt[28+24:28+24+8]
ip = str(int.from_bytes(binascii.unhexlify(ip_inhex[0:2]), byteorder="little"))+"."+str(int.from_bytes(binascii.unhexlify(ip_inhex[2:4]), byteorder="little"))+"."+str(int.from_bytes(binascii.unhexlify(ip_inhex[4:6]), byteorder="little"))+"."+str(int.from_bytes(binascii.unhexlify(ip_inhex[6:8]), byteorder="little"))
return ip
def get_mac(self,hex_pkt):
souce_mac = hex_pkt[12:24].decode()
modified_src_mac = ":".join(souce_mac[i:i + 2] for i in range(0, len(souce_mac), 2))
return modified_src_mac
def get_tcp_port(self,inhex):
if(inhex[46:48]==b"06"):
port = int(inhex[68:72], 16)
return port
def get_udp_port(self,inhex):
if (inhex[46:48] == b"11"):
port = int(inhex[68:72], 16)
return port
def find_mac(self,mac, trim_count=-1):
try:
if len(mac[:trim_count]) == 0:
return "No Mac"
else:
res = self.data[mac[:trim_count]]
return res
except:
r = self.find_mac(mac, trim_count - 1)
return r
def get_vendor(self,mac):
f = open("utilities/mac_vendors.json")
self.data = json.loads(f.read())
vendor = self.find_mac(mac.upper())
return vendor
def get_os(self,inhex):
try:
ttl = int(inhex[44:46].decode())
except:
ttl = 255
if ttl <=64:
return "Unix/Linux Based"
elif ttl <= 128:
return "Windows"
elif ttl <= 254:
return "Solaris"
else:
return "Indeterminate Operating System"
This diff is collapsed.
sudo cp ../security-management /usr/share -r
test -f /usr/share/security-management/config.yaml && ifaces=$(cat /usr/share/security-management/config.yaml | grep interfaces| sed 's/interfaces: //g') ||ifaces=$(ip link show | grep ': '|sed 's/\: <.*//g'| sed 's/[0-9]: //g')
inface=$(echo $ifaces|sed 's/ .*//g')
echo '[Unit]
Description=asset_discovery service
After=syslog.target network-online.target
[Service]
Type=simple
Restart=on-failure
WorkingDirectory=/usr/share/security-management/
User=root
ExecStart=/bin/bash /usr/share/security-management/start.sh --start -i '$inface'
ExecStop=/bin/bash /usr/share/security-management/stop.sh
[Install]
WantedBy=multi-user.target' |sudo tee /etc/systemd/system/security-management.service >/dev/null
sudo systemctl daemon-reload
sudo ln -s /usr/share/security-management/start.sh /bin/security-management
(sudo crontab -l ; echo "@reboot /bin/security-management --start -i $inface >> /var/log/assets_management_logs.txt 2&1")| sudo crontab -
sudo service security-management start
echo 'Install Complete!!!'
echo '###################################################################
#Start Asset Discovery : sudo service security-management start
#Interface currently used : '$inface'
###################################################################'
import json
import yaml
import requests
try:
yamlfile=open("config.yaml")
data = yaml.load(yamlfile, Loader=yaml.FullLoader)
transmit_assets=data["configuration"]["transmit_assets"]
url = data["configuration"]["unifytwin_server_ip_address"]
except Exception as e:
transmit_assets=False
try:
with open("assets.json") as json_file:
json_decoded = json.load(json_file)
except:
json_decoded={}
def write_into_json_file(json_decoded):
with open("assets.json", 'w') as json_file:
json.dump(json_decoded, json_file)
def insert_asset(ip,last_activity,dev_type,protocols,mac,vendor,firmware,model,os,plant):
json_decoded[ip]={}
json_transmit_data={}
json_transmit_data[ip]={}
json_transmit_data[ip]["last_activity"]=json_decoded[ip]["last_activity"]=last_activity
json_transmit_data[ip]["dev_type"]=json_decoded[ip]["dev_type"] =dev_type
json_transmit_data[ip]["protocols"]=json_decoded[ip]["protocols"] = protocols
json_transmit_data[ip]["mac"]=json_decoded[ip]["mac"] = mac
json_transmit_data[ip]["vendor"]=json_decoded[ip]["vendor"] = vendor
json_transmit_data[ip]["firmware"]=json_decoded[ip]["firmware"] = firmware
json_transmit_data[ip]["model"]=json_decoded[ip]["model"] = model
json_transmit_data[ip]["os"]=json_decoded[ip]["os"] = os
json_transmit_data[ip]["plant"]=json_decoded[ip]["plant"] = plant
write_into_json_file(json_decoded)
if transmit_assets:
requests.post(url=url,json=json_transmit_data)
def update_asset(ip,prev_protocols,last_activity,dev_type,vendor,firmware,model):
json_transmit_data = {}
json_transmit_data[ip] = {}
json_transmit_data[ip]["protocols"]=json_decoded[ip]["protocols"] = prev_protocols
json_transmit_data[ip]["last_activity"]=json_decoded[ip]["last_activity"] = last_activity
json_transmit_data[ip]["dev_type"]=json_decoded[ip]["dev_type"] = dev_type
json_transmit_data[ip]["vendor"]=json_decoded[ip]["vendor"] = vendor
json_transmit_data[ip]["firmware"]=json_decoded[ip]["firmware"] = firmware
json_transmit_data[ip]["model"]=json_decoded[ip]["model"] = model
write_into_json_file(json_decoded)
if transmit_assets:
requests.post(url=url, json=json_transmit_data)
def update_last_activity_and_protocols(ip,prev_protocols,last_activity):
json_transmit_data = {}
json_transmit_data[ip] = {}
json_transmit_data[ip]["protocols"]=json_decoded[ip]["protocols"] = prev_protocols
json_transmit_data[ip]["last_activity"]=json_decoded[ip]["last_activity"] = last_activity
write_into_json_file(json_decoded)
if transmit_assets:
requests.post(url=url, json=json_transmit_data)
def update_last_activity(ip,last_activity):
json_transmit_data = {}
json_transmit_data[ip] = {}
if(json_decoded[ip]["last_activity"]!=last_activity):
json_transmit_data[ip]["last_activity"]=json_decoded[ip]["last_activity"] = last_activity
write_into_json_file(json_decoded)
if transmit_assets:
requests.post(url=url, json=json_transmit_data)
def delete_asset():
print()
def get_existing_protocols(ip):
try:
return json_decoded[ip]["protocols"]
except KeyError:
return "No key"
def check_asset_exists(ip):
if(ip in json_decoded):
return True
else:
return False
\ No newline at end of file
from protocol_enumerators import ethernetip_enum as eip
from protocol_enumerators import s7_enum as s7
from protocol_enumerators import bacnet as bac
from protocol_enumerators import modbus
from protocol_enumerators import dnp3_enum
from protocol_enumerators import codesys
from helpers.port_service_helper import psdata
from protocol_enumerators import omron
import binascii
import os
from helpers.Packet_Analyzer import Packet_Analyzer
import sys
def analyse_protocol(protocols, pkt):
try:
dev_type = "Unknown"
vendor = "Unknown"
firmware = "Unknown"
model = "Unknown"
inhex = binascii.hexlify(bytes(pkt))
pa = Packet_Analyzer()
if ("enip" in protocols):
print(protocols)
res = eip.get_info(pa.get_ip(inhex),int(pa.get_tcp_port(inhex)) if "tcp" in protocols else int(pa.get_udp_port(inhex)))
if (res):
dev_type = res['Type']
vendor = res['Vendor']
firmware = res['ProductName']
model = res['SerialNumber']
elif ("s7comm" in protocols):
res = s7.get_info(pa.get_ip(inhex), int(pa.get_tcp_port(inhex)) if "tcp" in protocols else int(pa.get_udp_port(inhex)))
if (res):
dev_type = res['Module Type'] + " " + res['System Name']
vendor = res['Copyright']
firmware = res['Module'] + " " + res['Version']
model = res['Serial Number']
elif ("bacnet" in protocols):
res = bac.get_info(pa.get_ip(inhex), int(pa.get_tcp_port(inhex)) if "tcp" in protocols else int(pa.get_udp_port(inhex)))
if (res):
dev_type = res['desc'] if not res['desc'] == '' else res['object']
vendor = res['vendorid']
firmware = res['firmware']
model = res['model']
elif ("codesys" in protocols):
res = codesys.get_info(pa.get_ip(inhex), int(pa.get_tcp_port(inhex)) if "tcp" in protocols else int(
pa.get_udp_port(inhex)))
if (res):
dev_type = res['OS Name']
vendor = res['Product Type']
elif ("modbus" in protocols):
res = modbus.get_info(pa.get_ip(inhex), int(pa.get_tcp_port(inhex)) if "tcp" in protocols else int(
pa.get_udp_port(inhex)), False)
if (res):
dev_type = res['Device identification']
vendor = res['Slave ID data']
model = res['sid']
elif ("omron" in protocols):
res = omron.get_info(pa.get_ip(inhex), int(pa.get_tcp_port(inhex)) if "tcp" in protocols else int(
pa.get_udp_port(inhex)), False)
if (res):
dev_type = 'Omron Device'
vendor = 'Omron Devices'
firmware = res['Controller Version']
model = res['Controller Model']
elif("dnp3" in protocols):
res=dnp3_enum.get_info(pa.get_ip(inhex) ,int(pa.get_tcp_port(inhex)) if "tcp" in protocols else int(pa.get_udp_port(inhex)))
if(res):
dev_type=res['Device Type']
else:
port_no = str(pa.get_tcp_port(inhex)) if "tcp" in protocols else str(
pa.get_udp_port(inhex)) if "udp" in protocols else "Unknown"
dev_type = psdata[port_no] if port_no in psdata else "Unknown"
vendor = pa.get_vendor(pa.get_mac(inhex))
return dev_type, vendor, firmware, model
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
print(exc_type, fname, exc_tb.tb_lineno, e)
def update_protocol(protocols,pkt):
try:
dev_type="Unknown"
vendor="Unknown"
firmware="Unknown"
model="Unknown"
inhex = binascii.hexlify(bytes(pkt))
pa=Packet_Analyzer()
if("enip" in protocols):
res=eip.get_info(pa.get_ip(inhex) ,int(pa.get_tcp_port(inhex)) if "tcp" in protocols else int(pa.get_udp_port(inhex)))
if(res):
dev_type=res['Type']
vendor=res['Vendor']
firmware=res['ProductName']
model=res['SerialNumber']
elif("s7comm" in protocols):
res=s7.get_info(pa.get_ip(inhex) ,int(pa.get_tcp_port(inhex)) if "tcp" in protocols else int(pa.get_udp_port(inhex)))
if(res):
dev_type=res['Module Type']+" "+res['System Name']
vendor=res['Copyright']
firmware=res['Module']+" "+res['Version']
model=res['Serial Number']
elif("bacnet" in protocols):
res=bac.get_info(pa.get_ip(inhex) ,int(pa.get_tcp_port(inhex)) if "tcp" in protocols else int(pa.get_udp_port(inhex)))
if(res):
dev_type=res['desc']
vendor=res['vendorid']
firmware=res['firmware']
model=res['model']
elif("codesys" in protocols):
res=codesys.get_info(pa.get_ip(inhex) ,int(pa.get_tcp_port(inhex)) if "tcp" in protocols else int(pa.get_udp_port(inhex)))
if(res):
dev_type=res['OS Name']
vendor=res['Product Type']
elif("modbus" in protocols):
res=modbus.get_info(pa.get_ip(inhex) ,int(pa.get_tcp_port(inhex)) if "tcp" in protocols else int(pa.get_udp_port(inhex)),False)
if(res):
dev_type=res['Device identification']
vendor=res['Slave ID data']
model=res['sid']
elif("omron" in protocols):
res=omron.get_info(pa.get_ip(inhex) ,int(pa.get_tcp_port(inhex)) if "tcp" in protocols else int(pa.get_udp_port(inhex)),False)
if(res):
dev_type='Omron Device'
vendor='Omron Devices'
firmware=res['Controller Version']
model=res['Controller Model']
elif("dnp3" in protocols):
res=dnp3_enum.get_info(pa.get_ip(inhex) ,int(pa.get_tcp_port(inhex)) if "tcp" in protocols else int(pa.get_udp_port(inhex)))
if(res):
dev_type=res['Device Type']
return dev_type,vendor,firmware,model
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
print(exc_type, fname, exc_tb.tb_lineno, e)
def protocol_identify(hex_pkt):
if (b'810a' in hex_pkt and hex_pkt[84:88] == b'810a'):
return ":bacnet"
def protocol_identify(hex_pkt):
if (b'bbbb' in hex_pkt and hex_pkt[108:112] == b'bbbb'):
return ":codesys"
\ No newline at end of file
def protocol_identify(hex_pkt):
if (b'6300' in hex_pkt and hex_pkt[108:112] == b'6300'):
return ":enip"
def protocol_identify(hex_pkt):
if(hex_pkt[108:112] == b'0000'):
return ":modbus"
def protocol_identify(hex_pkt):
if ((b'8000' in hex_pkt or b'c000' in hex_pkt) and (hex_pkt[84:88] == b'8000' or hex_pkt[84:88] == b'c000')):
print("omron found")
return ":omron"
\ No newline at end of file
def protocol_identify(hex_pkt):
if (b'0300' in hex_pkt and hex_pkt[108:112] == b'0300'):
return ":s7comm"
\ No newline at end of file
This diff is collapsed.
import socket
import binascii
def action(host, port):
# CoDeSyS little endian query
lile_query = binascii.unhexlify("bbbb0100000001")
# CoDeSyS big endian query
bige_query = binascii.unhexlify("bbbb0100000101")
# Create a socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
# Connect to the remote host
sock.connect((host, port))
# Send the little endian query
sock.send(lile_query)
# Receive the response
response = sock.recv(1024)
# If there was no response, try the big endian query
if not response:
sock.send(bige_query)
response = sock.recv(1024)
# Check if the response starts with 0xbb
if response and response[0] == 0xbb:
# Extract the null-terminated strings (OS Name, OS Type, Product Type)
os_name_end = response.find(b'\x00', 64)
os_name = response[64:os_name_end].decode()
os_type_end = response.find(b'\x00', 96)
os_type = response[96:os_type_end].decode()
product_type_end = response.find(b'\x00', 128)
product_type = response[128:product_type_end].decode()
# Close the socket
sock.close()
output = {
"OS Name": os_name,
"Product Type": product_type,
"Device IP":host,
"Port":port
}
return output
except Exception as e:
print(f"Error: {e}")
return None
def get_info(ip,port):
return(action(ip,port))
\ No newline at end of file
This diff is collapsed.
import struct
from scapy.all import *
import socket
import json
output={}
modbus_exception_codes = {
1 : 'ILLEGAL FUNCTION',
2 : 'ILLEGAL DATA ADDRESS',
3 : 'ILLEGAL DATA VALUE',
4 : 'SLAVE DEVICE FAILURE',
5 : 'ACKNOWLEDGE',
6 : 'SLAVE DEVICE BUSY',
8 : 'MEMORY PARITY ERROR',
10 : 'GATEWAY PATH UNAVAILABLE',
11 : 'GATEWAY TARGET DEVICE FAILED TO RESPOND'
}
def form_rsid(sid, functionId, data):
payload_len = 2
if(len(data)>0):
payload_len = payload_len+len(data)
return b"\0\0\0\0\0"+struct.pack('BBB', payload_len, sid, functionId)+data
def discover_device_id_recursive(host, port, sid, start_id, objects_table):
rsid = form_rsid(sid, 0x2B, b"\x0E\x01"+struct.pack('B',start_id))
result = comm(host, port, rsid)
object_value=None
if (result!=False and len(result) >= 8):
ret_code = result[7]
if ( ret_code == 43 and len(result) >= 15 ):
more_follows = result[11]
next_object_id =result[12]
number_of_objects =result[13]
offset = 15
for i in range(start_id,(number_of_objects-2)):
object_len = result[offset+1]
if object_len == None:
break
object_value = result[offset + 1:offset + object_len]
offset = offset + 2 + object_len
if ( more_follows == 255 and next_object_id != 0 ):
return discover_device_id_recursive(host, port, sid, next_object_id, objects_table)
return object_value
def discover_device_id(host, port, sid):
return discover_device_id_recursive(host, port, sid, 0x0, {})
def extract_slave_id(response):
try:
byte_count = response[8]
if( byte_count == None or byte_count == 0):
return None
return struct.unpack(str(byte_count)+"s",response[9:-1])[0].decode()
except:
return None
def comm(host, port, rsid):
BUFFER_SIZE = 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.settimeout(3)
s.connect((host,port))
s.send(rsid)
data = s.recv(BUFFER_SIZE)
return data
except ConnectionError:
return False
except:
return 'terr'
def action(host,port,aggressive):
count=0
try:
for sid in range(1,247):
rsid=form_rsid(sid, 0x11, b"")
result=comm(host, port, rsid)
if(result!=False and len(result)>8):
output[sid]={'Slave ID data':'Unknown','Device identification':'Unknown'}
if(result[7]==17 or result[7]==145):
if(result[7]==17):
slave_id = extract_slave_id(result)
output[sid]["Slave ID data"] = slave_id if slave_id else "Unknown"
elif(result[7]==145):
exception_code = result[8]
exception_string = modbus_exception_codes[exception_code] if exception_code<12 and exception_code>0 else None
if(exception_string==None):
exception_string = "Unknown exception, Code="+str(exception_code)
output[sid]["Error"]=exception_string
else:
return False
device_table = discover_device_id(host, port, sid)
if (device_table!=None and len(device_table) > 0 ):
device_table = re.sub('[\x00-\x1f]',' ',device_table.decode(errors='ignore'))
output[sid]["Device identification"] = device_table.replace(" "," ")
count=0
if not aggressive:
output[sid]["sid"]="sid"+str(sid)
return output[sid]
elif(result=='terr' and count>2):
return False
elif(result==False):
return False
else:
count=count+1
return json.dumps(output)
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
print(exc_type, fname, exc_tb.tb_lineno, e)
def get_info(ip,port,aggressive=False):
return(action(ip,port,aggressive))
\ No newline at end of file
import modbus
import json
import sqlite3
def discover_modbus_slaves(host,port):
mydb=sqlite3.connect("../assets.db",check_same_thread=False)
query=mydb.cursor()
modbus_data=modbus.get_info(host,port,True)
slave_data=json.loads(modbus_data) if modbus_data!=False else False
if(slave_data):
for slave_key in slave_data:
insinventory='INSERT INTO modbus_devices\
(sid,sid_data,device_info,ip_address)\
VALUES\
("'+slave_key+'","'+slave_data[slave_key]["Slave ID data"]+'","'+slave_data[slave_key]["Device identification"]+'","'+host+'")'
query.execute(insinventory)
query.close()
mydb.commit()
\ No newline at end of file
import binascii
from scapy.all import *
import socket
memcard = {
0 : "No Memory Card",
1 : "SPRAM",
2 : "EPROM",
3 : "EEPROM"
}
def memory_card(value):
mem_card = memcard[value] if value in memcard else "Unknown Memory Card Type"
return mem_card
def send_tcp(s):
req_addr = binascii.unhexlify("46494e530000000c000000000000000000000000")
controller_data_read = binascii.unhexlify("46494e5300000015000000020000000080000200")
controller_data_read2 = binascii.unhexlify("000000ef050501")
BUFFER_SIZE = 1024
try:
s.send(req_addr)
response = s.recv(BUFFER_SIZE)
except:
return False
header = response[0]
if(header == 70):
address = response[:23]
controller_data = controller_data_read+address+controller_data_read2+binascii.unhexlify('00')
try:
s.send(controller_data)
res = s.recv(BUFFER_SIZE)
except:
return False
return res
return "ERROR"
def send_udp(host,port):
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
BUFFER_SIZE = 1024
controller_data_read = binascii.unhexlify("800002000000006300ef050100")
try:
s.sendto(controller_data_read,(host,port))
response = s.recv(BUFFER_SIZE)
except:
return False
return response
def action(host,port,protocol):
output={}
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.settimeout(3)
s.connect((host,port))
except:
return False
response = ""
offset = 0
if (protocol == "tcp"):
offset = 16
response = send_tcp(s)
else:
response = send_udp(host,port)
header = response[0]
if(header==192 or header==193 or header==70):
response_code = response[12+offset]
if(response_code == 2081):
output["Response Code"] = "Data cannot be changed (0x2108)"
elif(response_code == 290):
output["Response Code"] = "The mode is wrong (executing) (0x2201)"
elif(response_code == 0):
output["Response Code"] = "Normal completion (0x0000)"
output["Controller Model"] = ((response[14+offset:].split(b"\x00",1))[0]).decode()
output["Controller Version"] = ((response[34+offset:].split(b"\x00",1))[0]).decode()
output["For System Use"] = ((response[54+offset:].split(b"\x00",1))[0]).decode()
output["Program Area Size"] = str(response[95])
output["IOM size"] = str(response[96])
output["No. DM Words"] = str(int(binascii.hexlify(response[97:99]),base=16))
output["Timer/Counter"] = str(response[99])
output["Expansion DM Size"] = str(response[100])
output["No. of steps/transitions"] = str(int(binascii.hexlify(response[101:102]),base=16))
mem_card_type = response[102]
output["Kind of Memory Card"] = memory_card(mem_card_type)
output["Memory Card Size"] = str(int(binascii.hexlify(response[103:104]),base=16))
return (output)
def get_info(ip,port,protocol='udp'):
return(action(ip,port,protocol))
\ No newline at end of file
import binascii
from scapy.all import *
import socket
def send_receive(s,pack):
BUFFER_SIZE = 1024
try:
s.send(pack)
data = s.recv(BUFFER_SIZE)
except:
return False
return data
def first_parse_response(response,output):
value=hex(response[7])
if (value == "0x32"):
output["Module"]=response[43:43+19].decode()
output["Basic_Hardware"]=response[71:71+19].decode()
output["Version"]="%s.%s.%s"%(response[122],response[122+1],response[122+2])
return output
else:
return False
def second_parse_response(response,output):
value=hex(response[7])
offset = 0
szl_id = hex(response[30])
if (value == "0x32"):
if( szl_id != "0x1c" ):
offset = 4
output["System Name"]=((response[39+offset:].split(b"\x00",1))[0]).decode()
output["Module Type"] =((response[73+offset:].split(b"\x00",1))[0]).decode()
output["Serial Number"]=((response[175+offset:].split(b"\x00",1))[0]).decode()
output["Copyright"]=((response[141+offset:].split(b"\x00",1))[0]).decode()
return output
def action(host,port):
output={}
cotp=binascii.unhexlify('0300001611e00000001400c1020100c2020102c0010a')
alt_COTP = binascii.unhexlify("0300001611e00000000500c1020100c2020200c0010a")
ROSCTR_Setup = binascii.unhexlify("0300001902f08032010000000000080000f0000001000101e0")
Read_SZL = binascii.unhexlify("0300002102f080320700000000000800080001120411440100ff09000400110001")
first_SZL_Request = binascii.unhexlify("0300002102f080320700000000000800080001120411440100ff09000400110001")
second_SZL_Request = binascii.unhexlify("0300002102f080320700000000000800080001120411440100ff090004001c0001")
response=None
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.settimeout(3)
s.connect((host,port))
except:
return False
response=send_receive(s,cotp)
if(response):
if(hex(response[5])!="0xd0"):
s.close()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
response=send_receive(s,alt_COTP)
if(response):
if(hex(response[5])!="0xd0"):
return False
response = send_receive(s,ROSCTR_Setup)
if(response):
if(hex(response[7])!="0x32"):
return False
response = send_receive(s,Read_SZL)
if(response):
if(hex(response[7])!="0x32"):
return False
response = send_receive(s, first_SZL_Request)
try:
output = first_parse_response(response,output)
except:
return False
response = send_receive(s, second_SZL_Request)
output=second_parse_response(response,output)
output["DeviceIP"]=host
output["Port"]=port
return output
def get_info(ip,port):
return(action(ip,port))
\ No newline at end of file
scapy==2.4.5
PyYAML==5.4.1
flask==1.1.4
requests==2.27.1
markupsafe==2.0.1
asgiref==3.4.1
certifi==2023.7.22
charset-normalizer==2.0.0
Django==3.2.20
idna==3.4
sqlparse==0.4.4
tzdata==2023.3
urllib3==1.26.7
from protocol_enumerators import ethernetip_enum
from protocol_enumerators import s7_enum
from protocol_enumerators import bacnet
from protocol_enumerators import modbus
from protocol_enumerators import omron
import sqlite3
from datetime import datetime
import json_operations
probes=[s7_enum,ethernetip_enum,bacnet,modbus,omron]
def map_ports(ip,port):
query=mydb.cursor()
dev_type="Unknown"
vendor="Unknown"
firmware="Unknown"
model="Unknown"
for i in probes:
res=i.get_info(ip,port)
if(res):
if(i.__name__=="protocol_enumerators.s7_enum"):
dev_type=res['Module Type']+" "+res['System Name']
vendor=res['Copyright']
firmware=res['Module']+" "+res['Version']
model=res['Serial Number']
json_operations.update_asset(ip,"s7comm",datetime.now().strftime("%d-%m-%y %H:%M:%S"),dev_type,vendor,firmware,model)
#updateproto='UPDATE inventory SET protocols=(select protocols from inventory where ip_address="'+ip+'")||":"||"s7comm",last_activity="'+datetime.now().strftime("%d-%m-%y %H:%M:%S")+'",type="'+dev_type+'",vendor="'+vendor+'",firmware_version="'+firmware+'",model="'+model+'" WHERE ip_address="'+ip+'"'
elif(i.__name__=="protocol_enumerators.ethernetip_enum"):
dev_type=res['Type']
vendor=res['Vendor']
firmware=res['ProductName']
model=res['SerialNumber']
json_operations.update_asset(ip, "enip", datetime.now().strftime("%d-%m-%y %H:%M:%S"), dev_type,vendor, firmware, model)
#updateproto='UPDATE inventory SET protocols=(select protocols from inventory where ip_address="'+ip+'")||":"||"enip",last_activity="'+datetime.now().strftime("%d-%m-%y %H:%M:%S")+'",type="'+dev_type+'",vendor="'+vendor+'",firmware_version="'+firmware+'",model="'+model+'" WHERE ip_address="'+ip+'"'
elif(i.__name__=="protocol_enumerators.bacnet"):
dev_type=res['desc']
vendor=res['vendorid']
firmware=res['firmware']
model=res['model']
json_operations.update_asset(ip, "bacnet", datetime.now().strftime("%d-%m-%y %H:%M:%S"), dev_type, vendor,firmware, model)
#updateproto='UPDATE inventory SET protocols=(select protocols from inventory where ip_address="'+ip+'")||":"||"bacnet",last_activity="'+datetime.now().strftime("%d-%m-%y %H:%M:%S")+'",type="'+dev_type+'",vendor="'+vendor+'",firmware_version="'+firmware+'",model="'+model+'" WHERE ip_address="'+ip+'"'
elif(i.__name__=="protocol_enumerators.modbus"):
dev_type=res['Device identification']
vendor=res['Slave ID data']
model=res['sid']
json_operations.update_asset(ip, "modbus", datetime.now().strftime("%d-%m-%y %H:%M:%S"), dev_type, vendor,"Unknown", model)
#updateproto='UPDATE inventory SET protocols=(select protocols from inventory where ip_address="'+ip+'")||":"||"modbus",last_activity="'+datetime.now().strftime("%d-%m-%y %H:%M:%S")+'",type="'+dev_type+'",vendor="'+vendor+'",firmware_version="'+firmware+'",model="'+model+'" WHERE ip_address="'+ip+'"'
elif(i.__name__=="protocol_enumerators.omron"):
dev_type='Omron Device'
vendor='Omron Devices'
firmware=res['Controller Version']
model=res['Controller Model']
json_operations.update_asset(ip, "omron", datetime.now().strftime("%d-%m-%y %H:%M:%S"), dev_type, vendor,firmware, model)
#updateproto='UPDATE inventory SET protocols=(select protocols from inventory where ip_address="'+ip+'")||":"||"modbus",last_activity="'+datetime.now().strftime("%d-%m-%y %H:%M:%S")+'",type="'+dev_type+'",vendor="'+vendor+'",firmware_version="'+firmware+'",model="'+model+'" WHERE ip_address="'+ip+'"'
break
\ No newline at end of file
from scapy.all import *
import datetime
import os
import binascii
import yaml
import sqlite3
from datetime import datetime
import active_scan
import protocol_actions
import threading
import requests
import json_operations as jo
from helpers.Packet_Analyzer import Packet_Analyzer
try:
yamlfile=open("config.yaml")
data = yaml.load(yamlfile, Loader=yaml.FullLoader)
server_ip=data["configuration"]["unifytwin_server_ip_address"]
plant=data["configuration"]["edge_device_location"]
balacklist_ips=data["configuration"]["blacklist_ip"]
blacklist_dns=data["configuration"]["blacklist_dns"]
configured_threads=data["configuration"]["threads"]
interfaces=data["configuration"]["interfaces"]
null_loopback=data["configuration"]["null_loopback"]
except Exception as e:
server_ip=""
plant="Unknown Location"
balacklist_ips=['46.4.105.116','172.67.214.157','3.6.115.64','104.21.53.154']
blacklist_dns=['webhook.site.','hpd.gasmi.net.','dd01-14-98-12-178.in.ngrok.io.']
configured_threads=10
interfaces='eth0'
null_loopback=False
from sys import platform
if platform == "linux" or platform == "linux2":
clearing='clear'
elif platform == "darwin":
clearing='clear'
elif platform == "win32":
clearing='cls'
def convert_text(pkt):
inhex=binascii.hexlify(bytes(pkt))
if(null_loopback):
inhex=b'0000000000000000000000000800'+inhex[8:] if inhex[:2]==b'02' else b'00000000000000000000000086DD'+inhex[8:]
try:
pa = Packet_Analyzer()
protocols=pa.identify_protocol(inhex)
ip=pa.get_ip(inhex)
if(ip):
mac=pa.get_mac(inhex)
check_exist=jo.check_asset_exists(ip)
if(not check_exist):
dev_type,vendor,firmware,model=protocol_actions.analyse_protocol(protocols,pkt)
operating_sys=pa.get_os(inhex)
jo.insert_asset(ip,datetime.now().strftime("%d-%m-%y %H:%M:%S"),dev_type,str(protocols),mac,vendor,firmware,model,operating_sys,plant)
else:
prev_protocols=jo.get_existing_protocols(ip)
extra_proto=set(protocols.split(':'))-set(prev_protocols.split(':'))
if(extra_proto):
dev_type,vendor,firmware,model=protocol_actions.update_protocol(protocols,pkt)
prev_protocols=prev_protocols+':'+str(extra_proto).replace(", ",":").replace("{","").replace("}","").replace("'","")
if(dev_type!="Unknown"):
jo.update_asset(ip,prev_protocols,datetime.now().strftime("%d-%m-%y %H:%M:%S"),dev_type,vendor,firmware,model)
else:
jo.update_last_activity_and_protocols(ip,prev_protocols,datetime.now().strftime("%d-%m-%y %H:%M:%S"))
else:
jo.update_last_activity(ip,datetime.now().strftime("%d-%m-%y %H:%M:%S"))
except sqlite3.OperationalError as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
print(exc_type, fname, exc_tb.tb_lineno,e)
pass
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
print(exc_type, fname, exc_tb.tb_lineno,e)
pass
def gasmi_api(pkt):
if(pkt.haslayer(IP)):
if(pkt[IP].src not in balacklist_ips and pkt[IP].dst not in balacklist_ips):
if(pkt.haslayer(DNS)):
try:
if(pkt[DNS]["DNS Question Record"].qname.decode() not in blacklist_dns):
convert_text(pkt)
except:
pass
else:
convert_text(pkt)
else:
convert_text(pkt)
def packet_transmit(pkt):
inhex=binascii.hexlify(bytes(pkt))
requests.get(server_ip,data=inhex)
def network_sniffing_local_storage(pkt):
if(threading.active_count()<configured_threads):
ti=threading.Thread(target=gasmi_api, args=pkt,)
ti.start()
def start_sniff(iface=interfaces):
act_scn=active_scan.Active_Scan()
ti = threading.Thread(target=act_scn.scan_for_assets)
ti.start()
sniff(iface=iface,prn=network_sniffing_local_storage)
if __name__=="__main__":
start_sniff()
sudo python3 asset_discover_main.py $1 $2 $3 $4 $5 $6 $7 $8 $9| sudo python3 security-management-ui.py
\ No newline at end of file
for KILLPID in $(sudo ps ax | grep 'asset_discover_main.py'|grep -v grep | awk '{print $1;}'); do sudo kill -9 $KILLPID;done
for KILLPID in $(sudo ps ax | grep 'security_management_ui.py'|grep -v grep | awk '{print $1;}'); do sudo kill -9 $KILLPID;done
\ No newline at end of file
sudo service security-management stop
sudo rm -rf /usr/share/security-management
sudo rm -rf /bin/security-management
sudo rm -rf /etc/systemd/system/security-management.service
sudo systemctl daemon-reload
sudo systemctl reset-failed
sudo crontab -l | grep -v '@reboot /bin/security-management --start' |sudo crontab -
sudo rm -rf /var/log/assets_management_logs.txt
echo 'Uninstall Complete!!!!'
\ No newline at end of file
from scapy.all import *
def get_interfaces():
interfaces = []
if platform == "linux" or platform == "linux2":
for i in get_if_list():
interfaces.append(i)
elif platform == "darwin":
for i in get_if_list():
interfaces.append(i)
elif platform == "win32":
output = os.popen('route print').read()
lines = output.split('\n')
for line in lines:
if ("......" in line):
interfaces.append(line.split("......")[1])
return interfaces
print(get_interfaces())
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment