#!/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文件的更多相关文章

  1. python 如何在某.py文件中调用其他.py内的函数

    A.py的文件需要调用B.py文件内的test函数 同一目录下: A.py #!/usr/bin/env python # -*- coding: utf- -*- def test(): ''' 测 ...

  2. 【python】如何在某.py文件中调用其他.py内的函数

    假设名为A.py的文件需要调用B.py文件内的C(x,y)函数 假如在同一目录下,则只需 import B if __name__ == "__main__": B.C(x,y) ...

  3. python 在.py文件中调用其他.py内的函数

      假设名为A.py的文件需要调用B.py文件内的C(x,y)函数 假如在同一目录下,则只需 import B if __name__ == "__main__": B.C(x,y ...

  4. Python引用多个模块,调用模块中的函数时,要注意的地方

    转自:http://blog.csdn.net/yjk13703623757/article/details/70237463 python模块是”从下到上”导入(import)的. 例如: a.py ...

  5. Python基础------列表,元组的调用方法

    Python基础------列表,元组的调用方法@@@ 一. 列表 Python中的列表和歌曲列表类似,也是由一系列的按特定顺序排列的元素组成的,在内容上,可以将整数,实数,字符串,列表,元组等任何类 ...

  6. python与java的内存机制不一样;java的方法会进入方法区直到对象消失 方法才会消失;python的方法是对象每次调用都会创建新的对象 内存地址都不i一样

    python与java的内存机制不一样;java的方法会进入方法区直到对象消失 方法才会消失;python的方法是对象每次调用都会创建新的对象 内存地址都不i一样

  7. python 多个装饰器的调用顺序

    python 多个装饰器的调用顺序 一般情况下,在函数中可以使用一个装饰器,但是有时也会有两个或两个以上的装饰器.多个装饰器装饰的顺序是从里到外(就近原则),而调用的顺序是从外到里(就远原则). 原代 ...

  8. 【翻译】无需安装Python,就可以在.NET里调用Python库

    原文地址:https://henon.wordpress.com/2019/06/05/using-python-libraries-in-net-without-a-python-installat ...

  9. Python基础:绑定和方法调用

    首先,方法仅仅是类内部定义的函数,也就是说,方法是类属性而不是实例属性. 其次方法有两种被调用的方式:调用绑定的方法和调用未绑定的方法. 当存在一个实例时,方法才被认为绑定到了那个实例上,没有实例时方 ...

  10. Python基础_函数闭包、调用、递归

    这节的主要内容是函数的几个用法闭包,调用.递归. 一.函数闭包 对闭包更好的理解请看:https://www.cnblogs.com/Lin-Yi/p/7305364.html 我们来看一个简单的例子 ...

随机推荐

  1. [转帖]ipv6相关内核参数配置的优化实践

    https://zhuanlan.zhihu.com/p/605217713 调整ARP缓存大小 这个参数通常需要在高负载的访问服务器上增加.比如繁忙的网络(或网关/防火墙 Linux 服务器),再比 ...

  2. [转帖]linux设置page cache大小,Linux Page Cache调优在Kafka中的应用

    本文首发于 vivo互联网技术 微信公众号 链接: 作者:Yang Yijun 本文主要描述Linux Page Cache优化的背景.Page Cache的基本概念.列举之前针对Kafka的 IO ...

  3. [转帖]SPEC2006移入docker后的运行问题

    https://www.cnblogs.com/csxyc/p/7157890.html 实验需要给SPEC2006的benchmark绑定CPUID,于是想到用docker分配CPU资源,写一个简单 ...

  4. [转帖]Traefik中诡异的502和504问题

    https://zhuanlan.zhihu.com/p/156138704 我们都知道在 Kubernetes 集群中通常会使用 Ingress 方案来统一代理集群内部的流量,而常用的 Ingres ...

  5. 内网CentOS7搭建ntp服务器实现内网时间同步

    内网CentOS7搭建ntp服务器实现内网时间同步 背景 公司内部有很多虚拟机,本来很简单的实现了每天晚上自动同步阿里云时间 crontab -e 1 1 * * * ntpdate ntp.aliy ...

  6. python批量上传文件到七牛云

    导航 引子 棘手的需求 化繁为简 实战案例 结语 参考 本文首发于智客工坊-<python批量上传文件到七牛云>,感谢您的阅读,预计阅读时长3min. 古之立大事者,不惟有超世之才,亦必有 ...

  7. 我在京东做研发 | 揭秘支撑京东万人规模技术人员协作的行云DevOps平台

    随着业务变化的速度越来越快各类IT系统的建设也越来越复杂大规模研发团队的管理问题日益突出如何提升研发效能成为时下各类技术团队面临的重要挑战 京东云DevOps专家将带您深入研发一线揭秘支撑京东集团万人 ...

  8. 【JS 逆向百例】网洛者反爬练习平台第一题:JS 混淆加密,反 Hook 操作

    关注微信公众号:K哥爬虫,持续分享爬虫进阶.JS/安卓逆向等技术干货! 声明 本文章中所有内容仅供学习交流,抓包内容.敏感网址.数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后 ...

  9. 强化学习从基础到进阶-常见问题和面试必知必答[4]::深度Q网络-DQN、double DQN、经验回放、rainbow、分布式DQN

    强化学习从基础到进阶-常见问题和面试必知必答[4]::深度Q网络-DQN.double DQN.经验回放.rainbow.分布式DQN 1.核心词汇 深度Q网络(deep Q-network,DQN) ...

  10. 3.1 C/C++ 使用字符与指针

    C/C++语言是一种通用的编程语言,具有高效.灵活和可移植等特点.C语言主要用于系统编程,如操作系统.编译器.数据库等:C语言是C语言的扩展,增加了面向对象编程的特性,适用于大型软件系统.图形用户界面 ...