python调用namp.py进行扫描,调用go编译的so文件
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json
import os
import platform
from ctypes import cdll, c_char_p
from urllib import parse
import netaddr
from typing import List, Dict, Any
import nmap
from log import logger
from concurrent.futures import ThreadPoolExecutor, as_completed
"""
# https://www.keepnight.com/archives/1423/
-PS: 这个选项用于指定TCP SYN扫描的目标端口。当使用-PS选项时,Nmap将发送TCP SYN包到指定的端口,通过观察目标主机返回的不同响应来确定端口的状态。
如果目标主机响应一个RST包,表示端口是关闭的;如果目标主机响应一个SYN/ACK包,表示端口是开放的;
如果没有响应或收到其他类型的响应,则可能表示端口被过滤或阻止。
-Pn: 这个选项用于禁用主机存活检测。当使用-Pn选项时,Nmap将不执行任何主机存活检测,而是直接进行端口扫描。这意味着无论目标主机是否存活,Nmap都会尝试进行端口扫描。
-PE: 这个选项用于启用ICMP echo请求(ping)进行主机存活检测。当使用-PE选项时,Nmap将发送ICMP echo请求到目标主机,通过观察是否收到ICMP echo回复来确定主机的存活状态。
如果目标主机响应了ICMP echo请求,表示主机存活;如果没有响应,则表示主机可能不存活。
"""
# 资产扫描
class AssetScan(object):
def __init__(self, proxy: str) -> None:
if not parse.urlparse(proxy).scheme:
self.proxy = '' # 错误的代理格式
else:
self.proxy = proxy
self.sudo = False # docker中无sudo命令
# if platform.system() == 'Windows':
# self.sudo = False
self.methods = {
# nmap探活调用参数
'AUTO': '-PE -PS{} -n -sn --disable-arp-ping --max-retries=2 --min-rate=1000 -T4'.format(
','.join(TOP_1000_PORTS)),
'PING': '-PE -n -sn --disable-arp-ping --max-retries=2',
'TOP': '-PS{} -n -sn --disable-arp-ping --max-retries=0 --min-rate=1000 -T4'.format(
','.join(TOP_1000_PORTS)),
# nmap端口扫描调用参数
'TCP-SYN': '-Pn -sS -n -sU --max-retries=3 --version-light --open --min-rate={} --max-rate={} -T4 --host-timeout {}s',
'TCP-CONNECT': '-Pn -sT -sU -n --version-light --open --min-rate={} --max-rate={} -T4 --host-timeout {}s',
'TCP-SYN-WITH-UDP': '-Pn -sS -sU -n --version-light --open --min-rate=1000 -T4 --host-timeout 30m',
'TCP-CONNECT-WITH-UDP': '-Pn -sT -sU -n --version-light --open --min-rate=1000 -T4 --host-timeout 30m',
}
def _get_proxychains(self) -> str:
"""
:return:
"""
proxychains_config = ''
if self.proxy and platform.system() != 'Windows':
logger.info(self.proxy)
url_parts = parse.urlparse(self.proxy)
proxychains_config = os.path.join('/tmp', '{}@{}@{}.conf'.format(
url_parts.scheme,url_parts.hostname, url_parts.port))
# 写入代理配置
tmp_config = '''strict_chain
remote_dns_subnet 224
tcp_read_time_out 1200
tcp_connect_time_out 800
[ProxyList]
'''
tmp_config = tmp_config + '{} {} {} {} {}'.format(url_parts.scheme, url_parts.hostname,
url_parts.port,
url_parts.username if url_parts.username else '',
url_parts.password if url_parts.password else '')
try:
with open(proxychains_config, 'w', encoding='utf-8') as f:
f.write(tmp_config)
except Exception as err:
logger.error('获取代理配置文件失败: {}'.format(err))
return ''
return proxychains_config
def __host_discover_with_nmap(self, method: str, targets: str, host_scanner_type: int = 1,
host_scanner_ports: list = TOP_30_TCP_PORTS) -> List[str]:
"""
nmap主机存活扫描
:param method: 探活方式 AUTO: 智能模式 PING: icmp探活 TOP: 扫描一些常用端口判定目标为存活 PN: 假定目标全部存活
:param targets:
:return:
"""
online_ip = []
try:
address = targets.split(' ')
if method == 'PN':
# PN模式,假定目标全部存活
ret = []
for addr in address:
if '-' in addr:
a = addr.split('.')
range_ = a[3].split('-')
tmp_addr = "{}.{}.{}.".format(a[0], a[1], a[2])
for i in range(int(range_[0]), int(range_[1]) + 1):
ret.append("{}{}".format(tmp_addr, str(i)))
else:
ips = netaddr.IPNetwork(addr)
for ip in ips:
ret.append(str(ip))
return ret
else:
nm = nmap.PortScanner()
arguments = self.__auto_scanner_command()
arguments = self.__top_scanner_command(host_scanner_ports)
result = nm.scan(hosts=targets, arguments=arguments, sudo=self.sudo)
if host_scanner_type in [0, 4, 3]:
for ip, val in result['scan'].items():
# if val.get('status', {}).get('state') == 'up':
# online_ip.append(ip)
# continue
if any([p for p, v in val.get('tcp', {}).items() if v.get('state') == 'open']):
online_ip.append(ip)
else:
online_ip.extend([key for key, val in result['scan'].items() if
val.get('status', {}).get('state') == 'up'] if result else [])
except Exception as err:
logger.error('主机探活执行失败: {}'.format(err))
return online_ip
def host_discover_scan(self, host_scan_module: str, targets: List[str], host_scanner_type: int=1,
host_scanner_ports: list=TOP_30_TCP_PORTS) -> List[str]:
"""
主机存活扫描
:param targets: 待扫描目标
:param host_scan_module:
:return:
"""
# 使用nmap扫描
active_hosts = self.__host_discover_with_nmap(host_scan_module, ' '.join(targets),
host_scanner_type=host_scanner_type,
host_scanner_ports=host_scanner_ports)
return active_hosts
def scan_os(self, targets: List[str]) -> Dict[str, Any]:
"""
nmap os识别
:param targets:
:return:
"""
ret = {}
try:
nm = nmap.PortScanner()
result = nm.scan(hosts=' '.join(targets), arguments='-O -F -Pn -n', sudo=self.sudo)
except Exception as err:
logger.error('操作系统识别失败: {}'.format(err))
return ret
if result is not None:
for key, val in result['scan'].items():
if 'osmatch' not in val:
continue
try:
os_family = val['osmatch'][0]['osclass'][0]['osfamily']
except Exception as err:
os_family = 'Unknown'
logger.error('未识别到操作系统: {}:{}'.format(key, err))
if os_family in ['Linux', 'Windows', 'Mac OS X', 'Unknown']:
ret[key] = os_family
return ret
def scan_port(self, targets: List[str], ports: str, method: str, exclude_ports: str, scan_rate: int,
host_timeout: int) -> List[dict]:
"""
端口扫描
:param targets: 待扫描的目标
:param ports: 待扫描的端口 80,443,83-87
:param method: 扫描模式 当扫描模式使用syn时,端口扫描无法走代理
:param exclude_ports 排除的端口
:param scan_rate 最小发包速率 慢200 标准500 快速1000 自定义
:param host_timeout 单个主机超时时间 单位s
:return:
"""
ret = []
result = None
try:
arguments = self.methods[method]
# 最小发包率为最大发包率的一半
min_rate = scan_rate / 2
arguments = arguments.format(int(min_rate), scan_rate, host_timeout)
if exclude_ports:
arguments += ' --exclude-ports {}'.format(exclude_ports)
scan_ports = ''
if 'T:' in ports or 'U:' in ports:
scan_ports = ports
# 处理自定义 tcp udp 端口
try:
new_port = json.loads(ports)
if isinstance(new_port, dict):
tcp_ports = new_port.get('TCP')
udp_ports = new_port.get('UDP')
if tcp_ports:
scan_ports += 'T:' + tcp_ports.strip()
if udp_ports:
scan_ports += ',U:' + udp_ports.strip()
scan_ports = scan_ports.strip(',')
except Exception as err:
logger.warning(err)
if 'T:' not in scan_ports and 'U:' not in scan_ports:
# 不是json数据直接视为tcp端口
scan_ports = 'T:' + ports
nm = nmap.PortScanner()
logger.info("端口扫描参数ports: {}, arguments: {}".format(scan_ports, arguments))
result = nm.scan(hosts=' '.join(targets), ports=scan_ports, arguments=arguments, sudo=self.sudo,
proxychains=self._get_proxychains())
except Exception as err:
logger.error('端口扫描失败: {}'.format(err))
logger.exception(err)
if result is not None:
for key, val in result['scan'].items():
if 'tcp' not in val and 'udp' not in val:
continue
for protocol in ['tcp', 'udp']:
ports = val.get(protocol, {})
for port, data in ports.items():
if data.get('state', '') != 'open':
continue
ret.append({
'ip': key,
'port': str(port),
'protocol': protocol
})
return ret
@staticmethod
def __load_service_scan_library():
"""
加载服务识别golang库
:return:
"""
try:
sys_str = platform.system()
if sys_str == 'Darwin':
lib = cdll.LoadLibrary(os.path.join(SCANNER_DIR, 'lib', 'service_scan_darwin.so'))
elif sys_str == 'Windows':
lib = cdll.LoadLibrary(os.path.join(SCANNER_DIR, 'lib', 'service_scan.dll'))
else:
lib = cdll.LoadLibrary(os.path.join(SCANNER_DIR, 'lib', 'service_scan.so'))
lib.scan.restype = c_char_p
except Exception as e:
logger.error('加载scan库失败: {}'.format(e))
return None
return lib
def scan_service_with_golang(self, targets: str) -> List[dict]:
"""
使用golang c库进行服务识别
:param targets: 待扫描的目标json字符串 如 :[{"ip": "129.226.181.188", "port": "22", "protocol": "tcp"}, {"ip": "129.226.181.188", "port": "80", "protocol": "tcp"}, {"ip": "129.226.181.188", "port": "443", "protocol": "tcp"}]
:return: 返回数据示例:[{'ip': '129.226.181.188', 'port': '22', 'protocol': 'tcp', 'name': 'ssh', 'product': 'OpenSSH', 'version': '7.6p1 Ubuntu 4ubuntu0.3', 'state': 'open'}, {'ip': '129.226.181.188', 'port': '80', 'protocol': 'tcp', 'name': 'http', 'product': 'nginx', 'version': '', 'state': 'open'}, {'ip': '129.226.181.188', 'port': '443', 'protocol': 'tcp', 'name': 'ssl/http', 'product': 'nginx', 'version': '', 'state': 'open'}]
"""
ret = []
dll = self.__load_service_scan_library()
print(dll)
if dll is None:
return []
try:
"""
参数1: 待扫描的目标
参数2: 服务识别dll需要用到的指纹数据库路径
参数3: 代理地址
"""
result = dll.scan(c_char_p(targets.encode()),
c_char_p(os.path.join(SCANNER_DIR, 'db', 'db.sqlite3').encode()),
c_char_p(self.proxy.encode()))
res = json.loads(result.decode('utf-8'))
if res:
ret = res
except Exception as err:
logger.error('执行失败: {}'.format(err))
return ret
def port_scan(**kwargs):
"""
端口扫描job
kwargs :
proxy: 代理地址
targets: 存活的主机 [{'ip':'8.8.8.8', 'asset': 1, "asset_parent": None}, {'ip':'129.226.181.188', 'asset': 2}]
scan_ports: 待扫描的端口 80,443,22-25
port_scan_module: 扫描模式 TCP-SYN、TCP-CONNECT、...
exclude_ports: 排除的端口
"""
ret = []
asset_id_map = {} # 保存asset_id和ip的对应关系
asset_parent_map = {}
targets = kwargs.get('targets', [])
exclude_ports = kwargs.get('exclude_ports', '')
scan_ports = kwargs.get('scan_ports', '')
port_scan_rate = kwargs.get('port_scan_rate', NMAP_PORT_DEFAULT_SCAN_RATE)
proxy = kwargs.get('proxy', '')
host_timeout = kwargs.get('host_timeout', PORT_SCAN_HOST_TIMEOUT)
scan_targets = []
for target in targets:
asset_id_map[target.get('ip', '')] = target.get('asset')
asset_parent_map[target.get('ip', '')] = target.get('asset_parent')
scan_targets.append(target.get('ip', ''))
open_port_list = []
s = AssetScan(proxy=proxy)
if (scan_ports == "T:1-65535" or scan_ports == "1-65535") and proxy != "":
# 多进程并发提升proxychains性能
executor = ThreadPoolExecutor(max_workers=10)
futures = []
for i in range(1, 65535, 1000):
start = i
end = i + 999
if end > 65535:
end = 65535
job = executor.submit(s.scan_port, targets=scan_targets, ports='T:{}-{}'.format(start, end),
method=kwargs.get('port_scan_module', ''), exclude_ports=exclude_ports,
scan_rate=port_scan_rate, host_timeout=host_timeout)
futures.append(job)
for future in as_completed(futures):
res = future.result()
if res:
open_port_list.extend(res)
else:
open_port_list = s.scan_port(targets=scan_targets, ports=kwargs.get('scan_ports', ''),
method=kwargs.get('port_scan_module', ''), exclude_ports=exclude_ports,
scan_rate=port_scan_rate, host_timeout=host_timeout)
# 扫出端口的资产
open_port_asset = []
for port in open_port_list:
tmp = {
'ip': port.get('ip'),
'port': port.get('port'),
'protocol': port.get('protocol'),
'asset': asset_id_map[port.get('ip')],
"asset_parent": asset_parent_map[port.get('ip')],
}
ret.append(tmp)
open_port_asset.append(asset_id_map[port.get('ip')])
return ret
def service_scan(**kwargs):
"""
服务识别job
kwargs :
proxy: 代理地址
targets: 端口扫描结果传递 格式: [
{'ip': '8.8.8.8', 'port': '443', 'protocol': 'tcp', 'asset': 1},
{'ip': '129.226.181.188', 'port': '22', 'protocol':'tcp', 'asset':2},
{'ip': '129.226.181.188', 'port': '80', 'protocol': 'tcp', 'asset':2}
]
"""
ret = []
asset_id_map = {} # 保存asset_id和ip的对应关系
asset_parent_map = {}
targets = kwargs.get('targets', [])
for target in targets:
asset_id_map[target.get('ip', '')] = target.get('asset')
asset_parent_map[target.get('ip', '')] = target.get('asset_parent')
s = AssetScan(proxy=kwargs.get('proxy', ''))
for t in targets:
del t['asset']
service_result_list = s.scan_service_with_golang(targets=json.dumps(targets))
for row in service_result_list:
tmp = {
'asset': asset_id_map[row.get('ip')],
'asset_parent': asset_parent_map[row.get('ip')],
'ip': row.get('ip', ''),
"protocol": row.get('protocol'),
"port": row.get('port'),
"name": row.get('name'),
"product": row.get('product') or 'unknown',
"version": row.get('version') or 'unknown',
"state": row.get('state')
}
ret.append(tmp)
return ret
def os_scan(**kwargs):
"""
os识别job
kwargs :
targets: 存活的主机 [{'ip':'8.8.8.8', 'asset': 1}, {'ip':'129.226.181.188', 'asset': 2}]
"""
targets = kwargs.get('targets', [])
scan_targets = [t.get('ip', '') for t in targets]
s = AssetScan(proxy=kwargs.get('proxy', ''))
os_map = s.scan_os(scan_targets)
for target in targets:
target["os"] = os_map.get(target.get('ip', ''), 'Unknown')
return targets
if __name__ == '__main__':
pass
python调用namp.py进行扫描,调用go编译的so文件的更多相关文章
- python 如何在某.py文件中调用其他.py内的函数
A.py的文件需要调用B.py文件内的test函数 同一目录下: A.py #!/usr/bin/env python # -*- coding: utf- -*- def test(): ''' 测 ...
- 【python】如何在某.py文件中调用其他.py内的函数
假设名为A.py的文件需要调用B.py文件内的C(x,y)函数 假如在同一目录下,则只需 import B if __name__ == "__main__": B.C(x,y) ...
- python 在.py文件中调用其他.py内的函数
假设名为A.py的文件需要调用B.py文件内的C(x,y)函数 假如在同一目录下,则只需 import B if __name__ == "__main__": B.C(x,y ...
- Python引用多个模块,调用模块中的函数时,要注意的地方
转自:http://blog.csdn.net/yjk13703623757/article/details/70237463 python模块是”从下到上”导入(import)的. 例如: a.py ...
- Python基础------列表,元组的调用方法
Python基础------列表,元组的调用方法@@@ 一. 列表 Python中的列表和歌曲列表类似,也是由一系列的按特定顺序排列的元素组成的,在内容上,可以将整数,实数,字符串,列表,元组等任何类 ...
- python与java的内存机制不一样;java的方法会进入方法区直到对象消失 方法才会消失;python的方法是对象每次调用都会创建新的对象 内存地址都不i一样
python与java的内存机制不一样;java的方法会进入方法区直到对象消失 方法才会消失;python的方法是对象每次调用都会创建新的对象 内存地址都不i一样
- python 多个装饰器的调用顺序
python 多个装饰器的调用顺序 一般情况下,在函数中可以使用一个装饰器,但是有时也会有两个或两个以上的装饰器.多个装饰器装饰的顺序是从里到外(就近原则),而调用的顺序是从外到里(就远原则). 原代 ...
- 【翻译】无需安装Python,就可以在.NET里调用Python库
原文地址:https://henon.wordpress.com/2019/06/05/using-python-libraries-in-net-without-a-python-installat ...
- Python基础:绑定和方法调用
首先,方法仅仅是类内部定义的函数,也就是说,方法是类属性而不是实例属性. 其次方法有两种被调用的方式:调用绑定的方法和调用未绑定的方法. 当存在一个实例时,方法才被认为绑定到了那个实例上,没有实例时方 ...
- Python基础_函数闭包、调用、递归
这节的主要内容是函数的几个用法闭包,调用.递归. 一.函数闭包 对闭包更好的理解请看:https://www.cnblogs.com/Lin-Yi/p/7305364.html 我们来看一个简单的例子 ...
随机推荐
- [转帖]Oracle中有大量的sniped会话
https://www.cnblogs.com/abclife/p/15699959.html 1 2 3 4 5 6 7 SQL> select status ,count(*) from g ...
- [转帖]ext4的fsync性能和nodelalloc参数的分析
原文:http://blog.thinksrc.com/?p=189001 感叹归感叹,发泄完了还得继续过. 前几天忙的不可开交,周报上面竟然能列出11项,想想以前在T公司时候的清闲,现在的老板的真幸 ...
- 【转帖】一篇文章让你了解灾备指标:RPO与RTO
RTO 和 RPO 都是企业灾难恢复(Disaster Recovery, DR)需要考虑的关键指标,这两个指标可以用来指导企业来制定合适的业务系统服务或数据的恢复方案. RPO(Recovery P ...
- [转帖]远超DDR4,速度可达DDR5 6400!DDR5内存技术、产品解析
https://www.sohu.com/a/326810241_616364 内存是计算机技术的重要组成部分,经历了长时间的竞争更替和路线选择之后,PC内存技术被稳定在以DDR技术为基础的发展路线上 ...
- python安装与python、pip的环境变量配置
进入官网 在你常用的搜索引擎中输入 python官网 然后进入. 可直接点击本链接 python官网进入: 也可在浏览器地址栏输入www.python.org回车进入官网. 下载 将鼠标放到菜单栏中的 ...
- TienChin-课程管理-展示课程列表
配置按钮权限 博主这里就不贴SQL了,自行手动添加一下吧. 更改表结构 ALTER TABLE `tienchin_course` MODIFY COLUMN `info` varchar(255) ...
- 利用Mybatis拦截器实现自定义的ID自增器
原生的Mybatis框架是没有ID自增器,但例如国产的Mybatis Plus却是支持,不过,Mybatis Plus却是缺少了自定属性的填充:例如:我们需要自定义填充一些属性,updateDate. ...
- SqlSugar联表查询
Join用法 语法糖1.2和3 在Where OrderBy GroupBy Select用法都一样的,他们区别就在JOIN的方式不一样,其它都一样 语法糖1 优点:好理解,5个表以内的联表非常爽,支 ...
- Metasploit 生成带SSL加密载荷
1.下载证书.Impersonate_SSL模块,下载指定网站的证书. msf6> use auxiliary/gather/impersonate_ssl msf6 auxiliary(gat ...
- 辣鸡 mac 下 pycharm 中代码拖拽的问题
Editor –> General Enable Drag'n'Drop functionality in Editor